Author Topic: Breaking curves a distance from intersection points  (Read 4403 times)

0 Members and 1 Guest are viewing this topic.

Jeff H

  • Needs a day job
  • Posts: 6150
Breaking curves a distance from intersection points
« on: January 18, 2013, 12:40:00 PM »

Just starting to test it out and see how it works, and here was first shot that seems work for most cases tested with some exceptions like self-intersecting polylines.


So the idea is breaking a curve where it intersects another curve a set distance on each side of the intersection points(A example would be a wiring schematic where lines representing wires cross each other).


Of course having to do some searching(instead of reading needed documentation) found some info, and was wondering the best approach.


Here is a snippet of code leaving out prompting for distance from intersection to break curve, prompting for curve to break,  prompting for intersecting curve, and logic not to add curves returned from GetSplitCurves to the database  that fall in "break" area.


 
So basically is this the correct way of calculating the points  to pass to GetSplitCurves?
Code - C#: [Select]
  1.  
  2.  
  3.  
  4.                Point3dCollection intersectingPointsCollection = new Point3dCollection();
  5.                curveToBreak.IntersectWith(intersectingCurve, Intersect.OnBothOperands, intersectingPointsCollection, IntPtr.Zero, IntPtr.Zero);
  6.  
  7.  
  8.                if (intersectingPointsCollection.Count > 0)
  9.                {
  10.                    List<Point3d> intersectingPointsList = new List<Point3d>(intersectingPointsCollection.ToArray<Point3d>());
  11.                    intersectingPointsList.OrderBy(p => curveToBreak.GetDistAtPoint(p));
  12.  
  13.  
  14.                    Point3dCollection offsetPoints = new Point3dCollection();
  15.                    List<Point3d> skipStartPoints = new List<Point3d>();
  16.  
  17.  
  18.                    double offsetValue = promptedDoubleResult.Value;
  19.                    foreach (Point3d intersectingPoint in intersectingPointsList)
  20.                    {
  21.  
  22.  
  23.                        double intersectingParameter = curveToBreak.GetParameterAtPoint(intersectingPoint);
  24.                        double distanceToIntersection = curveToBreak.GetDistanceAtParameter(intersectingParameter);
  25.  
  26.  
  27.                        double positiveOffsetParameter = curveToBreak.GetParameterAtDistance(distanceToIntersection + offsetValue);
  28.                        double negativeOffsetParameter = curveToBreak.GetParameterAtDistance(distanceToIntersection - offsetValue);
  29.  
  30.  
  31.                        Point3d positiveOffsetPoint3d = curveToBreak.GetPointAtParameter(positiveOffsetParameter);
  32.                        offsetPoints.Add(positiveOffsetPoint3d);
  33.  
  34.  
  35.                        Point3d negativeOffsetPoint3d = curveToBreak.GetPointAtParameter(negativeOffsetParameter);
  36.                        offsetPoints.Add(negativeOffsetPoint3d);
  37.  
  38.  
  39.                        skipStartPoints.Add(negativeOffsetPoint3d);
  40.                    }
  41.  
  42.                    DBObjectCollection splitCurves = curveToBreak.GetSplitCurves(offsetPoints);
« Last Edit: January 18, 2013, 12:48:22 PM by Jeff H »

owenwengerd

  • Bull Frog
  • Posts: 451
Re: Breaking curves a distance from intersection points
« Reply #1 on: January 18, 2013, 03:04:26 PM »
I'm just making an educated guess, but it would likely be more efficient if you used the version of GetSplitCurves() that expects a DoubleCollection of parameters. Most implementations of GetSplitCurves will first convert the points to parameters anyway, and since you already have the parameters, may as well use them directly and eliminate the extra work. Alternatively, you could eliminate the use of parameters entirely by using Curve.GetPointAtDist() to get the break points.

Jeff H

  • Needs a day job
  • Posts: 6150
Re: Breaking curves a distance from intersection points
« Reply #2 on: January 18, 2013, 05:08:37 PM »

Thanks Owenwengerd!

I'm just making an educated guess, but it would likely be more efficient if you used the version of GetSplitCurves() that expects a DoubleCollection of parameters. Most implementations of GetSplitCurves will first convert the points to parameters anyway, and since you already have the parameters, may as well use them directly and eliminate the extra work.


Was first try before any refactoring but went with points because I was not sure how to test curves returned from GetSplitCurves using parameters if it needed to be added or not.


Alternatively, you could eliminate the use of parameters entirely by using Curve.GetPointAtDist() to get the break points.


You know better than I do but I was mixed up on how I could of done that way.


Will add a before and after pic below of what it does as I might not be explaining it correctly, or possibly post all of the code if that would make more sense.




Before



After



TheMaster

  • Guest
Re: Breaking curves a distance from intersection points
« Reply #3 on: January 19, 2013, 07:44:29 AM »

Thanks Owenwengerd!

I'm just making an educated guess, but it would likely be more efficient if you used the version of GetSplitCurves() that expects a DoubleCollection of parameters. Most implementations of GetSplitCurves will first convert the points to parameters anyway, and since you already have the parameters, may as well use them directly and eliminate the extra work.


Was first try before any refactoring but went with points because I was not sure how to test curves returned from GetSplitCurves using parameters if it needed to be added or not.


Alternatively, you could eliminate the use of parameters entirely by using Curve.GetPointAtDist() to get the break points.


You know better than I do but I was mixed up on how I could of done that way.


Will add a before and after pic below of what it does as I might not be explaining it correctly, or possibly post all of the code if that would make more sense.




Before



After




What I would recommend is to first identify the problem cases, which in this case, would be an intersection that is closer to the end of the curve you will break, than the gap distance you remove. That will complicate the task of figuring out which of the curves from GetSplitCurves() must be discarded. A similar problem occurs when a polyline vertex falls in a gap.

The other problem, is if you use parameters, you will need to deal with polylines that dinstinctly parameterize each segment as a value from n to n+1 where n is the segment index. Because of that, you can't make the assumption that the distance between two points whose parameters p2-p1=n, is constant over the length of the entire curve.  So, I would follow Owen's advice about using points exclusively if you have to deal with polylines.


fixo

  • Guest
Re: Breaking curves a distance from intersection points
« Reply #4 on: January 20, 2013, 04:21:23 PM »
I got interesting moment, third piece of polyline
is not breaks as needs, why?
   
Code: [Select]
     [CommandMethod("gaps")]
        public void TestBreaks()
        {
            Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;
            PromptEntityOptions peo = new PromptEntityOptions("\nSelect the first polyline to be break: ");
            peo.SetRejectMessage("Only a curve !");
            peo.AddAllowedClass(typeof(Curve), false);
            PromptEntityResult per = ed.GetEntity(peo);
            if (per.Status != PromptStatus.OK) return;
            ObjectId id1 = per.ObjectId;
            peo.Message = "\nSelect the second curve: ";
            per = ed.GetEntity(peo);
            if (per.Status != PromptStatus.OK) return;
            ObjectId id2 = per.ObjectId;

            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                doc.TransactionManager.EnableGraphicsFlush(true);
                Curve curve1 = (Curve)tr.GetObject(id1, OpenMode.ForRead);
                Curve curve2 = (Curve)tr.GetObject(id2, OpenMode.ForRead);

                double gap = 10;
                Point3dCollection ptColl = new Point3dCollection();
                curve1.IntersectWith(curve2, Intersect.OnBothOperands, ptColl, 0, 0);

                DBObjectCollection qcurves = new DBObjectCollection();
                qcurves = curve1.GetSplitCurves(ptColl);
                if (qcurves.Count > 0)
                {
                    List<DBObject> objs = new List<DBObject>();
                    foreach (DBObject o in qcurves)
                        objs.Add(o);
                    objs.OrderBy(o => curve1.GetParameterAtPoint((o as Curve).StartPoint));

                    ed.WriteMessage("\n" + ptColl.Count.ToString());
                    Point3dCollection offPts = new Point3dCollection();
                    List<Point3d> gapPts = new List<Point3d>();
                    Entity en;
                    if (ptColl.Count > 0)
                    {
                        ed.WriteMessage("\n" + qcurves.Count.ToString());
                        int i = 0;
                        // int n = 0;
                        BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                        DBObjectCollection newcurves = new DBObjectCollection();
                        for (i = 0; i < objs.Count; i++)
                        {

                            Curve curve = objs[i] as Curve;
                   
                            en = (Entity)curve;

                            en.ColorIndex = 1;

                            btr.AppendEntity(en);
                            tr.AddNewlyCreatedDBObject(en, true);
                            tr.TransactionManager.QueueForGraphicsFlush();
                            newcurves.Add(en);
                        }
                        ed.WriteMessage("\n" + newcurves.Count.ToString());
                        int n = 0;
                        Polyline poly = new Polyline();
                        for (n = 0; n < newcurves.Count; n++)
                        {
                            en = (Entity)newcurves[n];

                            if (en.GetRXClass().DxfName == "LWPOLYLINE")
                            {
                                poly = en as Polyline;
                            }

                            if (poly == null) return;
                            if (!poly.IsWriteEnabled) poly.UpgradeOpen();
                            double leg = poly.GetDistanceAtParameter(poly.EndParam) - poly.GetDistanceAtParameter(poly.StartParam);
                            if (gap >= leg)
                            {
                                ed.WriteMessage("\nLength of curve exceed the gap, exiting...");
                                return;
                            }
                            double spar = poly.StartParam;
                            double epar = poly.EndParam;
                            double sgap = poly.GetParameterAtDistance(gap / 2);
                            Point3d sp = poly.GetPointAtDist(gap / 2).TransformBy(Matrix3d.Identity); ;
                            Point3d ep = poly.GetPointAtDist(poly.GetDistanceAtParameter(poly.EndParam) - poly.GetDistanceAtParameter(poly.StartParam) - gap / 2).TransformBy(Matrix3d.Identity); ;
                            Point3d spt; Point3d ept;
                            if (n == 0)
                            {

                                ept = poly.GetClosestPointTo(ep, false).TransformBy(Matrix3d.Identity);

                                poly.SetPointAt(poly.NumberOfVertices - 1, new Point2d(ept.X, ept.Y));
                            }
                            else if (n == poly.NumberOfVertices - 1)
                            {
                                spt = poly.GetClosestPointTo(sp, false).TransformBy(Matrix3d.Identity);

                                poly.SetPointAt(0, new Point2d(spt.X, spt.Y));
                            }
                            else
                            {
                                spt = poly.GetClosestPointTo(sp, false).TransformBy(Matrix3d.Identity);

                                poly.SetPointAt(0, new Point2d(spt.X, spt.Y));
                               
                               ept = poly.GetClosestPointTo(ep, false).TransformBy(Matrix3d.Identity);
                               
                                poly.SetPointAt(poly.NumberOfVertices - 1, new Point2d(ept.X, ept.Y));
                            }


                            tr.TransactionManager.QueueForGraphicsFlush();

                        }
                        curve1.UpgradeOpen();
                        curve1.Erase();

                    }
                }
                doc.TransactionManager.FlushGraphics();
                tr.Commit();
            }
        }[code]

