.NET
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Breaking a line/polyline

36 REPLIES 36
SOLVED
Reply
Message 1 of 37
Anonymous
6766 Views, 36 Replies

Breaking a line/polyline

Anonymous
Not applicable
Hi all,

I'm trying to break a line/polyline from code (vb.net). Letting the user
select the object (line/polyline) from code is not a problem I have the
entity and I can see it's a line/polyline via entity.GetType.FullName.
Now I need to break that line at the point the user selected the line.
Basically the same way the "break" command works from the commandline.

Has anyone got a clue on how to do this?

Rinze
0 Likes

Breaking a line/polyline

Hi all,

I'm trying to break a line/polyline from code (vb.net). Letting the user
select the object (line/polyline) from code is not a problem I have the
entity and I can see it's a line/polyline via entity.GetType.FullName.
Now I need to break that line at the point the user selected the line.
Basically the same way the "break" command works from the commandline.

Has anyone got a clue on how to do this?

Rinze
36 REPLIES 36
Message 2 of 37
Anonymous
in reply to: Anonymous

Anonymous
Not applicable
GetSplitCurves should work for you.

--
James Allen
Malicoat-Winslow Engineers, P.C.
Columbia, MO



Rinze wrote:
> Hi all,
>
> I'm trying to break a line/polyline from code (vb.net). Letting the user
> select the object (line/polyline) from code is not a problem I have the
> entity and I can see it's a line/polyline via entity.GetType.FullName.
> Now I need to break that line at the point the user selected the line.
> Basically the same way the "break" command works from the commandline.
>
> Has anyone got a clue on how to do this?
>
> Rinze
>
0 Likes

GetSplitCurves should work for you.

--
James Allen
Malicoat-Winslow Engineers, P.C.
Columbia, MO



Rinze wrote:
> Hi all,
>
> I'm trying to break a line/polyline from code (vb.net). Letting the user
> select the object (line/polyline) from code is not a problem I have the
> entity and I can see it's a line/polyline via entity.GetType.FullName.
> Now I need to break that line at the point the user selected the line.
> Basically the same way the "break" command works from the commandline.
>
> Has anyone got a clue on how to do this?
>
> Rinze
>
Message 3 of 37
Anonymous
in reply to: Anonymous

Anonymous
Not applicable
James Allen wrote:
> GetSplitCurves should work for you.
>

Thanks, got it working now

Rinze
0 Likes

James Allen wrote:
> GetSplitCurves should work for you.
>

Thanks, got it working now

Rinze
Message 4 of 37
Anonymous
in reply to: Anonymous

Anonymous
Not applicable


[CommandMethod("myb")]

public static void MyBreakLine()

{



Document doc = Application.DocumentManager.MdiActiveDocument;

Database db = doc.Database;

Editor ed = doc.Editor;



PromptEntityOptions opt1 = new PromptEntityOptions("\nselect a line:");

opt1.SetRejectMessage("\nerror!");

opt1.AddAllowedClass(typeof(Line), true);

PromptEntityResult res1 = ed.GetEntity(opt1);



if (res1.Status == PromptStatus.OK)

{

PromptPointOptions opt2 = new PromptPointOptions("\nselect second point:");

opt2.AllowNone = true;

PromptPointResult res2 = ed.GetPoint(opt2);



using (Transaction tr = db.TransactionManager.StartTransaction())

{



Line l = (Line)tr.GetObject(res1.ObjectId, OpenMode.ForRead);

List<double> pars = new List<double>();



Point3d pt1 = l.GetClosestPointTo(res1.PickedPoint, false);

Point3d pt2 = new Point3d();

pars.Add(l.GetParameterAtPoint(pt1));



BlockTableRecord btr =

(BlockTableRecord)tr.GetObject(

db.CurrentSpaceId,

OpenMode.ForWrite,

false);



if (res2.Status == PromptStatus.OK)

{

pt2 = l.GetClosestPointTo(res2.Value, false);

pars.Add(l.GetParameterAtPoint(pt2));

pars.Sort();

DBObjectCollection objs = l.GetSplitCurves(new DoubleCollection(pars.ToArray()));

foreach (Line ll in objs)

{

if ((ll.StartPoint != pt1 && ll.StartPoint != pt2) ^ (ll.EndPoint != pt1 && ll.EndPoint != pt2))

{

btr.AppendEntity(ll);

tr.AddNewlyCreatedDBObject(ll, true);

}

}

}

else

{

DBObjectCollection objs = l.GetSplitCurves(new DoubleCollection(pars.ToArray()));

foreach (Line ll in objs)

{

btr.AppendEntity(ll);

tr.AddNewlyCreatedDBObject(ll, true);

}

}



l.UpgradeOpen();

l.Erase();

tr.Commit();



}

}

}

0 Likes


[CommandMethod("myb")]

public static void MyBreakLine()

{



Document doc = Application.DocumentManager.MdiActiveDocument;

Database db = doc.Database;

Editor ed = doc.Editor;



PromptEntityOptions opt1 = new PromptEntityOptions("\nselect a line:");

opt1.SetRejectMessage("\nerror!");

opt1.AddAllowedClass(typeof(Line), true);

PromptEntityResult res1 = ed.GetEntity(opt1);



if (res1.Status == PromptStatus.OK)

{

PromptPointOptions opt2 = new PromptPointOptions("\nselect second point:");

opt2.AllowNone = true;

PromptPointResult res2 = ed.GetPoint(opt2);



using (Transaction tr = db.TransactionManager.StartTransaction())

{



Line l = (Line)tr.GetObject(res1.ObjectId, OpenMode.ForRead);

List<double> pars = new List<double>();



Point3d pt1 = l.GetClosestPointTo(res1.PickedPoint, false);

Point3d pt2 = new Point3d();

pars.Add(l.GetParameterAtPoint(pt1));



BlockTableRecord btr =

(BlockTableRecord)tr.GetObject(

db.CurrentSpaceId,

OpenMode.ForWrite,

false);



if (res2.Status == PromptStatus.OK)

{

pt2 = l.GetClosestPointTo(res2.Value, false);

pars.Add(l.GetParameterAtPoint(pt2));

pars.Sort();

DBObjectCollection objs = l.GetSplitCurves(new DoubleCollection(pars.ToArray()));

foreach (Line ll in objs)

{

if ((ll.StartPoint != pt1 && ll.StartPoint != pt2) ^ (ll.EndPoint != pt1 && ll.EndPoint != pt2))

{

btr.AppendEntity(ll);

tr.AddNewlyCreatedDBObject(ll, true);

}

}

}

else

{

DBObjectCollection objs = l.GetSplitCurves(new DoubleCollection(pars.ToArray()));

foreach (Line ll in objs)

{

btr.AppendEntity(ll);

tr.AddNewlyCreatedDBObject(ll, true);

}

}



l.UpgradeOpen();

l.Erase();

tr.Commit();



}

}

}

Message 5 of 37
Anonymous
in reply to: Anonymous

Anonymous
Not applicable
You're welcome.

James


Rinze wrote:
> Thanks, got it working now
> Rinze
>
0 Likes

You're welcome.

James


Rinze wrote:
> Thanks, got it working now
> Rinze
>
Message 6 of 37
Hallex
in reply to: Anonymous

Hallex
Advisor
Advisor
Thanks for the sharing nice code example

Regards,

~'J'~
_____________________________________
C6309D9E0751D165D0934D0621DFF27919
0 Likes

Thanks for the sharing nice code example

Regards,

~'J'~
_____________________________________
C6309D9E0751D165D0934D0621DFF27919
Message 7 of 37
Anonymous
in reply to: Anonymous

Anonymous
Not applicable
You're welcome. hallex

xsfh lzh Edited by: XSFHLZH on May 17, 2009 6:35 AM
0 Likes

You're welcome. hallex

xsfh lzh Edited by: XSFHLZH on May 17, 2009 6:35 AM
Message 8 of 37
Anonymous
in reply to: Anonymous

Anonymous
Not applicable
XSFHLZH wrote:
>
> [CommandMethod("myb")]

I had already resolved my problem, but thanks for posting your code anyway. Never hurts to have more examples on hand.

Rinze
0 Likes

XSFHLZH wrote:
>
> [CommandMethod("myb")]

I had already resolved my problem, but thanks for posting your code anyway. Never hurts to have more examples on hand.

Rinze
Message 9 of 37
Anonymous
in reply to: Anonymous

Anonymous
Not applicable

Hi, 
A code which you have Posted here as Breaking Line/Polyline. where as Its supporing only for Polylines not for Lines. So Please look into this, It should support for Lines and Polylines both.
The Reason may be below,

Line l= (Line)tr.GetObject(res1.ObjectId, OpenMode.ForRead);

 

Regards

 

Alex Andrews.

 

0 Likes

Hi, 
A code which you have Posted here as Breaking Line/Polyline. where as Its supporing only for Polylines not for Lines. So Please look into this, It should support for Lines and Polylines both.
The Reason may be below,

Line l= (Line)tr.GetObject(res1.ObjectId, OpenMode.ForRead);

 

Regards

 

Alex Andrews.

 

Message 10 of 37
_gile
in reply to: Anonymous

_gile
Mentor
Mentor

Hi,

 