WILL HATCH

  • Bull Frog
  • Posts: 450
Re: Breaking curves a distance from intersection points
« Reply #5 on: January 21, 2013, 11:34:03 AM »
Found it!  I added a line to see what was happening, and noticed that on the n==3 case that ept was not being transformed.  Also commented out the code erasing the original line, noticed that the last segment was being shortened from both ends and then I realized that we were looking at the poly.NumberOfVertices not the newcurves.Count in the if statement on line 98.  BTW great piece of code here!  Also worth noting, the program breaks if the second curve is a plain line.

Cheers!

Will

Code - C#: [Select]
  1. [CommandMethod("gaps")]
  2.         public void TestBreaks()
  3.         {
  4.             Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
  5.             Database db = doc.Database;
  6.             Editor ed = doc.Editor;
  7.             PromptEntityOptions peo = new PromptEntityOptions("\nSelect the first polyline to be break: ");
  8.             peo.SetRejectMessage("Only a curve !");
  9.             peo.AddAllowedClass(typeof(Curve), false);
  10.             PromptEntityResult per = ed.GetEntity(peo);
  11.             if (per.Status != PromptStatus.OK) return;
  12.             ObjectId id1 = per.ObjectId;
  13.             peo.Message = "\nSelect the second curve: ";
  14.             per = ed.GetEntity(peo);
  15.             if (per.Status != PromptStatus.OK) return;
  16.             ObjectId id2 = per.ObjectId;
  17.  
  18.             using (Transaction tr = db.TransactionManager.StartTransaction())
  19.             {
  20.                 doc.TransactionManager.EnableGraphicsFlush(true);
  21.                 Curve curve1 = (Curve)tr.GetObject(id1, OpenMode.ForRead);
  22.                 Curve curve2 = (Curve)tr.GetObject(id2, OpenMode.ForRead);
  23.  
  24.                 double gap = 10;
  25.                 Point3dCollection ptColl = new Point3dCollection();
  26.                 curve1.IntersectWith(curve2, Intersect.OnBothOperands, ptColl, 0, 0);
  27.  
  28.                 DBObjectCollection qcurves = new DBObjectCollection();
  29.                 qcurves = curve1.GetSplitCurves(ptColl);
  30.                 if (qcurves.Count > 0)
  31.                 {
  32.                     List<DBObject> objs = new List<DBObject>();
  33.                     foreach (DBObject o in qcurves)
  34.                         objs.Add(o);
  35.                     objs.OrderBy(o => curve1.GetParameterAtPoint((o as Curve).StartPoint));
  36.  
  37.                     ed.WriteMessage("\n" + ptColl.Count.ToString());
  38.                     Point3dCollection offPts = new Point3dCollection();
  39.                     List<Point3d> gapPts = new List<Point3d>();
  40.                     Entity en;
  41.                     if (ptColl.Count > 0)
  42.                     {
  43.                         ed.WriteMessage("\n" + qcurves.Count.ToString());
  44.                         int i = 0;
  45.                         // int n = 0;
  46.                         BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
  47.                         DBObjectCollection newcurves = new DBObjectCollection();
  48.                         for (i = 0; i < objs.Count; i++)
  49.                         {
  50.  
  51.                             Curve curve = objs[i] as Curve;
  52.  
  53.                             en = (Entity)curve;
  54.  
  55.                             en.ColorIndex = 1;
  56.  
  57.                             btr.AppendEntity(en);
  58.                             tr.AddNewlyCreatedDBObject(en, true);
  59.                             tr.TransactionManager.QueueForGraphicsFlush();
  60.                             newcurves.Add(en);
  61.                         }
  62.                         ed.WriteMessage("\n" + newcurves.Count.ToString());
  63.                         int n = 0;
  64.                         Polyline poly = new Polyline();
  65.                         for (n = 0; n < newcurves.Count; n++)
  66.                         {
  67.                             en = (Entity)newcurves[n];
  68.  
  69.                             if (en.GetRXClass().DxfName == "LWPOLYLINE")
  70.                             {
  71.                                 poly = en as Polyline;
  72.                             }
  73.  
  74.                             if (poly == null) return;
  75.                             if (!poly.IsWriteEnabled) poly.UpgradeOpen();
  76.                             double leg = poly.GetDistanceAtParameter(poly.EndParam) - poly.GetDistanceAtParameter(poly.StartParam);
  77.                             if (gap >= leg)
  78.                             {
  79.                                 ed.WriteMessage("\nLength of curve exceed the gap, exiting...");
  80.                                 return;
  81.                             }
  82.                             double spar = poly.StartParam;
  83.                             double epar = poly.EndParam;
  84.                             double sgap = poly.GetParameterAtDistance(gap / 2);
  85.                             Point3d sp = poly.GetPointAtDist(gap / 2).TransformBy(Matrix3d.Identity);
  86.                             Point3d spprime = poly.GetPointAtDist(gap / 2);
  87.                             ed.WriteMessage("\nPoint transformed by Identity:     {0}\nPoint NOT transformed by Identity: {1}", sp, spprime);
  88.                             Point3d ep = poly.GetPointAtDist(poly.GetDistanceAtParameter(poly.EndParam) - poly.GetDistanceAtParameter(poly.StartParam) - gap / 2).TransformBy(Matrix3d.Identity);
  89.                             Point3d spt = new Point3d();
  90.                             Point3d ept = new Point3d();
  91.                             if (n == 0)
  92.                             {
  93.  
  94.                                 ept = poly.GetClosestPointTo(ep, false).TransformBy(Matrix3d.Identity);
  95.  
  96.                                 poly.SetPointAt(poly.NumberOfVertices - 1, new Point2d(ept.X, ept.Y));
  97.                             }
  98.                             else if (n == newcurves.Count - 1)//<-------HERE!
  99.                             {
  100.                                 spt = poly.GetClosestPointTo(sp, false).TransformBy(Matrix3d.Identity);
  101.  
  102.                                 poly.SetPointAt(0, new Point2d(spt.X, spt.Y));
  103.                             }
  104.                             else
  105.                             {
  106.                                 spt = poly.GetClosestPointTo(sp, false).TransformBy(Matrix3d.Identity);
  107.  
  108.                                 poly.SetPointAt(0, new Point2d(spt.X, spt.Y));
  109.  
  110.                                 ept = poly.GetClosestPointTo(ep, false).TransformBy(Matrix3d.Identity);
  111.  
  112.                                 poly.SetPointAt(poly.NumberOfVertices - 1, new Point2d(ept.X, ept.Y));
  113.                             }
  114.  
  115.  
  116.                             tr.TransactionManager.QueueForGraphicsFlush();
  117.                             ed.WriteMessage("Polyline n: {0}\n\tpoly.NumberOfVerticies: {5}\n\tsp:  {1}\n\tspt: {2}\n\tep:  {3}\n\tept: {4}", n, sp, spt, ep, ept,poly.NumberOfVertices);
  118.  
  119.                         }
  120.                         curve1.UpgradeOpen();
  121.                         curve1.Erase();
  122.  
  123.                     }
  124.                 }
  125.                 doc.TransactionManager.FlushGraphics();
  126.                 tr.Commit();
  127.             }
  128.         }
  129.  