This one mimics the native BREAK command.

 

        [CommandMethod("BRLPL")]
        public void BreakLineOrPolyline()
        {
            var doc = AcAp.DocumentManager.MdiActiveDocument;
            var db = doc.Database;
            var ed = doc.Editor;

            var entityOptions = new PromptEntityOptions("\nSelect line or polyline: ");
            entityOptions.SetRejectMessage("Selected object is neither a line nor a polyline.");
            entityOptions.AddAllowedClass(typeof(Polyline), true);
            entityOptions.AddAllowedClass(typeof(Line), true);
            var entityResult = ed.GetEntity(entityOptions);
            if (entityResult.Status != PromptStatus.OK)
                return;

            Point3d pt1, pt2;
            var ucs = ed.CurrentUserCoordinateSystem;
            var pointOptions = new PromptPointOptions("\nSpecify second point or [First point]: ", "First");
            var pointResult = ed.GetPoint(pointOptions);
            if (pointResult.Status == PromptStatus.Keyword)
            {
                pointOptions.Message = "\nSpecify first point: ";
                pointOptions.Keywords.Clear();
                pointResult = ed.GetPoint(pointOptions);
                if (pointResult.Status != PromptStatus.OK)
                    return;
                pt1 = pointResult.Value.TransformBy(ucs);
                pointOptions.Message = "\nSpecify second point: ";
                pointResult = ed.GetPoint(pointOptions);
                if (pointResult.Status != PromptStatus.OK)
                    return;
                pt2 = pointResult.Value.TransformBy(ucs);
            }
            else if (pointResult.Status == PromptStatus.OK)
            {
                pt1 = entityResult.PickedPoint.TransformBy(ucs);
                pt2 = pointResult.Value.TransformBy(ucs);
            }
            else return;

            using (var tr = db.TransactionManager.StartTransaction())
            {
                var curve = (Curve)tr.GetObject(entityResult.ObjectId, OpenMode.ForWrite);
                double param1 = curve.GetParameterAtPoint(curve.GetClosestPointTo(pt1, false));
                double param2 = curve.GetParameterAtPoint(curve.GetClosestPointTo(pt2, false));
                var parameters = new DoubleCollection
                    (new[] { param1, param2 }
                    .Distinct()
                    .OrderBy(x => x)
                    .ToArray());
                var curves = curve.GetSplitCurves(parameters);
                var curSpace = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                switch (curves.Count)
                {
                    case 3:
                        curSpace.AppendEntity((Entity)curves[0]);
                        tr.AddNewlyCreatedDBObject(curves[0], true);
                        curSpace.AppendEntity((Entity)curves[2]);
                        tr.AddNewlyCreatedDBObject(curves[2], true);
                        curves[1].Dispose();
                        curve.Erase();
                        break;
                    case 2:
                        curSpace.AppendEntity((Entity)curves[0]);
                        tr.AddNewlyCreatedDBObject(curves[0], true);
                        curSpace.AppendEntity((Entity)curves[1]);
                        tr.AddNewlyCreatedDBObject(curves[1], true);
                        curve.Erase();
                        break;
                    default:
                        break;
                }
                tr.Commit();
            }
        }


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Hi,

 

This one mimics the native BREAK command.

 

        [CommandMethod("BRLPL")]
        public void BreakLineOrPolyline()
        {
            var doc = AcAp.DocumentManager.MdiActiveDocument;
            var db = doc.Database;
            var ed = doc.Editor;

            var entityOptions = new PromptEntityOptions("\nSelect line or polyline: ");
            entityOptions.SetRejectMessage("Selected object is neither a line nor a polyline.");
            entityOptions.AddAllowedClass(typeof(Polyline), true);
            entityOptions.AddAllowedClass(typeof(Line), true);
            var entityResult = ed.GetEntity(entityOptions);
            if (entityResult.Status != PromptStatus.OK)
                return;

            Point3d pt1, pt2;
            var ucs = ed.CurrentUserCoordinateSystem;
            var pointOptions = new PromptPointOptions("\nSpecify second point or [First point]: ", "First");
            var pointResult = ed.GetPoint(pointOptions);
            if (pointResult.Status == PromptStatus.Keyword)
            {
                pointOptions.Message = "\nSpecify first point: ";
                pointOptions.Keywords.Clear();
                pointResult = ed.GetPoint(pointOptions);
                if (pointResult.Status != PromptStatus.OK)
                    return;
                pt1 = pointResult.Value.TransformBy(ucs);
                pointOptions.Message = "\nSpecify second point: ";
                pointResult = ed.GetPoint(pointOptions);
                if (pointResult.Status != PromptStatus.OK)
                    return;
                pt2 = pointResult.Value.TransformBy(ucs);
            }
            else if (pointResult.Status == PromptStatus.OK)
            {
                pt1 = entityResult.PickedPoint.TransformBy(ucs);
                pt2 = pointResult.Value.TransformBy(ucs);
            }
            else return;

            using (var tr = db.TransactionManager.StartTransaction())
            {
                var curve = (Curve)tr.GetObject(entityResult.ObjectId, OpenMode.ForWrite);
                double param1 = curve.GetParameterAtPoint(curve.GetClosestPointTo(pt1, false));
                double param2 = curve.GetParameterAtPoint(curve.GetClosestPointTo(pt2, false));
                var parameters = new DoubleCollection
                    (new[] { param1, param2 }
                    .Distinct()
                    .OrderBy(x => x)
                    .ToArray());
                var curves = curve.GetSplitCurves(parameters);
                var curSpace = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                switch (curves.Count)
                {
                    case 3:
                        curSpace.AppendEntity((Entity)curves[0]);
                        tr.AddNewlyCreatedDBObject(curves[0], true);
                        curSpace.AppendEntity((Entity)curves[2]);
                        tr.AddNewlyCreatedDBObject(curves[2], true);
                        curves[1].Dispose();
                        curve.Erase();
                        break;
                    case 2:
                        curSpace.AppendEntity((Entity)curves[0]);
                        tr.AddNewlyCreatedDBObject(curves[0], true);
                        curSpace.AppendEntity((Entity)curves[1]);
                        tr.AddNewlyCreatedDBObject(curves[1], true);
                        curve.Erase();
                        break;
                    default:
                        break;
                }
                tr.Commit();
            }
        }


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 11 of 37
Anonymous
in reply to: _gile

Anonymous
Not applicable

Thank You so much Gilles!!! Its working fine as per my request.

 

Alex Andrews.

0 Likes

Thank You so much Gilles!!! Its working fine as per my request.

 

Alex Andrews.

Message 12 of 37
ActivistInvestor
in reply to: _gile

ActivistInvestor
Advisor
Advisor

 

Hi @_gile

 

To fully-mimic the native BREAK command, the code must honor application data and inter-object references that can be established with most any type of AutoCAD entity (this holds especially true with the use of constraints), so rather than erasing the original object, and appending the replacement object(s), You can use HandOverTo() on the original object and the first replacement object, because that preserves both application data and inter-object references.

 

One other minor point about your code is that there's no need for calling Distinct() on points or parameters passed to GetSplitCurves(). It will ignore duplicates and also points or parameters that correspond to the start/end points/parameters. I only recently discovered that myself after reading the native ObjectARX docs and doing some testing.

 

And lastly, like most example code posted here (including my own), your code will work on entities that lie in the XY plane of the current UCS, in a PLAN view of same, but can easily fail if the entities involved do not lie in the current UCS XY plane, and/or the current view is not a plan view of same. The reason is because the point returned by GetEntity() is always in the XY plane of the current UCS, which may not be the closest point to the selected curve in the DCS.

 

Here's the extension method I use to properly find the point on a curve, closest to the point where the curve was picked:

 

public static class EditorExtensions
{
   /// <summary>
   /// Returns the point on the given curve that is closest to
   /// a line that's parallel to the current view direction, 
   /// and passes through the given point. The given point is
   /// a point expressed in the current UCS. The resulting
   /// point is expressed in the WCS.
   /// </summary>
   /// 
   /// <remarks>This API must be called immediately after the
   /// given point is acquired via an interactive function such
   /// as GetPoint(), GetEntity(), etc., in cases where there
   /// are multiple points being obtained, and the user is able
   /// to switch viewports and specify points in any viewport.
   /// </remarks>

   public static Point3d GetClosestPointTo(this Editor editor, Curve curve, Point3d ucsPoint)
   {
      return curve.GetClosestPointTo(ucsPoint.TransformBy(editor.CurrentUserCoordinateSystem),
         editor.GetCurrentView().ViewDirection, false);
   }

}

@_gile wrote:

Hi,

 

This one mimics the native BREAK command.

 

        [CommandMethod("BRLPL")]
        public void BreakLineOrPolyline()
        {
            var doc = AcAp.DocumentManager.MdiActiveDocument;
            var db = doc.Database;
            var ed = doc.Editor;

            var entityOptions = new PromptEntityOptions("\nSelect line or polyline: ");
            entityOptions.SetRejectMessage("Selected object is neither a line nor a polyline.");
            entityOptions.AddAllowedClass(typeof(Polyline), true);
            entityOptions.AddAllowedClass(typeof(Line), true);
            var entityResult = ed.GetEntity(entityOptions);
            if (entityResult.Status != PromptStatus.OK)
                return;

            Point3d pt1, pt2;
            var ucs = ed.CurrentUserCoordinateSystem;
            var pointOptions = new PromptPointOptions("\nSpecify second point or [First point]: ", "First");
            var pointResult = ed.GetPoint(pointOptions);
            if (pointResult.Status == PromptStatus.Keyword)
            {
                pointOptions.Message = "\nSpecify first point: ";
                pointOptions.Keywords.Clear();
                pointResult = ed.GetPoint(pointOptions);
                if (pointResult.Status != PromptStatus.OK)
                    return;
                pt1 = pointResult.Value.TransformBy(ucs);
                pointOptions.Message = "\nSpecify second point: ";
                pointResult = ed.GetPoint(pointOptions);
                if (pointResult.Status != PromptStatus.OK)
                    return;
                pt2 = pointResult.Value.TransformBy(ucs);
            }
            else if (pointResult.Status == PromptStatus.OK)
            {
                pt1 = entityResult.PickedPoint.TransformBy(ucs);
                pt2 = pointResult.Value.TransformBy(ucs);
            }
            else return;

            using (var tr = db.TransactionManager.StartTransaction())
            {
                var curve = (Curve)tr.GetObject(entityResult.ObjectId, OpenMode.ForWrite);
                double param1 = curve.GetParameterAtPoint(curve.GetClosestPointTo(pt1, false));
                double param2 = curve.GetParameterAtPoint(curve.GetClosestPointTo(pt2, false));
                var parameters = new DoubleCollection
                    (new[] { param1, param2 }
                    .Distinct()
                    .OrderBy(x => x)
                    .ToArray());
                var curves = curve.GetSplitCurves(parameters);
                var curSpace = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                switch (curves.Count)
                {
                    case 3:
                        curSpace.AppendEntity((Entity)curves[0]);
                        tr.AddNewlyCreatedDBObject(curves[0], true);
                        curSpace.AppendEntity((Entity)curves[2]);
                        tr.AddNewlyCreatedDBObject(curves[2], true);
                        curves[1].Dispose();
                        curve.Erase();
                        break;
                    case 2:
                        curSpace.AppendEntity((Entity)curves[0]);
                        tr.AddNewlyCreatedDBObject(curves[0], true);
                        curSpace.AppendEntity((Entity)curves[1]);
                        tr.AddNewlyCreatedDBObject(curves[1], true);
                        curve.Erase();
                        break;
                    default:
                        break;
                }
                tr.Commit();
            }
        }

 

0 Likes

 

Hi @_gile

 

To fully-mimic the native BREAK command, the code must honor application data and inter-object references that can be established with most any type of AutoCAD entity (this holds especially true with the use of constraints), so rather than erasing the original object, and appending the replacement object(s), You can use HandOverTo() on the original object and the first replacement object, because that preserves both application data and inter-object references.

 

One other minor point about your code is that there's no need for calling Distinct() on points or parameters passed to GetSplitCurves(). It will ignore duplicates and also points or parameters that correspond to the start/end points/parameters. I only recently discovered that myself after reading the native ObjectARX docs and doing some testing.

 

And lastly, like most example code posted here (including my own), your code will work on entities that lie in the XY plane of the current UCS, in a PLAN view of same, but can easily fail if the entities involved do not lie in the current UCS XY plane, and/or the current view is not a plan view of same. The reason is because the point returned by GetEntity() is always in the XY plane of the current UCS, which may not be the closest point to the selected curve in the DCS.

 

Here's the extension method I use to properly find the point on a curve, closest to the point where the curve was picked:

 

public static class EditorExtensions
{
   /// <summary>
   /// Returns the point on the given curve that is closest to
   /// a line that's parallel to the current view direction, 
   /// and passes through the given point. The given point is
   /// a point expressed in the current UCS. The resulting
   /// point is expressed in the WCS.
   /// </summary>
   /// 
   /// <remarks>This API must be called immediately after the
   /// given point is acquired via an interactive function such
   /// as GetPoint(), GetEntity(), etc., in cases where there
   /// are multiple points being obtained, and the user is able
   /// to switch viewports and specify points in any viewport.
   /// </remarks>

   public static Point3d GetClosestPointTo(this Editor editor, Curve curve, Point3d ucsPoint)
   {
      return curve.GetClosestPointTo(ucsPoint.TransformBy(editor.CurrentUserCoordinateSystem),
         editor.GetCurrentView().ViewDirection, false);
   }

}

@_gile wrote:

Hi,

 

This one mimics the native BREAK command.

 

        [CommandMethod("BRLPL")]
        public void BreakLineOrPolyline()
        {
            var doc = AcAp.DocumentManager.MdiActiveDocument;
            var db = doc.Database;
            var ed = doc.Editor;

            var entityOptions = new PromptEntityOptions("\nSelect line or polyline: ");
            entityOptions.SetRejectMessage("Selected object is neither a line nor a polyline.");
            entityOptions.AddAllowedClass(typeof(Polyline), true);
            entityOptions.AddAllowedClass(typeof(Line), true);
            var entityResult = ed.GetEntity(entityOptions);
            if (entityResult.Status != PromptStatus.OK)
                return;

            Point3d pt1, pt2;
            var ucs = ed.CurrentUserCoordinateSystem;
            var pointOptions = new PromptPointOptions("\nSpecify second point or [First point]: ", "First");
            var pointResult = ed.GetPoint(pointOptions);
            if (pointResult.Status == PromptStatus.Keyword)
            {
                pointOptions.Message = "\nSpecify first point: ";
                pointOptions.Keywords.Clear();
                pointResult = ed.GetPoint(pointOptions);
                if (pointResult.Status != PromptStatus.OK)
                    return;
                pt1 = pointResult.Value.TransformBy(ucs);
                pointOptions.Message = "\nSpecify second point: ";
                pointResult = ed.GetPoint(pointOptions);
                if (pointResult.Status != PromptStatus.OK)
                    return;
                pt2 = pointResult.Value.TransformBy(ucs);
            }
            else if (pointResult.Status == PromptStatus.OK)
            {
                pt1 = entityResult.PickedPoint.TransformBy(ucs);
                pt2 = pointResult.Value.TransformBy(ucs);
            }
            else return;

            using (var tr = db.TransactionManager.StartTransaction())
            {
                var curve = (Curve)tr.GetObject(entityResult.ObjectId, OpenMode.ForWrite);
                double param1 = curve.GetParameterAtPoint(curve.GetClosestPointTo(pt1, false));
                double param2 = curve.GetParameterAtPoint(curve.GetClosestPointTo(pt2, false));
                var parameters = new DoubleCollection
                    (new[] { param1, param2 }
                    .Distinct()
                    .OrderBy(x => x)
                    .ToArray());
                var curves = curve.GetSplitCurves(parameters);
                var curSpace = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                switch (curves.Count)
                {
                    case 3:
                        curSpace.AppendEntity((Entity)curves[0]);
                        tr.AddNewlyCreatedDBObject(curves[0], true);
                        curSpace.AppendEntity((Entity)curves[2]);
                        tr.AddNewlyCreatedDBObject(curves[2], true);
                        curves[1].Dispose();
                        curve.Erase();
                        break;
                    case 2:
                        curSpace.AppendEntity((Entity)curves[0]);
                        tr.AddNewlyCreatedDBObject(curves[0], true);
                        curSpace.AppendEntity((Entity)curves[1]);
                        tr.AddNewlyCreatedDBObject(curves[1], true);
                        curve.Erase();
                        break;
                    default:
                        break;
                }
                tr.Commit();
            }
        }

 

Message 13 of 37
_gile
in reply to: ActivistInvestor

_gile
Mentor
Mentor

Hi @ActivistInvestor

 

Thanks for these clafications.

I thaught about HandOverTo() (and also the curve plane and current view) but I wanted to keep the code focused on the @Anonymous request.

Thanks also for your extension methods.



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes

Hi @ActivistInvestor

 

Thanks for these clafications.

I thaught about HandOverTo() (and also the curve plane and current view) but I wanted to keep the code focused on the @Anonymous request.

Thanks also for your extension methods.



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 14 of 37
ActivistInvestor
in reply to: _gile

ActivistInvestor
Advisor
Advisor

@_gile wrote:

Hi @ActivistInvestor

 

Thanks for these clafications.

I thaught about HandOverTo() (and also the curve plane and current view) but I wanted to keep the code focused on the @Anonymous request.

Thanks also for your extension methods.


You're welcome @_gile. I only mentioned those things because I had been bitten by the same 'selection in non-plan view problem' recently also, and was also under assumption that Distinct() must be used to remove duplicate points/parameters.

0 Likes


@_gile wrote:

Hi @ActivistInvestor

 

Thanks for these clafications.

I thaught about HandOverTo() (and also the curve plane and current view) but I wanted to keep the code focused on the @Anonymous request.

Thanks also for your extension methods.


You're welcome @_gile. I only mentioned those things because I had been bitten by the same 'selection in non-plan view problem' recently also, and was also under assumption that Distinct() must be used to remove duplicate points/parameters.

Message 15 of 37
_gile
in reply to: ActivistInvestor

_gile
Mentor
Mentor
Accepted solution

A new version including @ActivistInvestor suggestions.

 

        [CommandMethod("BRLPL")]
        public void BreakLineOrPolyline()
        {
            var doc = AcAp.DocumentManager.MdiActiveDocument;
            var db = doc.Database;
            var ed = doc.Editor;

            var entityOptions = new PromptEntityOptions("\nSelect line or polyline: ");
            entityOptions.SetRejectMessage("Selected object is neither a line nor a polyline.");
            entityOptions.AddAllowedClass(typeof(Polyline), true);
            entityOptions.AddAllowedClass(typeof(Line), true);
            var entityResult = ed.GetEntity(entityOptions);
            if (entityResult.Status != PromptStatus.OK)
                return;

            Point3d pt1, pt2;
            var ucs = ed.CurrentUserCoordinateSystem;
            Vector3d viewDir;
            using (var view = ed.GetCurrentView())
                viewDir = view.ViewDirection;
            var pointOptions = new PromptPointOptions("\nSpecify second point or [First point]: ", "First");
            var pointResult = ed.GetPoint(pointOptions);
            if (pointResult.Status == PromptStatus.Keyword)
            {
                pointOptions.Message = "\nSpecify first point: ";
                pointOptions.Keywords.Clear();
                pointResult = ed.GetPoint(pointOptions);
                if (pointResult.Status != PromptStatus.OK)
                    return;
                pt1 = pointResult.Value.TransformBy(ucs);
                pointOptions.Message = "\nSpecify second point: ";
                pointResult = ed.GetPoint(pointOptions);
                if (pointResult.Status != PromptStatus.OK)
                    return;
                pt2 = pointResult.Value.TransformBy(ucs);
            }
            else if (pointResult.Status == PromptStatus.OK)
            {
                pt1 = entityResult.PickedPoint.TransformBy(ucs);
                pt2 = pointResult.Value.TransformBy(ucs);
            }
            else return;

            using (var tr = db.TransactionManager.StartOpenCloseTransaction())
            {
                var curve = (Curve)tr.GetObject(entityResult.ObjectId, OpenMode.ForWrite);
                double param1 = curve.GetParameterAtPoint(curve.GetClosestPointTo(pt1, viewDir, false));
                double param2 = curve.GetParameterAtPoint(curve.GetClosestPointTo(pt2, viewDir, false));
                var parameters = new DoubleCollection
                    (new[] { param1, param2 }
                    .OrderBy(x => x)
                    .ToArray());
                var curves = curve.GetSplitCurves(parameters);
                var curSpace = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                switch (curves.Count)
                {
                    case 3:
                        curve.HandOverTo(curves[0], true, true);
                        curSpace.AppendEntity((Entity)curves[2]);
                        tr.AddNewlyCreatedDBObject(curves[2], true);
                        curves[1].Dispose();
                        break;
                    case 2:
                        curve.HandOverTo(curves[0], true, true);
                        curSpace.AppendEntity((Entity)curves[1]);
                        tr.AddNewlyCreatedDBObject(curves[1], true);
                        break;
                    default:
                        break;
                }
                curves[0].Dispose();
                tr.Commit();
            }
        }


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