WILL HATCH

  • Bull Frog
  • Posts: 450
Re: Breaking curves a distance from intersection points
« Reply #6 on: January 21, 2013, 11:48:52 AM »
Sorry, forgot to mention in my first post that the operation Point3d.TransformBy(Matrix3d.Identity) is redundant.  I couldn't remember for sure so I added lines 86 and 87 to the code to test.

The identity matrix is the matrix equivalent of 1.  Given any matrix A and identity matrix I:
A x I = A
I x A = A

Important to note that if A is not a square matrix the identity matrix used in both cases is not of the same dimension.

fixo

  • Guest
Re: Breaking curves a distance from intersection points
« Reply #7 on: January 21, 2013, 11:57:13 AM »
Thanks so much Will
This code is working good enough on my end
as well as in case if the second curve is line, arc, pline or spline
Kind regards,
Oleg

kaefer

  • Guest
Re: Breaking curves a distance from intersection points
« Reply #8 on: January 21, 2013, 06:52:41 PM »
What I would recommend is to first identify the problem cases, which in this case, would be an intersection that is closer to the end of the curve you will break, than the gap distance you remove. That will complicate the task of figuring out which of the curves from GetSplitCurves() must be discarded. A similar problem occurs when a polyline vertex falls in a gap.

Alternatively, you could preprocess the points before feeding them to GetSplitCurves(). Get gap incidence points by intersecting the target curve with circles centered on the intersection points with the other curve, and then discard them if they are contained in any other circle.  That is, if their distance from any other intersection is less than half a gap's width.