A new version including @ActivistInvestor suggestions.

 

        [CommandMethod("BRLPL")]
        public void BreakLineOrPolyline()
        {
            var doc = AcAp.DocumentManager.MdiActiveDocument;
            var db = doc.Database;
            var ed = doc.Editor;

            var entityOptions = new PromptEntityOptions("\nSelect line or polyline: ");
            entityOptions.SetRejectMessage("Selected object is neither a line nor a polyline.");
            entityOptions.AddAllowedClass(typeof(Polyline), true);
            entityOptions.AddAllowedClass(typeof(Line), true);
            var entityResult = ed.GetEntity(entityOptions);
            if (entityResult.Status != PromptStatus.OK)
                return;

            Point3d pt1, pt2;
            var ucs = ed.CurrentUserCoordinateSystem;
            Vector3d viewDir;
            using (var view = ed.GetCurrentView())
                viewDir = view.ViewDirection;
            var pointOptions = new PromptPointOptions("\nSpecify second point or [First point]: ", "First");
            var pointResult = ed.GetPoint(pointOptions);
            if (pointResult.Status == PromptStatus.Keyword)
            {
                pointOptions.Message = "\nSpecify first point: ";
                pointOptions.Keywords.Clear();
                pointResult = ed.GetPoint(pointOptions);
                if (pointResult.Status != PromptStatus.OK)
                    return;
                pt1 = pointResult.Value.TransformBy(ucs);
                pointOptions.Message = "\nSpecify second point: ";
                pointResult = ed.GetPoint(pointOptions);
                if (pointResult.Status != PromptStatus.OK)
                    return;
                pt2 = pointResult.Value.TransformBy(ucs);
            }
            else if (pointResult.Status == PromptStatus.OK)
            {
                pt1 = entityResult.PickedPoint.TransformBy(ucs);
                pt2 = pointResult.Value.TransformBy(ucs);
            }
            else return;

            using (var tr = db.TransactionManager.StartOpenCloseTransaction())
            {
                var curve = (Curve)tr.GetObject(entityResult.ObjectId, OpenMode.ForWrite);
                double param1 = curve.GetParameterAtPoint(curve.GetClosestPointTo(pt1, viewDir, false));
                double param2 = curve.GetParameterAtPoint(curve.GetClosestPointTo(pt2, viewDir, false));
                var parameters = new DoubleCollection
                    (new[] { param1, param2 }
                    .OrderBy(x => x)
                    .ToArray());
                var curves = curve.GetSplitCurves(parameters);
                var curSpace = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                switch (curves.Count)
                {
                    case 3:
                        curve.HandOverTo(curves[0], true, true);
                        curSpace.AppendEntity((Entity)curves[2]);
                        tr.AddNewlyCreatedDBObject(curves[2], true);
                        curves[1].Dispose();
                        break;
                    case 2:
                        curve.HandOverTo(curves[0], true, true);
                        curSpace.AppendEntity((Entity)curves[1]);
                        tr.AddNewlyCreatedDBObject(curves[1], true);
                        break;
                    default:
                        break;
                }
                curves[0].Dispose();
                tr.Commit();
            }
        }


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 16 of 37
ActivistInvestor
in reply to: _gile

ActivistInvestor
Advisor
Advisor

@_gile wrote:

A new version including @ActivistInvestor suggestions.

 

        [CommandMethod("BRLPL")]
        public void BreakLineOrPolyline()
        {
            var doc = AcAp.DocumentManager.MdiActiveDocument;
            var db = doc.Database;
            var ed = doc.Editor;

            var entityOptions = new PromptEntityOptions("\nSelect line or polyline: ");
            entityOptions.SetRejectMessage("Selected object is neither a line nor a polyline.");
            entityOptions.AddAllowedClass(typeof(Polyline), true);
            entityOptions.AddAllowedClass(typeof(Line), true);
            var entityResult = ed.GetEntity(entityOptions);
            if (entityResult.Status != PromptStatus.OK)
                return;

            Point3d pt1, pt2;
            var ucs = ed.CurrentUserCoordinateSystem;
            Vector3d viewDir;
            using (var view = ed.GetCurrentView())
                viewDir = view.ViewDirection;
            var pointOptions = new PromptPointOptions("\nSpecify second point or [First point]: ", "First");
            var pointResult = ed.GetPoint(pointOptions);
            if (pointResult.Status == PromptStatus.Keyword)
            {
                pointOptions.Message = "\nSpecify first point: ";
                pointOptions.Keywords.Clear();
                pointResult = ed.GetPoint(pointOptions);
                if (pointResult.Status != PromptStatus.OK)
                    return;
                pt1 = pointResult.Value.TransformBy(ucs);
                pointOptions.Message = "\nSpecify second point: ";
                pointResult = ed.GetPoint(pointOptions);
                if (pointResult.Status != PromptStatus.OK)
                    return;
                pt2 = pointResult.Value.TransformBy(ucs);
            }
            else if (pointResult.Status == PromptStatus.OK)
            {
                pt1 = entityResult.PickedPoint.TransformBy(ucs);
                pt2 = pointResult.Value.TransformBy(ucs);
            }
            else return;

            using (var tr = db.TransactionManager.StartOpenCloseTransaction())
            {
                var curve = (Curve)tr.GetObject(entityResult.ObjectId, OpenMode.ForWrite);
                double param1 = curve.GetParameterAtPoint(curve.GetClosestPointTo(pt1, viewDir, false));
                double param2 = curve.GetParameterAtPoint(curve.GetClosestPointTo(pt2, viewDir, false));
                var parameters = new DoubleCollection
                    (new[] { param1, param2 }
                    .OrderBy(x => x)
                    .ToArray());
                var curves = curve.GetSplitCurves(parameters);
                var curSpace = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                switch (curves.Count)
                {
                    case 3:
                        curve.HandOverTo(curves[0], true, true);
                        curSpace.AppendEntity((Entity)curves[2]);
                        tr.AddNewlyCreatedDBObject(curves[2], true);
                        curves[1].Dispose();
                        break;
                    case 2:
                        curve.HandOverTo(curves[0], true, true);
                        curSpace.AppendEntity((Entity)curves[1]);
                        tr.AddNewlyCreatedDBObject(curves[1], true);
                        break;
                    default:
                        break;
                }
                curves[0].Dispose();
                tr.Commit();
            }
        }

Nice @_gile.

 

I haven't noticed any problems with not disposing the ViewTableRecord returned by GetCurrentView() (perhaps because the AcDbViewTableRecord's destructor is thread-safe), but I'll revise my extension method to do that also.

 

0 Likes


@_gile wrote:

A new version including @ActivistInvestor suggestions.

 

        [CommandMethod("BRLPL")]
        public void BreakLineOrPolyline()
        {
            var doc = AcAp.DocumentManager.MdiActiveDocument;
            var db = doc.Database;
            var ed = doc.Editor;

            var entityOptions = new PromptEntityOptions("\nSelect line or polyline: ");
            entityOptions.SetRejectMessage("Selected object is neither a line nor a polyline.");
            entityOptions.AddAllowedClass(typeof(Polyline), true);
            entityOptions.AddAllowedClass(typeof(Line), true);
            var entityResult = ed.GetEntity(entityOptions);
            if (entityResult.Status != PromptStatus.OK)
                return;

            Point3d pt1, pt2;
            var ucs = ed.CurrentUserCoordinateSystem;
            Vector3d viewDir;
            using (var view = ed.GetCurrentView())
                viewDir = view.ViewDirection;
            var pointOptions = new PromptPointOptions("\nSpecify second point or [First point]: ", "First");
            var pointResult = ed.GetPoint(pointOptions);
            if (pointResult.Status == PromptStatus.Keyword)
            {
                pointOptions.Message = "\nSpecify first point: ";
                pointOptions.Keywords.Clear();
                pointResult = ed.GetPoint(pointOptions);
                if (pointResult.Status != PromptStatus.OK)
                    return;
                pt1 = pointResult.Value.TransformBy(ucs);
                pointOptions.Message = "\nSpecify second point: ";
                pointResult = ed.GetPoint(pointOptions);
                if (pointResult.Status != PromptStatus.OK)
                    return;
                pt2 = pointResult.Value.TransformBy(ucs);
            }
            else if (pointResult.Status == PromptStatus.OK)
            {
                pt1 = entityResult.PickedPoint.TransformBy(ucs);
                pt2 = pointResult.Value.TransformBy(ucs);
            }
            else return;

            using (var tr = db.TransactionManager.StartOpenCloseTransaction())
            {
                var curve = (Curve)tr.GetObject(entityResult.ObjectId, OpenMode.ForWrite);
                double param1 = curve.GetParameterAtPoint(curve.GetClosestPointTo(pt1, viewDir, false));
                double param2 = curve.GetParameterAtPoint(curve.GetClosestPointTo(pt2, viewDir, false));
                var parameters = new DoubleCollection
                    (new[] { param1, param2 }
                    .OrderBy(x => x)
                    .ToArray());
                var curves = curve.GetSplitCurves(parameters);
                var curSpace = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                switch (curves.Count)
                {
                    case 3:
                        curve.HandOverTo(curves[0], true, true);
                        curSpace.AppendEntity((Entity)curves[2]);
                        tr.AddNewlyCreatedDBObject(curves[2], true);
                        curves[1].Dispose();
                        break;
                    case 2:
                        curve.HandOverTo(curves[0], true, true);
                        curSpace.AppendEntity((Entity)curves[1]);
                        tr.AddNewlyCreatedDBObject(curves[1], true);
                        break;
                    default:
                        break;
                }
                curves[0].Dispose();
                tr.Commit();
            }
        }