The other problem, is if you use parameters, you will need to deal with polylines that dinstinctly parameterize each segment as a value from n to n+1 where n is the segment index. Because of that, you can't make the assumption that the distance between two points whose parameters p2-p1=n, is constant over the length of the entire curve.  So, I would follow Owen's advice about using points exclusively if you have to deal with polylines.

That could be taken care of by intersecting with another Entity, or even by deploying a CurveCurveIntersector, since no graphical representation is required. But it would be difficult to avoid curve parameters altogether: the resulting points have to be sorted by Parameter to avoid overlapping segments generated by GetSplitCurves(). And there are still the pathological cases of two (or more) circles meeting at half a gap' width along the target curve, which needs elimination of duplicate points occuring in multiples of two.
« Last Edit: January 21, 2013, 07:04:12 PM by kaefer »

Jeff H

  • Needs a day job
  • Posts: 6150
Re: Breaking curves a distance from intersection points
« Reply #9 on: January 22, 2013, 10:28:50 PM »
What about using IntersectWith with curves returned from GetOffsetCurves?

fixo

  • Guest
Re: Breaking curves a distance from intersection points
« Reply #10 on: January 23, 2013, 04:09:46 AM »
With the reflected polylines you can receive unpredictable result,
I would try to avoid their use, just a thought

TheMaster

  • Guest
Re: Breaking curves a distance from intersection points
« Reply #11 on: January 23, 2013, 07:45:13 AM »
What about using IntersectWith with curves returned from GetOffsetCurves?

That will give you a very different result. Consider curves that intersect at a sharp angle. 

When using the intersecting circle method, the distance from the intersection point to the break points would be constant (in the normal case), regardless of the angle of the intersecting curves. 

Which is more desireable would actually depend on particulars of your use.


Jeff H

  • Needs a day job
  • Posts: 6150
Re: Breaking curves a distance from intersection points
« Reply #12 on: January 23, 2013, 09:14:33 AM »
Thanks guys