Nice @_gile.

 

I haven't noticed any problems with not disposing the ViewTableRecord returned by GetCurrentView() (perhaps because the AcDbViewTableRecord's destructor is thread-safe), but I'll revise my extension method to do that also.

 

Message 17 of 37
_gile
in reply to: ActivistInvestor

_gile
Mentor
Mentor

Activist_Investor a écrit :

Nice @_gile.

I haven't noticed any problems with not disposing the ViewTableRecord returned by GetCurrentView() (perhaps because the AcDbViewTableRecord's destructor is thread-safe), but I'll revise my extension method to do that also.


 

Thanks,

 

I just noticed a warning in th VS Output window:

Forgot to call Dispose? (Autodesk.AutoCAD.DatabaseServices.ViewTableRecord): DisposableWrapper



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes


Activist_Investor a écrit :

Nice @_gile.

I haven't noticed any problems with not disposing the ViewTableRecord returned by GetCurrentView() (perhaps because the AcDbViewTableRecord's destructor is thread-safe), but I'll revise my extension method to do that also.


 

Thanks,

 

I just noticed a warning in th VS Output window:

Forgot to call Dispose? (Autodesk.AutoCAD.DatabaseServices.ViewTableRecord): DisposableWrapper



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 18 of 37
ActivistInvestor
in reply to: _gile

ActivistInvestor
Advisor
Advisor

@_gile, please read again the remarks from my GetClosestPointTo() extension method:

 

 

   /// <remarks>This API must be called immediately after the
   /// given point is acquired via an interactive function such
   /// as GetPoint(), GetEntity(), etc., in cases where there
   /// are multiple points being obtained, and the user is able
   /// to switch viewports and specify points in any viewport.
   /// </remarks>

 

And, see my annotations of your code:

 


@_gile wrote:

A new version including @ActivistInvestor suggestions.

 

  [CommandMethod("BRLPL")]
  public void BreakLineOrPolyline()
  {
      var doc = AcAp.DocumentManager.MdiActiveDocument;
      var db = doc.Database;
      var ed = doc.Editor;

      var entityOptions = new PromptEntityOptions("\nSelect line or polyline: ");
      entityOptions.SetRejectMessage("Selected object is neither a line nor a polyline.");
      entityOptions.AddAllowedClass(typeof(Polyline), true);
      entityOptions.AddAllowedClass(typeof(Line), true);
      var entityResult = ed.GetEntity(entityOptions);
      if (entityResult.Status != PromptStatus.OK)
          return;

      Point3d pt1, pt2;
      var ucs = ed.CurrentUserCoordinateSystem;
      Vector3d viewDir;
      using (var view = ed.GetCurrentView())
          viewDir = view.ViewDirection;

      //////////////////////////////////////////////////////////////
      // viewDir is valid for the PickedPoint of the entityResult
      //////////////////////////////////////////////////////////////            
      var pointOptions = new PromptPointOptions("\nSpecify second point or [First point]: ", "First");
      var pointResult = ed.GetPoint(pointOptions);

      /////////////////////////////////////////////////////////////
      // At the above prompt from GetPoint(), the user can 
      // change the active viewport, or transparently orbit
      // the current view before picking the point, making 
      // the above viewDir invalid for the selected point. 
      /////////////////////////////////////////////////////////////
      if (pointResult.Status == PromptStatus.Keyword)
      {
          pointOptions.Message = "\nSpecify first point: ";
          pointOptions.Keywords.Clear();
          pointResult = ed.GetPoint(pointOptions);
          if (pointResult.Status != PromptStatus.OK)
              return;
          pt1 = pointResult.Value.TransformBy(ucs);
          pointOptions.Message = "\nSpecify second point: ";
          pointResult = ed.GetPoint(pointOptions);
///////////////////////////////////////////////////////////////// // Ditto as per above for the second call to GetPoint(), // the viewDir is not valid for computing a point on the curve /////////////////////////////////////////////////////////////////
if (pointResult.Status != PromptStatus.OK) return; pt2 = pointResult.Value.TransformBy(ucs); } else if (pointResult.Status == PromptStatus.OK) { pt1 = entityResult.PickedPoint.TransformBy(ucs); pt2 = pointResult.Value.TransformBy(ucs); } else return; using (var tr = db.TransactionManager.StartOpenCloseTransaction()) { var curve = (Curve)tr.GetObject(entityResult.ObjectId, OpenMode.ForWrite); double param1 = curve.GetParameterAtPoint(curve.GetClosestPointTo(pt1, viewDir, false)); double param2 = curve.GetParameterAtPoint(curve.GetClosestPointTo(pt2, viewDir, false)); var parameters = new DoubleCollection (new[] { param1, param2 } .OrderBy(x => x) .ToArray()); var curves = curve.GetSplitCurves(parameters); var curSpace = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite); switch (curves.Count) { case 3: curve.HandOverTo(curves[0], true, true); curSpace.AppendEntity((Entity)curves[2]); tr.AddNewlyCreatedDBObject(curves[2], true); curves[1].Dispose(); break; case 2: curve.HandOverTo(curves[0], true, true); curSpace.AppendEntity((Entity)curves[1]); tr.AddNewlyCreatedDBObject(curves[1], true); break; default: break; } curves[0].Dispose(); tr.Commit(); } }

 

This is one reason why I chose to take a modular route for solving this problem, and my own library takes it a bit further..

 

Below are surrogates for GetEntity() and GetPoint() that encapsulate both the selection, and computing the point on the selected curve, so that it is done at the point when it must be done (immediately after the user responds to the prompt, while the view they used to pick the entity or point is unchanged). 

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Linq.Expressions;
using System.MyDiagnostics;

using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using AcadApp = Autodesk.AutoCAD.ApplicationServices.Application;

#pragma warning disable 0618

namespace Autodesk.AutoCAD.EditorInput
{
   public static class EditorExtensions
   {
      /// <summary>
      /// Returns the WCS point on the given curve that is closest 
      /// to a line parallel to the current view direction, passing
      /// through the given point. The given point must be expressed
      /// in current UCS coordinates, and is typically obtained from 
      /// an instance of PromptResult-based type returned by a call
      /// to one of the Editor's GetXxxxx() methods.
      /// 
      /// The resulting point is a World coordinate.
      /// </summary>
      /// <remarks>This API must be called <em>immediately</em> after 
      /// the given point is acquired via an interactive function such
      /// as GetPoint(), GetEntity(), etc., while the viewport which
      /// the point or object was selected in is still active, and the 
      /// view parameters of that viewport have not changed.
      /// 
      /// This method produces the 'apparent' nearest point on the 
      /// curve, accounting for the curve's orientation in 3D space, 
      /// the current view direction, and the current UCS.
      /// </remarks>

      public static Point3d GetClosestPointTo(this Editor editor, Curve curve, Point3d ucsPoint)
      {
         Assert.IsNotNull(editor, "editor");
         Assert.IsNotNull(curve, "curve");
         using(var view = editor.GetCurrentView())
         {
            return curve.GetClosestPointTo(
               ucsPoint.TransformBy(editor.CurrentUserCoordinateSystem),
               view.ViewDirection,
               false);
         }
      }

      /// <summary>
      /// Like GetEntity(), except that if the selected entity is a curve,
      /// the PickedPoint is the WCS point on the curve closest to a line 
      /// parallel to the view direction, passing through the point used 
      /// to pick the curve.
      ///
      /// The PickedPoint property of the result <em>is a WCS coordinate</em>.
      /// </summary>
      /// <remarks>
      /// This method encapsulates the process of selecting an entity and
      /// if it is a curve, computing the point on the curve nearest to the
      /// selection point, to ensure that the correct view parameters are 
      /// used in the computation.
      /// 
      /// This method does not restrict selection to a Curve-based type, as 
      /// it is designed to work with any type derived from Curve. Therefore, 
      /// the caller should initialize the options argument as needed to 
      /// restrict input to a Curve-based type, using AddAllowedClass() and 
      /// SetRejectMessage().
      /// </remarks>

      public static PromptEntityResult GetCurve(this Editor editor, PromptEntityOptions options, bool setLastPoint = false)
      {
         Assert.IsNotNull(editor, "editor");
         Assert.IsNotNull(options, "options");
         var result = editor.GetEntity(options);
         if(result.Status == PromptStatus.OK && result.ObjectId.ObjectClass.IsDerivedFrom(curveClass))
         {
            using(Curve curve = (Curve) result.ObjectId.Open(OpenMode.ForRead))
            {
               var rawPoint = result.PickedPoint;
               result.SetPickPoint(GetClosestPointTo(editor, curve, rawPoint));
               if(setLastPoint)
                  AcadApp.SetSystemVariable("LASTPOINT", rawPoint);
            }
         }
         return result;
      }

      public static PromptEntityResult GetCurve(this Editor editor, string message)
      {
         return GetCurve(editor, new PromptEntityOptions(message));
      }

      /// <summary>
      /// Like GetPoint(), except can be used when requesting a point that
      /// lies on a Curve. The PromptPointResult will contain the WCS point 
      /// on the curve, nearest to the selection point in the DCS. It will
      /// optionally set the LASTPOINT system variable to the 'raw' picked
      /// point.
      ///
      /// The Value property of the result <em>is a World coordinate</em>.
      /// </summary>
      /// <remarks>
      /// This method encapsulates the process of obtaining a point on a
      /// curve and computing that point to ensure that the correct view 
      /// parameters are used in the computation.
      /// </remarks>
      /// <param name="setLastPoint">True to set the LASTPOINT system 
      /// variable to the actual UCS point that was selected.</param>
      /// <returns></returns>

      public static PromptPointResult GetPointOn(this Editor editor, Curve curve, PromptPointOptions options, bool setLastPoint = false)
      {
         Assert.IsNotNull(editor, "editor");
         Assert.IsNotNull(options, "ppo");
         Assert.IsNotNull(curve, "curve");
         var result = editor.GetPoint(options);
         if(result.Status == PromptStatus.OK)
         {
            var rawPoint = result.Value;
            result.SetValue(GetClosestPointTo(editor, curve, rawPoint));
            if(setLastPoint)
               AcadApp.SetSystemVariable("LASTPOINT", rawPoint);
         }
         return result;
      }

      /// <summary>
      /// Prompts user for a point and returns the WCS point on the Curve 
      /// whose ObjectId is the given curveId, nearest to a line passing 
      /// through the user-selected point, and parallel to the current 
      /// view direction.
      /// 
      /// This method encapsulates the process of obtaining a point on a
      /// curve and computing that point to ensure that the correct view 
      /// parameters are used in the computation.
      ///
      /// The Value property of the result <em>is a World coordinate</em>.
      /// </summary>

      public static PromptPointResult GetPointOn(this Editor editor, ObjectId curveId, PromptPointOptions options, bool setLastPoint = false)
      {
         ErrorStatus.NullObjectId.Check(!curveId.IsNull);
         ErrorStatus.WrongObjectType.Check(curveId.ObjectClass.IsDerivedFrom(curveClass));
         var result = editor.GetPoint(options);
         if(result.Status == PromptStatus.OK)
         {
            using(Curve curve = (Curve) curveId.Open(OpenMode.ForRead))
            {
               Point3d rawPoint = result.Value;
               result.SetValue(GetClosestPointTo(editor, curve, rawPoint));
               if(setLastPoint)
                  AcadApp.SetSystemVariable("LASTPOINT", rawPoint);
            }
         }
         return result;
      }

      public static PromptPointResult GetPointOn(this Editor editor, ObjectId curveId, string message, bool setLastPoint = false)
      {
         Assert.IsNotNullOrWhiteSpace(message, "message");
         return GetPointOn(editor, curveId, new PromptPointOptions(message), setLastPoint);
      }

      public static PromptPointResult GetPointOn(this Editor editor, Curve curve, string message, bool setLastPoint = false)
      {
         Assert.IsNotNullOrWhiteSpace(message, "message");
         return GetPointOn(editor, curve, new PromptPointOptions(message), setLastPoint);
      }

      static void SetValue(this PromptPointResult ppr, Point3d point)
      {
         ppr_set_value(ppr, point);
      }

      static void SetPickPoint(this PromptEntityResult per, Point3d point)
      {
         per_set_pickPoint(per, point);
      }

      static Action<PromptPointResult, Point3d> ppr_set_value =
         FieldAccess.GetModifier<PromptPointResult, Point3d>("m_value");
      static Action<PromptEntityResult, Point3d> per_set_pickPoint =
         FieldAccess.GetModifier<PromptEntityResult, Point3d>("m_pickPoint");

      static RXClass curveClass = RXObject.GetClass(typeof(Curve));

   }
}

namespace System.Reflection
{
   /// <summary>
   /// Methods for generating delegates that access and 
   /// modify fields without relying on reflection.
   /// </summary>

   public static class FieldAccess
   {
      public static Func<TComponent, TField> GetAccessor<TComponent, TField>(string name, BindingFlags flags = defaultFlags)
      {
         return (Func<TComponent, TField>) GetAccessor(typeof(TComponent), typeof(TField), name, flags);
      }

      public static Action<TComponent, TField> GetModifier<TComponent, TField>(string name, BindingFlags flags = defaultFlags)
      {
         return (Action<TComponent, TField>) GetModifier(typeof(TComponent), typeof(TField), name, flags);
      }

      public static Delegate GetModifier(this Type declaringType, Type fieldType, string name, BindingFlags flags = defaultFlags)
      {
         Assert.IsNotNull(declaringType, "declaringType");
         Assert.IsNotNull(fieldType, "fieldType");
         Assert.IsNotNullOrWhiteSpace(name, "name");
         FieldInfo field = declaringType.GetField(name, flags);
         if(field == null)
            Throw(declaringType, name, "not found");
         var instance = Expression.Parameter(declaringType, "instance");
         var value = Expression.Parameter(fieldType, "value");
         var assign = Expression.Assign(Expression.Field(instance, field), value);
         return Expression.Lambda(assign, instance, value).Compile();
      }

      public static Delegate GetAccessor(this Type declaringType, Type fieldType, string name, BindingFlags flags = defaultFlags)
      {
         Assert.IsNotNull(declaringType, "declaringType");
         Assert.IsNotNull(fieldType, "fieldType");
         Assert.IsNotNullOrWhiteSpace(name, "name");
         FieldInfo field = declaringType.GetField(name, flags);
         if(field == null)
            Throw(declaringType, name, "not found");
         if(!fieldType.IsAssignableFrom(field.FieldType))
            Throw(declaringType, name, "type mismatch");
         ParameterExpression instance = Expression.Parameter(declaringType);
         return Expression.Lambda(Expression.Field(instance, field), new[] { instance }).Compile();
      }

      const BindingFlags defaultFlags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance;

      private static void Throw(Type type, string name, string msg)
      {
         throw new ArgumentException(string.Format("Field {0}.{1} {2}", type.Name, name, msg));
      }
   }
}

namespace System.MyDiagnostics
{
   public static class Assert
   {
      public static void IsNotNull<T>(T obj, string name) where T : class
      {
         if(obj == null)
            throw new ArgumentException(name);
      }

      public static void IsNotNullOrWhiteSpace(this string str, string name)
      {
         if(string.IsNullOrWhiteSpace(str))
            throw new ArgumentException(name);
      }
   }
}

namespace Autodesk.AutoCAD.Runtime
{

   public static class RuntimeExtensions
   {
      public static void Check(this ErrorStatus es, bool condition, string msg = null)
      {
         if(!condition)
         {
            if(msg == null)
               throw new Autodesk.AutoCAD.Runtime.Exception(es);
            else
               throw new Autodesk.AutoCAD.Runtime.Exception(es, msg);
         }
      }
   }
}

 

 

 

 

 

@_gile, please read again the remarks from my GetClosestPointTo() extension method:

 

 

   /// <remarks>This API must be called immediately after the
   /// given point is acquired via an interactive function such
   /// as GetPoint(), GetEntity(), etc., in cases where there
   /// are multiple points being obtained, and the user is able
   /// to switch viewports and specify points in any viewport.
   /// </remarks>

 

And, see my annotations of your code:

 


@_gile wrote:

A new version including @ActivistInvestor suggestions.

 

  [CommandMethod("BRLPL")]
  public void BreakLineOrPolyline()
  {
      var doc = AcAp.DocumentManager.MdiActiveDocument;
      var db = doc.Database;
      var ed = doc.Editor;

      var entityOptions = new PromptEntityOptions("\nSelect line or polyline: ");
      entityOptions.SetRejectMessage("Selected object is neither a line nor a polyline.");
      entityOptions.AddAllowedClass(typeof(Polyline), true);
      entityOptions.AddAllowedClass(typeof(Line), true);
      var entityResult = ed.GetEntity(entityOptions);
      if (entityResult.Status != PromptStatus.OK)
          return;

      Point3d pt1, pt2;
      var ucs = ed.CurrentUserCoordinateSystem;
      Vector3d viewDir;
      using (var view = ed.GetCurrentView())
          viewDir = view.ViewDirection;

      //////////////////////////////////////////////////////////////
      // viewDir is valid for the PickedPoint of the entityResult
      //////////////////////////////////////////////////////////////            
      var pointOptions = new PromptPointOptions("\nSpecify second point or [First point]: ", "First");
      var pointResult = ed.GetPoint(pointOptions);

      /////////////////////////////////////////////////////////////
      // At the above prompt from GetPoint(), the user can 
      // change the active viewport, or transparently orbit
      // the current view before picking the point, making 
      // the above viewDir invalid for the selected point. 
      /////////////////////////////////////////////////////////////
      if (pointResult.Status == PromptStatus.Keyword)
      {
          pointOptions.Message = "\nSpecify first point: ";
          pointOptions.Keywords.Clear();
          pointResult = ed.GetPoint(pointOptions);
          if (pointResult.Status != PromptStatus.OK)
              return;
          pt1 = pointResult.Value.TransformBy(ucs);
          pointOptions.Message = "\nSpecify second point: ";
          pointResult = ed.GetPoint(pointOptions);
///////////////////////////////////////////////////////////////// // Ditto as per above for the second call to GetPoint(), // the viewDir is not valid for computing a point on the curve /////////////////////////////////////////////////////////////////
if (pointResult.Status != PromptStatus.OK) return; pt2 = pointResult.Value.TransformBy(ucs); } else if (pointResult.Status == PromptStatus.OK) { pt1 = entityResult.PickedPoint.TransformBy(ucs); pt2 = pointResult.Value.TransformBy(ucs); } else return; using (var tr = db.TransactionManager.StartOpenCloseTransaction()) { var curve = (Curve)tr.GetObject(entityResult.ObjectId, OpenMode.ForWrite); double param1 = curve.GetParameterAtPoint(curve.GetClosestPointTo(pt1, viewDir, false)); double param2 = curve.GetParameterAtPoint(curve.GetClosestPointTo(pt2, viewDir, false)); var parameters = new DoubleCollection (new[] { param1, param2 } .OrderBy(x => x) .ToArray()); var curves = curve.GetSplitCurves(parameters); var curSpace = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite); switch (curves.Count) { case 3: curve.HandOverTo(curves[0], true, true); curSpace.AppendEntity((Entity)curves[2]); tr.AddNewlyCreatedDBObject(curves[2], true); curves[1].Dispose(); break; case 2: curve.HandOverTo(curves[0], true, true); curSpace.AppendEntity((Entity)curves[1]); tr.AddNewlyCreatedDBObject(curves[1], true); break; default: break; } curves[0].Dispose(); tr.Commit(); } }

 

This is one reason why I chose to take a modular route for solving this problem, and my own library takes it a bit further..

 

Below are surrogates for GetEntity() and GetPoint() that encapsulate both the selection, and computing the point on the selected curve, so that it is done at the point when it must be done (immediately after the user responds to the prompt, while the view they used to pick the entity or point is unchanged). 

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Linq.Expressions;
using System.MyDiagnostics;

using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using AcadApp = Autodesk.AutoCAD.ApplicationServices.Application;

#pragma warning disable 0618

namespace Autodesk.AutoCAD.EditorInput
{
   public static class EditorExtensions
   {
      /// <summary>
      /// Returns the WCS point on the given curve that is closest 
      /// to a line parallel to the current view direction, passing
      /// through the given point. The given point must be expressed
      /// in current UCS coordinates, and is typically obtained from 
      /// an instance of PromptResult-based type returned by a call
      /// to one of the Editor's GetXxxxx() methods.
      /// 
      /// The resulting point is a World coordinate.
      /// </summary>
      /// <remarks>This API must be called <em>immediately</em> after 
      /// the given point is acquired via an interactive function such
      /// as GetPoint(), GetEntity(), etc., while the viewport which
      /// the point or object was selected in is still active, and the 
      /// view parameters of that viewport have not changed.
      /// 
      /// This method produces the 'apparent' nearest point on the 
      /// curve, accounting for the curve's orientation in 3D space, 
      /// the current view direction, and the current UCS.
      /// </remarks>

      public static Point3d GetClosestPointTo(this Editor editor, Curve curve, Point3d ucsPoint)
      {
         Assert.IsNotNull(editor, "editor");
         Assert.IsNotNull(curve, "curve");
         using(var view = editor.GetCurrentView())
         {
            return curve.GetClosestPointTo(
               ucsPoint.TransformBy(editor.CurrentUserCoordinateSystem),
               view.ViewDirection,
               false);
         }
      }

      /// <summary>
      /// Like GetEntity(), except that if the selected entity is a curve,
      /// the PickedPoint is the WCS point on the curve closest to a line 
      /// parallel to the view direction, passing through the point used 
      /// to pick the curve.
      ///
      /// The PickedPoint property of the result <em>is a WCS coordinate</em>.
      /// </summary>
      /// <remarks>
      /// This method encapsulates the process of selecting an entity and
      /// if it is a curve, computing the point on the curve nearest to the
      /// selection point, to ensure that the correct view parameters are 
      /// used in the computation.
      /// 
      /// This method does not restrict selection to a Curve-based type, as 
      /// it is designed to work with any type derived from Curve. Therefore, 
      /// the caller should initialize the options argument as needed to 
      /// restrict input to a Curve-based type, using AddAllowedClass() and 
      /// SetRejectMessage().
      /// </remarks>

      public static PromptEntityResult GetCurve(this Editor editor, PromptEntityOptions options, bool setLastPoint = false)
      {
         Assert.IsNotNull(editor, "editor");
         Assert.IsNotNull(options, "options");
         var result = editor.GetEntity(options);
         if(result.Status == PromptStatus.OK && result.ObjectId.ObjectClass.IsDerivedFrom(curveClass))
         {
            using(Curve curve = (Curve) result.ObjectId.Open(OpenMode.ForRead))
            {
               var rawPoint = result.PickedPoint;
               result.SetPickPoint(GetClosestPointTo(editor, curve, rawPoint));
               if(setLastPoint)
                  AcadApp.SetSystemVariable("LASTPOINT", rawPoint);
            }
         }
         return result;
      }

      public static PromptEntityResult GetCurve(this Editor editor, string message)
      {
         return GetCurve(editor, new PromptEntityOptions(message));
      }

      /// <summary>
      /// Like GetPoint(), except can be used when requesting a point that
      /// lies on a Curve. The PromptPointResult will contain the WCS point 
      /// on the curve, nearest to the selection point in the DCS. It will
      /// optionally set the LASTPOINT system variable to the 'raw' picked
      /// point.
      ///
      /// The Value property of the result <em>is a World coordinate</em>.
      /// </summary>
      /// <remarks>
      /// This method encapsulates the process of obtaining a point on a
      /// curve and computing that point to ensure that the correct view 
      /// parameters are used in the computation.
      /// </remarks>
      /// <param name="setLastPoint">True to set the LASTPOINT system 
      /// variable to the actual UCS point that was selected.</param>
      /// <returns></returns>

      public static PromptPointResult GetPointOn(this Editor editor, Curve curve, PromptPointOptions options, bool setLastPoint = false)
      {
         Assert.IsNotNull(editor, "editor");
         Assert.IsNotNull(options, "ppo");
         Assert.IsNotNull(curve, "curve");
         var result = editor.GetPoint(options);
         if(result.Status == PromptStatus.OK)
         {
            var rawPoint = result.Value;
            result.SetValue(GetClosestPointTo(editor, curve, rawPoint));
            if(setLastPoint)
               AcadApp.SetSystemVariable("LASTPOINT", rawPoint);
         }
         return result;
      }

      /// <summary>
      /// Prompts user for a point and returns the WCS point on the Curve 
      /// whose ObjectId is the given curveId, nearest to a line passing 
      /// through the user-selected point, and parallel to the current 
      /// view direction.
      /// 
      /// This method encapsulates the process of obtaining a point on a
      /// curve and computing that point to ensure that the correct view 
      /// parameters are used in the computation.
      ///
      /// The Value property of the result <em>is a World coordinate</em>.
      /// </summary>

      public static PromptPointResult GetPointOn(this Editor editor, ObjectId curveId, PromptPointOptions options, bool setLastPoint = false)
      {
         ErrorStatus.NullObjectId.Check(!curveId.IsNull);
         ErrorStatus.WrongObjectType.Check(curveId.ObjectClass.IsDerivedFrom(curveClass));
         var result = editor.GetPoint(options);
         if(result.Status == PromptStatus.OK)
         {
            using(Curve curve = (Curve) curveId.Open(OpenMode.ForRead))
            {
               Point3d rawPoint = result.Value;
               result.SetValue(GetClosestPointTo(editor, curve, rawPoint));
               if(setLastPoint)
                  AcadApp.SetSystemVariable("LASTPOINT", rawPoint);
            }
         }
         return result;
      }

      public static PromptPointResult GetPointOn(this Editor editor, ObjectId curveId, string message, bool setLastPoint = false)
      {
         Assert.IsNotNullOrWhiteSpace(message, "message");
         return GetPointOn(editor, curveId, new PromptPointOptions(message), setLastPoint);
      }

      public static PromptPointResult GetPointOn(this Editor editor, Curve curve, string message, bool setLastPoint = false)
      {
         Assert.IsNotNullOrWhiteSpace(message, "message");
         return GetPointOn(editor, curve, new PromptPointOptions(message), setLastPoint);
      }

      static void SetValue(this PromptPointResult ppr, Point3d point)
      {
         ppr_set_value(ppr, point);
      }

      static void SetPickPoint(this PromptEntityResult per, Point3d point)
      {
         per_set_pickPoint(per, point);
      }

      static Action<PromptPointResult, Point3d> ppr_set_value =
         FieldAccess.GetModifier<PromptPointResult, Point3d>("m_value");
      static Action<PromptEntityResult, Point3d> per_set_pickPoint =
         FieldAccess.GetModifier<PromptEntityResult, Point3d>("m_pickPoint");

      static RXClass curveClass = RXObject.GetClass(typeof(Curve));

   }
}

namespace System.Reflection
{
   /// <summary>
   /// Methods for generating delegates that access and 
   /// modify fields without relying on reflection.
   /// </summary>

   public static class FieldAccess
   {
      public static Func<TComponent, TField> GetAccessor<TComponent, TField>(string name, BindingFlags flags = defaultFlags)
      {
         return (Func<TComponent, TField>) GetAccessor(typeof(TComponent), typeof(TField), name, flags);
      }

      public static Action<TComponent, TField> GetModifier<TComponent, TField>(string name, BindingFlags flags = defaultFlags)
      {
         return (Action<TComponent, TField>) GetModifier(typeof(TComponent), typeof(TField), name, flags);
      }

      public static Delegate GetModifier(this Type declaringType, Type fieldType, string name, BindingFlags flags = defaultFlags)
      {
         Assert.IsNotNull(declaringType, "declaringType");
         Assert.IsNotNull(fieldType, "fieldType");
         Assert.IsNotNullOrWhiteSpace(name, "name");
         FieldInfo field = declaringType.GetField(name, flags);
         if(field == null)
            Throw(declaringType, name, "not found");
         var instance = Expression.Parameter(declaringType, "instance");
         var value = Expression.Parameter(fieldType, "value");
         var assign = Expression.Assign(Expression.Field(instance, field), value);
         return Expression.Lambda(assign, instance, value).Compile();
      }

      public static Delegate GetAccessor(this Type declaringType, Type fieldType, string name, BindingFlags flags = defaultFlags)
      {
         Assert.IsNotNull(declaringType, "declaringType");
         Assert.IsNotNull(fieldType, "fieldType");
         Assert.IsNotNullOrWhiteSpace(name, "name");
         FieldInfo field = declaringType.GetField(name, flags);
         if(field == null)
            Throw(declaringType, name, "not found");
         if(!fieldType.IsAssignableFrom(field.FieldType))
            Throw(declaringType, name, "type mismatch");
         ParameterExpression instance = Expression.Parameter(declaringType);
         return Expression.Lambda(Expression.Field(instance, field), new[] { instance }).Compile();
      }

      const BindingFlags defaultFlags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance;

      private static void Throw(Type type, string name, string msg)
      {
         throw new ArgumentException(string.Format("Field {0}.{1} {2}", type.Name, name, msg));
      }
   }
}

namespace System.MyDiagnostics
{
   public static class Assert
   {
      public static void IsNotNull<T>(T obj, string name) where T : class
      {
         if(obj == null)
            throw new ArgumentException(name);
      }

      public static void IsNotNullOrWhiteSpace(this string str, string name)
      {
         if(string.IsNullOrWhiteSpace(str))
            throw new ArgumentException(name);
      }
   }
}

namespace Autodesk.AutoCAD.Runtime
{

   public static class RuntimeExtensions
   {
      public static void Check(this ErrorStatus es, bool condition, string msg = null)
      {
         if(!condition)
         {
            if(msg == null)
               throw new Autodesk.AutoCAD.Runtime.Exception(es);
            else
               throw new Autodesk.AutoCAD.Runtime.Exception(es, msg);
         }
      }
   }
}

 

 

 

 

 

Message 19 of 37
ActivistInvestor
in reply to: _gile

ActivistInvestor
Advisor
Advisor

@_gile wrote:

Activist_Investor a écrit :

Nice @_gile.

I haven't noticed any problems with not disposing the ViewTableRecord returned by GetCurrentView() (perhaps because the AcDbViewTableRecord's destructor is thread-safe), but I'll revise my extension method to do that also.


 

Thanks,

 

I just noticed a warning in th VS Output window:

Forgot to call Dispose? (Autodesk.AutoCAD.DatabaseServices.ViewTableRecord): DisposableWrapper


Yes, it does that for all DBObjects.

0 Likes


@_gile wrote:

Activist_Investor a écrit :

Nice @_gile.

I haven't noticed any problems with not disposing the ViewTableRecord returned by GetCurrentView() (perhaps because the AcDbViewTableRecord's destructor is thread-safe), but I'll revise my extension method to do that also.


 

Thanks,

 

I just noticed a warning in th VS Output window:

Forgot to call Dispose? (Autodesk.AutoCAD.DatabaseServices.ViewTableRecord): DisposableWrapper


Yes, it does that for all DBObjects.

Message 20 of 37
_gile
in reply to: ActivistInvestor

_gile
Mentor
Mentor

@ActivistInvestor

 

You're absolutely right.

 

What about simply using a local function?

 

 

        [CommandMethod("BRLPL")]
        public void BreakLineOrPolyline()
        {
            var doc = AcAp.DocumentManager.MdiActiveDocument;
            var db = doc.Database;
            var ed = doc.Editor;

            var entityOptions = new PromptEntityOptions("\nSelect line or polyline: ");
            entityOptions.SetRejectMessage("Selected object is neither a line nor a polyline.");
            entityOptions.AddAllowedClass(typeof(Polyline), true);
            entityOptions.AddAllowedClass(typeof(Line), true);
            var entityResult = ed.GetEntity(entityOptions);
            if (entityResult.Status != PromptStatus.OK)
                return;

            using (var tr = db.TransactionManager.StartOpenCloseTransaction())
            {
                var curve = (Curve)tr.GetObject(entityResult.ObjectId, OpenMode.ForWrite);
                var ucs = ed.CurrentUserCoordinateSystem;
                
                Point3d getPointOnCurve(Point3d pt)
                {
                    using (var view = ed.GetCurrentView())
                    {
                        return curve.GetClosestPointTo(pt.TransformBy(ucs), view.ViewDirection, false);
                    }
                }

                var pt1 = getPointOnCurve(entityResult.PickedPoint);
                Point3d pt2;
                var pointOptions = new PromptPointOptions("\nSpecify second point or [First point]: ", "First");
                var pointResult = ed.GetPoint(pointOptions);
                if (pointResult.Status == PromptStatus.Keyword)
                {
                    pointOptions.Message = "\nSpecify first point: ";
                    pointOptions.Keywords.Clear();
                    pointResult = ed.GetPoint(pointOptions);
                    if (pointResult.Status != PromptStatus.OK)
                        return;
                    pt1 = getPointOnCurve(pointResult.Value);
                    pointOptions.Message = "\nSpecify second point: ";
                    pointResult = ed.GetPoint(pointOptions);
                    if (pointResult.Status != PromptStatus.OK)
                        return;
                    pt2 = getPointOnCurve(pointResult.Value);
                }
                else if (pointResult.Status == PromptStatus.OK)
                {
                    pt2 = getPointOnCurve(pointResult.Value);
                }
                else return;

                double param1 = curve.GetParameterAtPoint(pt1);
                double param2 = curve.GetParameterAtPoint(pt2);
                var parameters = new DoubleCollection
                    (new[] { param1, param2 }
                    .OrderBy(x => x)
                    .ToArray());
                var curves = curve.GetSplitCurves(parameters);
                var curSpace = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                switch (curves.Count)
                {
                    case 3:
                        curve.HandOverTo(curves[0], true, true);
                        curSpace.AppendEntity((Entity)curves[2]);
                        tr.AddNewlyCreatedDBObject(curves[2], true);
                        curves[1].Dispose();
                        break;
                    case 2:
                        curve.HandOverTo(curves[0], true, true);
                        curSpace.AppendEntity((Entity)curves[1]);
                        tr.AddNewlyCreatedDBObject(curves[1], true);
                        break;
                    default:
                        break;
                }
                curves[0].Dispose();
                tr.Commit();
            }
        }

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

@ActivistInvestor

 

You're absolutely right.

 

What about simply using a local function?

 

 

        [CommandMethod("BRLPL")]
        public void BreakLineOrPolyline()
        {
            var doc = AcAp.DocumentManager.MdiActiveDocument;
            var db = doc.Database;
            var ed = doc.Editor;

            var entityOptions = new PromptEntityOptions("\nSelect line or polyline: ");
            entityOptions.SetRejectMessage("Selected object is neither a line nor a polyline.");
            entityOptions.AddAllowedClass(typeof(Polyline), true);
            entityOptions.AddAllowedClass(typeof(Line), true);
            var entityResult = ed.GetEntity(entityOptions);
            if (entityResult.Status != PromptStatus.OK)
                return;

            using (var tr = db.TransactionManager.StartOpenCloseTransaction())
            {
                var curve = (Curve)tr.GetObject(entityResult.ObjectId, OpenMode.ForWrite);
                var ucs = ed.CurrentUserCoordinateSystem;
                
                Point3d getPointOnCurve(Point3d pt)
                {
                    using (var view = ed.GetCurrentView())
                    {
                        return curve.GetClosestPointTo(pt.TransformBy(ucs), view.ViewDirection, false);
                    }
                }

                var pt1 = getPointOnCurve(entityResult.PickedPoint);
                Point3d pt2;
                var pointOptions = new PromptPointOptions("\nSpecify second point or [First point]: ", "First");
                var pointResult = ed.GetPoint(pointOptions);
                if (pointResult.Status == PromptStatus.Keyword)
                {
                    pointOptions.Message = "\nSpecify first point: ";
                    pointOptions.Keywords.Clear();
                    pointResult = ed.GetPoint(pointOptions);
                    if (pointResult.Status != PromptStatus.OK)
                        return;
                    pt1 = getPointOnCurve(pointResult.Value);
                    pointOptions.Message = "\nSpecify second point: ";
                    pointResult = ed.GetPoint(pointOptions);
                    if (pointResult.Status != PromptStatus.OK)
                        return;
                    pt2 = getPointOnCurve(pointResult.Value);
                }
                else if (pointResult.Status == PromptStatus.OK)
                {
                    pt2 = getPointOnCurve(pointResult.Value);
                }
                else return;

                double param1 = curve.GetParameterAtPoint(pt1);
                double param2 = curve.GetParameterAtPoint(pt2);
                var parameters = new DoubleCollection
                    (new[] { param1, param2 }
                    .OrderBy(x => x)
                    .ToArray());
                var curves = curve.GetSplitCurves(parameters);
                var curSpace = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                switch (curves.Count)
                {
                    case 3:
                        curve.HandOverTo(curves[0], true, true);
                        curSpace.AppendEntity((Entity)curves[2]);
                        tr.AddNewlyCreatedDBObject(curves[2], true);
                        curves[1].Dispose();
                        break;
                    case 2:
                        curve.HandOverTo(curves[0], true, true);
                        curSpace.AppendEntity((Entity)curves[1]);
                        tr.AddNewlyCreatedDBObject(curves[1], true);
                        break;
                    default:
                        break;
                }
                curves[0].Dispose();
                tr.Commit();
            }
        }

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

AutoCAD Inside the Factory


Autodesk Design & Make Report