Author Topic: .NET GEOMETRY Routines  (Read 63563 times)

0 Members and 2 Guests are viewing this topic.

gile

  • Gator
  • Posts: 2505
  • Marseille, France
Re: .NET GEOMETRY Routines
« Reply #30 on: August 15, 2012, 05:52:44 AM »
New release of the GeometryExtensions Library (1.4).
See reply #1.
Speaking English as a French Frog

lamarn

  • Swamp Rat
  • Posts: 636
Re: .NET GEOMETRY Routines
« Reply #31 on: August 15, 2012, 10:23:58 AM »
Hi Gile,
I am intrested in this extension, however i am not a C programmer.
Do you have a workaround to test it or do you have a test file or programm?
Design is something you should do with both hands. My 2d hand , my 3d hand ..

gile

  • Gator
  • Posts: 2505
  • Marseille, France
Re: .NET GEOMETRY Routines
« Reply #32 on: August 15, 2012, 01:05:21 PM »
Hi,

You can reference the DLL in a VB project to get all extensions methods and classes available in this project.
« Last Edit: August 15, 2012, 01:20:43 PM by gile »
Speaking English as a French Frog

Jeff H

  • Needs a day job
  • Posts: 6144
Re: .NET GEOMETRY Routines
« Reply #33 on: September 27, 2012, 01:25:34 AM »
Gile I can not believe I have not thanked you yet for extension libraries.
So Thanks.
 
Good stuff.

gile

  • Gator
  • Posts: 2505
  • Marseille, France
Re: .NET GEOMETRY Routines
« Reply #34 on: September 27, 2012, 05:03:11 AM »
You're very welcome Jeff.
Speaking English as a French Frog

gile

  • Gator
  • Posts: 2505
  • Marseille, France
Re: .NET GEOMETRY Routines
« Reply #35 on: September 14, 2013, 12:58:46 PM »
Related to this thread, a little extension for GeometryExtensions library: two methods which extents the CircularArc3d type to find tangents between to a point or another instance of CircularArc3d.

Code - C#: [Select]
  1. using System;
  2. using Autodesk.AutoCAD.Geometry;
  3.  
  4. namespace GeometryExtensions
  5. {
  6.     /// <summary>
  7.     /// Tangent type enum
  8.     /// </summary>
  9.     [Flags]
  10.     public enum TangentType { Inner = 1, Outer = 2 }
  11.  
  12.     /// <summary>
  13.     /// Provides extension methods for the CircularArc3d class.
  14.     /// </summary>
  15.     public static class CircularArc3dExtensions
  16.     {
  17.         /// <summary>
  18.         /// Returns the tangents between the active CircularArc3d instance complete circle and another one.
  19.         /// </summary>
  20.         /// <remarks>
  21.         /// Tangents start points are on the object to which this method applies, end points on the one passed as argument.
  22.         /// Tangents are always returned in the same order: outer tangents before inner tangents, and for both,
  23.         /// the tangent on the left side of the line from this circular arc center to the other one before the one on the right side.
  24.         /// </remarks>
  25.         /// <param name="arc">The object to which this method applies.</param>
  26.         /// <param name="other">The CircularArc3d to which searched for tangents.</param>
  27.         /// <param name="flags">An enum value specifying which type of tangent is returned.</param>
  28.         /// <returns>An array of LineSegment3d representing the tangents (maybe 2 or 4) or null if there is none.</returns>
  29.         /// <exception cref="Autodesk.AutoCAD.Runtime.exception">eNonCoplanarGeometry is thrown if the objects do not lies on the same plane.</exception>
  30.         public static LineSegment3d[] GetTangentsTo(this CircularArc3d arc, CircularArc3d other, TangentType flags)
  31.         {
  32.             // check if circles lies on the same plane
  33.             Vector3d normal = arc.Normal;
  34.             double elev1 = arc.Center.TransformBy(Matrix3d.WorldToPlane(normal)).Z;
  35.             double elev2 = other.Center.TransformBy(Matrix3d.WorldToPlane(normal)).Z;
  36.             if (!(normal.IsParallelTo(other.Normal) &&
  37.                 Math.Abs(elev1 - elev2) < Tolerance.Global.EqualPoint))
  38.                 throw new Autodesk.AutoCAD.Runtime.Exception(
  39.                     Autodesk.AutoCAD.Runtime.ErrorStatus.NonCoplanarGeometry);
  40.  
  41.             // check if a circle is inside the other
  42.             double dist = arc.Center.DistanceTo(other.Center);
  43.             if (dist - Math.Abs(arc.Radius - other.Radius) <= Tolerance.Global.EqualPoint)
  44.                 return null;
  45.  
  46.             // check if circles overlap
  47.             bool overlap = arc.Radius + other.Radius >= dist;
  48.             if (overlap && flags == TangentType.Inner)
  49.                 return null;
  50.  
  51.             CircularArc3d tmp1, tmp2;
  52.             Point3d[] inters;
  53.             Vector3d vec1, vec2, vec = other.Center - arc.Center;
  54.             int i, j;
  55.             LineSegment3d[] result = new LineSegment3d[(int)flags == 3 && !overlap ? 4 : 2];
  56.  
  57.             // outer tangents
  58.             if (flags.HasFlag(TangentType.Outer))
  59.             {
  60.                 if (arc.Radius == other.Radius)
  61.                 {
  62.                     Line3d perp = new Line3d(arc.Center, vec.CrossProduct(normal));
  63.                     inters = arc.IntersectWith(perp);
  64.                     vec1 = (inters[0] - arc.Center).GetNormal();
  65.                     vec2 = (inters[1] - arc.Center).GetNormal();
  66.                     i = vec.GetAngleTo(vec1, normal) < vec.GetAngleTo(vec2, normal) ? 0 : 1;
  67.                     j = i ^ 1;
  68.                     result[i] = new LineSegment3d(inters[0], inters[0] + vec);
  69.                     result[j] = new LineSegment3d(inters[1], inters[1] + vec);
  70.                 }
  71.                 else
  72.                 {
  73.                     Point3d center = arc.Radius < other.Radius ? other.Center : arc.Center;
  74.                     tmp1 = new CircularArc3d(center, normal, Math.Abs(arc.Radius - other.Radius));
  75.                     tmp2 = new CircularArc3d(arc.Center + vec / 2.0, normal, dist / 2.0);
  76.                     inters = tmp1.IntersectWith(tmp2);
  77.                     vec1 = (inters[0] - center).GetNormal();
  78.                     vec2 = (inters[1] - center).GetNormal();
  79.                     i = vec.GetAngleTo(vec1, normal) < vec.GetAngleTo(vec2, normal) ? 0 : 1;
  80.                     j = i ^ 1;
  81.                     result[i] = new LineSegment3d(arc.Center + vec1 * arc.Radius, other.Center + vec1 * other.Radius);
  82.                     result[j] = new LineSegment3d(arc.Center + vec2 * arc.Radius, other.Center + vec2 * other.Radius);
  83.                 }
  84.             }
  85.  
  86.             // inner tangents
  87.             if (flags.HasFlag(TangentType.Inner) && !overlap)
  88.             {
  89.                 double ratio = (arc.Radius / (arc.Radius + other.Radius)) / 2.0;
  90.                 tmp1 = new CircularArc3d(arc.Center + vec * ratio, normal, dist * ratio);
  91.                 inters = arc.IntersectWith(tmp1);
  92.                 vec1 = (inters[0] - arc.Center).GetNormal();
  93.                 vec2 = (inters[1] - arc.Center).GetNormal();
  94.                 i = vec.GetAngleTo(vec1, normal) < vec.GetAngleTo(vec2, normal) ? 2 : 3;
  95.                 j = i == 2 ? 3 : 2;
  96.                 result[i] = new LineSegment3d(arc.Center + vec1 * arc.Radius, other.Center + vec1.Negate() * other.Radius);
  97.                 result[j] = new LineSegment3d(arc.Center + vec2 * arc.Radius, other.Center + vec2.Negate() * other.Radius);
  98.             }
  99.             return result;
  100.         }
  101.  
  102.         /// <summary>
  103.         /// Returns the tangents between the active CircularArc3d instance complete circle and a point.
  104.         /// </summary>
  105.         /// <remarks>
  106.         /// Tangents start points are on the object to which this method applies, end points on the point passed as argument.
  107.         /// Tangents are always returned in the same order: the tangent on the left side of the line from the circular arc center
  108.         /// to the point before the one on the right side.
  109.         /// </remarks>
  110.         /// <param name="arc">The object to which this method applies.</param>
  111.         /// <param name="pt">The Point3d to which tangents are searched</param>
  112.         /// <returns>An array of LineSegement3d representing the tangents (2) or null if there is none.</returns>
  113.         /// <exception cref="Autodesk.AutoCAD.Runtime.exception">eNonCoplanarGeometry is thrown if the objects do not lies on the same plane.</exception>
  114.         public static LineSegment3d[] GetTangentsTo(this CircularArc3d arc, Point3d pt)
  115.         {
  116.             // check if circle and point lies on the plane
  117.             Vector3d normal = arc.Normal;
  118.             double elev1 = arc.Center.TransformBy(Matrix3d.WorldToPlane(normal)).Z;
  119.             double elev2 = pt.TransformBy(Matrix3d.WorldToPlane(normal)).Z;
  120.             if (Math.Abs(elev1 - elev2) < Tolerance.Global.EqualPoint)
  121.                 throw new Autodesk.AutoCAD.Runtime.Exception(
  122.                     Autodesk.AutoCAD.Runtime.ErrorStatus.NonCoplanarGeometry);
  123.  
  124.             // check if the point is inside the circle
  125.             Point3d center = arc.Center;
  126.             if (pt.DistanceTo(center) <= arc.Radius)
  127.                 return null;
  128.  
  129.             Vector3d vec = pt.GetVectorTo(center) / 2.0;
  130.             CircularArc3d tmp = new CircularArc3d(pt + vec, arc.Normal, vec.Length);
  131.             Point3d[] inters = arc.IntersectWith(tmp);
  132.             LineSegment3d[] result = new LineSegment3d[2];
  133.             int i = vec.GetAngleTo(inters[0] - center, normal) < vec.GetAngleTo(inters[1] - center, normal) ? 0 : 1;
  134.             int j = i ^ 1;
  135.             result[i] = new LineSegment3d(inters[0], pt);
  136.             result[j] = new LineSegment3d(inters[1], pt);
  137.             return result;
  138.         }
  139.     }
  140. }
  141.  

A (maybe usefull) command example which draws a closed polyline along the outer tangents and the trimmed selected circles

Code - C#: [Select]
  1.         [CommandMethod("JoinCircles", CommandFlags.Modal)]
  2.         public void JoinCircles()
  3.         {
  4.             Document doc = Application.DocumentManager.MdiActiveDocument;
  5.             Database db = doc.Database;
  6.             Editor ed = doc.Editor;
  7.  
  8.             PromptEntityOptions peo = new PromptEntityOptions("\nSelect a circle: ");
  9.             peo.SetRejectMessage("Only a circle.");
  10.             peo.AddAllowedClass(typeof(Circle), true);
  11.             PromptEntityResult per = ed.GetEntity(peo);
  12.             if (per.Status != PromptStatus.OK)
  13.                 return;
  14.             ObjectId id1 = per.ObjectId;
  15.  
  16.             peo.Message = "\nSelect another circle: ";
  17.             ObjectId id2;
  18.             while (true)
  19.             {
  20.                 per = ed.GetEntity(peo);
  21.                 if (per.Status != PromptStatus.OK)
  22.                     return;
  23.                 id2 = per.ObjectId;
  24.                 if (id1 == id2)
  25.                     ed.WriteMessage("\nThe second circle is the same as the first one.");
  26.                 else break;
  27.             }
  28.  
  29.             try
  30.             {
  31.                 using (Transaction tr = db.TransactionManager.StartTransaction())
  32.                 {
  33.                     Circle c1 = (Circle)tr.GetObject(id1, OpenMode.ForRead);
  34.                     Circle c2 = (Circle)tr.GetObject(id2, OpenMode.ForRead);
  35.                     CircularArc3d ca1 = new CircularArc3d(c1.Center, c1.Normal, c1.Radius);
  36.                     CircularArc3d ca2 = new CircularArc3d(c2.Center, c2.Normal, c2.Radius);
  37.                     LineSegment3d[] lines = ca1.GetTangentsTo(ca2, TangentType.Outer);
  38.                     if (lines != null)
  39.                     {
  40.                         BlockTableRecord btr =
  41.                             (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
  42.                         Vector3d vec = c1.Center.GetVectorTo(c2.Center);
  43.                         Plane plane = new Plane(Point3d.Origin, c1.Normal);
  44.                         double a1 = vec.GetAngleTo(ca1.Center.GetVectorTo(lines[1].StartPoint), ca1.Normal) -
  45.                             vec.GetAngleTo(ca1.Center.GetVectorTo(lines[0].StartPoint), ca1.Normal);
  46.                         double a2 = vec.Negate().GetAngleTo(ca2.Center.GetVectorTo(lines[0].EndPoint), ca1.Normal) -
  47.                             vec.Negate().GetAngleTo(ca2.Center.GetVectorTo(lines[1].EndPoint), ca1.Normal);
  48.                         Polyline pline = new Polyline(4);
  49.                         pline.AddVertexAt(0, lines[0].StartPoint.Convert2d(plane), Math.Tan(a1 / 4.0), 0.0, 0.0);
  50.                         pline.AddVertexAt(1, lines[1].StartPoint.Convert2d(plane), 0.0, 0.0, 0.0);
  51.                         pline.AddVertexAt(2, lines[1].EndPoint.Convert2d(plane), Math.Tan(a2 / 4.0), 0.0, 0.0);
  52.                         pline.AddVertexAt(3, lines[0].EndPoint.Convert2d(plane), 0.0, 0.0, 0.0);
  53.                         pline.Closed = true;
  54.                         pline.Normal = c1.Normal;
  55.                         pline.Elevation = c1.Center.TransformBy(Matrix3d.WorldToPlane(c1.Normal)).Z;
  56.                         btr.AppendEntity(pline);
  57.                         tr.AddNewlyCreatedDBObject(pline, true);
  58.                         c1.UpgradeOpen();
  59.                         c2.UpgradeOpen();
  60.                         c1.Erase();
  61.                         c2.Erase();
  62.                     }
  63.                     tr.Commit();
  64.                 }
  65.             }
  66.             catch (System.Exception exn)
  67.             {
  68.                 ed.WriteMessage("\nError: " + exn.Message);
  69.             }
  70.         }
Speaking English as a French Frog

gile

  • Gator
  • Posts: 2505
  • Marseille, France
Re: .NET GEOMETRY Routines
« Reply #36 on: September 15, 2013, 11:36:01 AM »
As i encountered some issues with the CircularArc3d.IntersectWith() method in some randomly 3d rotated planes, I decided to try the CircularArc2d route it seems to work fine.

The two methods shown upper now call equivalent extension methods for the CircularArc2d type after converting the CircularArc3d instance into CircularArc2d ones.
The Point2d.Convert3d() extension method is extracted from the GeometryExtensions library.

Code - C#: [Select]
  1. using System;
  2. using Autodesk.AutoCAD.Geometry;
  3.  
  4. namespace GeometryExtensions
  5. {
  6.     /// <summary>
  7.     /// Tangent type enum
  8.     /// </summary>
  9.     [Flags]
  10.     public enum TangentType { Inner = 1, Outer = 2 }
  11.  
  12.     /// <summary>
  13.     /// Provides extension methods for the Point2d structure.
  14.     /// </summary>
  15.     public static class Point2dExtensions
  16.     {        
  17.         /// <summary>
  18.         /// Converts a 2d point into a 3d point according to the plane defined by
  19.         /// the specified normal vector and elevation.
  20.         /// </summary>
  21.         /// <param name="pt">The instance to which the method applies.</param>
  22.         /// <param name="normal">The normal vector of the plane which the point lies on.</param>
  23.         /// <param name="elevation">The elevation of the plane which the point lies on.</param>
  24.         /// <returns>The corresponding 3d point</returns>
  25.         public static Point3d Convert3d(this Point2d pt, Vector3d normal, double elevation)
  26.         {
  27.             return new Point3d(pt.X, pt.Y, elevation).TransformBy(Matrix3d.PlaneToWorld(normal));
  28.         }
  29.     }
  30.  
  31.     /// <summary>
  32.     /// Provides extension methods for the CircularArc3d class.
  33.     /// </summary>
  34.     public static class CircularArc3dExtensions
  35.     {
  36.         /// <summary>
  37.         /// Returns the tangents between the active CircularArc3d instance complete circle and a point.
  38.         /// </summary>
  39.         /// <remarks>
  40.         /// Tangents start points are on the object to which this method applies, end points on the point passed as argument.
  41.         /// Tangents are always returned in the same order: the tangent on the left side of the line from the circular arc center
  42.         /// to the point before the one on the right side.
  43.         /// </remarks>
  44.         /// <param name="arc">The object to which this method applies.</param>
  45.         /// <param name="pt">The Point3d to which tangents are searched</param>
  46.         /// <returns>An array of LineSegement3d representing the tangents (2) or null if there is none.</returns>
  47.         /// <exception cref="Autodesk.AutoCAD.Runtime.exception">eNonCoplanarGeometry is thrown if the objects do not lies on the same plane.</exception>
  48.         public static LineSegment3d[] GetTangentsTo(this CircularArc3d arc, Point3d pt)
  49.         {
  50.             // check if arc and point lies on the plane
  51.             Vector3d normal = arc.Normal;
  52.             Matrix3d WCS2OCS = Matrix3d.WorldToPlane(normal);
  53.             double elevation = arc.Center.TransformBy(WCS2OCS).Z;
  54.             if (Math.Abs(elevation - pt.TransformBy(WCS2OCS).Z) < Tolerance.Global.EqualPoint)
  55.                 throw new Autodesk.AutoCAD.Runtime.Exception(
  56.                     Autodesk.AutoCAD.Runtime.ErrorStatus.NonCoplanarGeometry);
  57.  
  58.             Plane plane = new Plane(Point3d.Origin, normal);
  59.             Matrix3d OCS2WCS = Matrix3d.PlaneToWorld(plane);
  60.             CircularArc2d ca2d = new CircularArc2d(arc.Center.Convert2d(plane), arc.Radius);
  61.             LineSegment2d[] lines2d = ca2d.GetTangentsTo(pt.Convert2d(plane));
  62.  
  63.             if (lines2d == null)
  64.                 return null;
  65.  
  66.             LineSegment3d[] result = new LineSegment3d[lines2d.Length];
  67.             for (int i = 0; i < lines2d.Length; i++)
  68.             {
  69.                 LineSegment2d ls2d = lines2d[i];
  70.                 //Point3d p1 = new Point3d(ls2d.StartPoint.X, ls2d.StartPoint.Y, elevation);
  71.                 //Point3d p2 = new Point3d(ls2d.EndPoint.X, ls2d.EndPoint.Y, elevation);
  72.                 //result[i] = new LineSegment3d(p1.TransformBy(OCS2WCS), p2.TransformBy(OCS2WCS));
  73.                 result[i] = new LineSegment3d(ls2d.StartPoint.Convert3d(normal, elevation), ls2d.EndPoint.Convert3d(normal, elevation));
  74.             }
  75.             return result;
  76.         }
  77.  
  78.         /// <summary>
  79.         /// Returns the tangents between the active CircularArc3d instance complete circle and another one.
  80.         /// </summary>
  81.         /// <remarks>
  82.         /// Tangents start points are on the object to which this method applies, end points on the one passed as argument.
  83.         /// Tangents are always returned in the same order: outer tangents before inner tangents, and for both,
  84.         /// the tangent on the left side of the line from this circular arc center to the other one before the one on the right side.
  85.         /// </remarks>
  86.         /// <param name="arc">The object to which this method applies.</param>
  87.         /// <param name="other">The CircularArc3d to which searched for tangents.</param>
  88.         /// <param name="flags">An enum value specifying which type of tangent is returned.</param>
  89.         /// <returns>An array of LineSegment3d representing the tangents (maybe 2 or 4) or null if there is none.</returns>
  90.         /// <exception cref="Autodesk.AutoCAD.Runtime.exception">eNonCoplanarGeometry is thrown if the objects do not lies on the same plane.</exception>
  91.         public static LineSegment3d[] GetTangentsTo(this CircularArc3d arc, CircularArc3d other, TangentType flags)
  92.         {
  93.             // check if circles lies on the same plane
  94.             Vector3d normal = arc.Normal;
  95.             Matrix3d WCS2OCS = Matrix3d.WorldToPlane(normal);
  96.             double elevation = arc.Center.TransformBy(WCS2OCS).Z;
  97.             if (!(normal.IsParallelTo(other.Normal) &&
  98.                 Math.Abs(elevation - other.Center.TransformBy(WCS2OCS).Z) < Tolerance.Global.EqualPoint))
  99.                 throw new Autodesk.AutoCAD.Runtime.Exception(
  100.                     Autodesk.AutoCAD.Runtime.ErrorStatus.NonCoplanarGeometry);
  101.  
  102.             Plane plane = new Plane(Point3d.Origin, normal);
  103.             Matrix3d OCS2WCS = Matrix3d.PlaneToWorld(plane);
  104.             CircularArc2d ca2d1 = new CircularArc2d(arc.Center.Convert2d(plane), arc.Radius);
  105.             CircularArc2d ca2d2 = new CircularArc2d(other.Center.Convert2d(plane), other.Radius);
  106.             LineSegment2d[] lines2d = ca2d1.GetTangentsTo(ca2d2, flags);
  107.  
  108.             if (lines2d == null)
  109.                 return null;
  110.  
  111.             LineSegment3d[] result = new LineSegment3d[lines2d.Length];
  112.             for (int i = 0; i < lines2d.Length; i++)
  113.             {
  114.                 LineSegment2d ls2d = lines2d[i];
  115.                 //Point3d p1 = new Point3d(ls2d.StartPoint.X, ls2d.StartPoint.Y, elevation);
  116.                 //Point3d p2 = new Point3d(ls2d.EndPoint.X, ls2d.EndPoint.Y, elevation);
  117.                 //result[i] = new LineSegment3d(p1.TransformBy(OCS2WCS), p2.TransformBy(OCS2WCS));
  118.                 result[i] = new LineSegment3d(ls2d.StartPoint.Convert3d(normal, elevation), ls2d.EndPoint.Convert3d(normal, elevation));
  119.             }
  120.             return result;
  121.         }
  122.     }
  123.  
  124.     /// <summary>
  125.     /// Provides extension methods for the CircularArc2d class.
  126.     /// </summary>
  127.     public static class CircularArc2dExtensions
  128.     {
  129.         /// <summary>
  130.         /// Returns the tangents between the active CircularArc2d instance complete circle and a point.
  131.         /// </summary>
  132.         /// <remarks>
  133.         /// Tangents start points are on the object to which this method applies, end points on the point passed as argument.
  134.         /// Tangents are always returned in the same order: the tangent on the left side of the line from the circular arc center
  135.         /// to the point before the one on the right side.
  136.         /// </remarks>
  137.         /// <param name="arc">The object to which this method applies.</param>
  138.         /// <param name="pt">The Point2d to which tangents are searched</param>
  139.         /// <returns>An array of LineSegement2d representing the tangents (2) or null if there is none.</returns>
  140.         public static LineSegment2d[] GetTangentsTo(this CircularArc2d arc, Point2d pt)
  141.         {
  142.             // check if the point is inside the circle
  143.             Point2d center = arc.Center;
  144.             if (pt.GetDistanceTo(center) <= arc.Radius)
  145.                 return null;
  146.  
  147.             Vector2d vec = center.GetVectorTo(pt) / 2.0;
  148.             CircularArc2d tmp = new CircularArc2d(center + vec, vec.Length);
  149.             Point2d[] inters = arc.IntersectWith(tmp);
  150.             if (inters == null)
  151.                 return null;
  152.             LineSegment2d[] result = new LineSegment2d[2];
  153.             Vector2d v1 = inters[0] - center;
  154.             Vector2d v2 = inters[1] - center;
  155.             int i = vec.X * v1.Y - vec.Y - v1.X > 0 ? 0 : 1;
  156.             int j = i ^ 1;
  157.             result[i] = new LineSegment2d(inters[0], pt);
  158.             result[j] = new LineSegment2d(inters[1], pt);
  159.             return result;
  160.         }
  161.  
  162.         /// <summary>
  163.         /// Returns the tangents between the active CircularArc2d instance complete circle and another one.
  164.         /// </summary>
  165.         /// <remarks>
  166.         /// Tangents start points are on the object to which this method applies, end points on the one passed as argument.
  167.         /// Tangents are always returned in the same order: outer tangents before inner tangents, and for both,
  168.         /// the tangent on the left side of the line from this circular arc center to the other one before the one on the right side.
  169.         /// </remarks>
  170.         /// <param name="arc">The object to which this method applies.</param>
  171.         /// <param name="other">The CircularArc2d to which searched for tangents.</param>
  172.         /// <param name="flags">An enum value specifying which type of tangent is returned.</param>
  173.         /// <returns>An array of LineSegment2d representing the tangents (maybe 2 or 4) or null if there is none.</returns>
  174.         public static LineSegment2d[] GetTangentsTo(this CircularArc2d arc, CircularArc2d other, TangentType flags)
  175.         {
  176.             // check if a circle is inside the other
  177.             double dist = arc.Center.GetDistanceTo(other.Center);
  178.             if (dist - Math.Abs(arc.Radius - other.Radius) <= Tolerance.Global.EqualPoint)
  179.                 return null;
  180.  
  181.             // check if circles overlap
  182.             bool overlap = arc.Radius + other.Radius >= dist;
  183.             if (overlap && flags == TangentType.Inner)
  184.                 return null;
  185.  
  186.             CircularArc2d tmp1, tmp2;
  187.             Point2d[] inters;
  188.             Vector2d vec1, vec2, vec = other.Center - arc.Center;
  189.             int i, j;
  190.             LineSegment2d[] result = new LineSegment2d[(int)flags == 3 && !overlap ? 4 : 2];
  191.  
  192.             // outer tangents
  193.             if (flags.HasFlag(TangentType.Outer))
  194.             {
  195.                 if (arc.Radius == other.Radius)
  196.                 {
  197.                     Line2d perp = new Line2d(arc.Center, vec.GetPerpendicularVector());
  198.                     inters = arc.IntersectWith(perp);
  199.                     if (inters == null)
  200.                         return null;
  201.                     vec1 = (inters[0] - arc.Center).GetNormal();
  202.                     vec2 = (inters[1] - arc.Center).GetNormal();
  203.                     i = vec.X * vec1.Y - vec.Y - vec1.X > 0 ? 0 : 1;
  204.                     j = i ^ 1;
  205.                     result[i] = new LineSegment2d(inters[0], inters[0] + vec);
  206.                     result[j] = new LineSegment2d(inters[1], inters[1] + vec);
  207.                 }
  208.                 else
  209.                 {
  210.                     Point2d center = arc.Radius < other.Radius ? other.Center : arc.Center;
  211.                     tmp1 = new CircularArc2d(center, Math.Abs(arc.Radius - other.Radius));
  212.                     tmp2 = new CircularArc2d(arc.Center + vec / 2.0, dist / 2.0);
  213.                     inters = tmp1.IntersectWith(tmp2);
  214.                     if (inters == null)
  215.                         return null;
  216.                     vec1 = (inters[0] - center).GetNormal();
  217.                     vec2 = (inters[1] - center).GetNormal();
  218.                     i = vec.X * vec1.Y - vec.Y - vec1.X > 0 ? 0 : 1;
  219.                     j = i ^ 1;
  220.                     result[i] = new LineSegment2d(arc.Center + vec1 * arc.Radius, other.Center + vec1 * other.Radius);
  221.                     result[j] = new LineSegment2d(arc.Center + vec2 * arc.Radius, other.Center + vec2 * other.Radius);
  222.                 }
  223.             }
  224.  
  225.             // inner tangents
  226.             if (flags.HasFlag(TangentType.Inner) && !overlap)
  227.             {
  228.                 double ratio = (arc.Radius / (arc.Radius + other.Radius)) / 2.0;
  229.                 tmp1 = new CircularArc2d(arc.Center + vec * ratio, dist * ratio);
  230.                 inters = arc.IntersectWith(tmp1);
  231.                 if (inters == null)
  232.                     return null;
  233.                 vec1 = (inters[0] - arc.Center).GetNormal();
  234.                 vec2 = (inters[1] - arc.Center).GetNormal();
  235.                 i = vec.X * vec1.Y - vec.Y - vec1.X > 0 ? 2 : 3;
  236.                 j = i == 2 ? 3 : 2;
  237.                 result[i] = new LineSegment2d(arc.Center + vec1 * arc.Radius, other.Center + vec1.Negate() * other.Radius);
  238.                 result[j] = new LineSegment2d(arc.Center + vec2 * arc.Radius, other.Center + vec2.Negate() * other.Radius);
  239.             }
  240.             return result;
  241.         }
  242.     }
  243. }
  244.  

A Test command which draws all tangents between the two selected circles. the lines are colored according to their order in the LineSegment3d array returned by GetTangentsTo() (1 red, 2 yellow, 3 green, 4 cyan).

Code - C#: [Select]
  1.         [CommandMethod("Test")]
  2.         public void Test()
  3.         {
  4.             Document doc = Application.DocumentManager.MdiActiveDocument;
  5.             Database db = doc.Database;
  6.             Editor ed = doc.Editor;
  7.  
  8.             PromptEntityOptions peo = new PromptEntityOptions("\nSelect a circle: ");
  9.             peo.SetRejectMessage("Only a circle.");
  10.             peo.AddAllowedClass(typeof(Circle), true);
  11.             PromptEntityResult per = ed.GetEntity(peo);
  12.             if (per.Status != PromptStatus.OK)
  13.                 return;
  14.             ObjectId id1 = per.ObjectId;
  15.  
  16.             peo.Message = "\nSelect another circle: ";
  17.             ObjectId id2;
  18.             while (true)
  19.             {
  20.                 per = ed.GetEntity(peo);
  21.                 if (per.Status != PromptStatus.OK)
  22.                     return;
  23.                 id2 = per.ObjectId;
  24.                 if (id1 == id2)
  25.                     ed.WriteMessage("\nThe second circle is the same as the first one.");
  26.                 else break;
  27.             }
  28.  
  29.             try
  30.             {
  31.                 using (Transaction tr = db.TransactionManager.StartTransaction())
  32.                 {
  33.                     Circle c1 = (Circle)tr.GetObject(id1, OpenMode.ForRead);
  34.                     Circle c2 = (Circle)tr.GetObject(id2, OpenMode.ForRead);
  35.  
  36.                     CircularArc3d ca1 = new CircularArc3d(c1.Center, c1.Normal, c1.Radius);
  37.                     CircularArc3d ca2 = new CircularArc3d(c2.Center, c2.Normal, c2.Radius);
  38.                     LineSegment3d[] lines = ca1.GetTangentsTo(ca2, TangentType.Inner | TangentType.Outer);
  39.                     if (lines != null)
  40.                     {
  41.                         BlockTableRecord btr =
  42.                             (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
  43.                         for (int i = 0; i < lines.Length; i++)
  44.                         {
  45.                             Line line = new Line(lines[i].StartPoint, lines[i].EndPoint);
  46.                             line.ColorIndex = i + 1;
  47.                             btr.AppendEntity(line);
  48.                             tr.AddNewlyCreatedDBObject(line, true);
  49.                         }
  50.                     }
  51.                     tr.Commit();
  52.                 }
  53.             }
  54.             catch (System.Exception exn)
  55.             {
  56.                 ed.WriteMessage("\n" + exn.Message);
  57.             }
  58.         }
Speaking English as a French Frog

gile

  • Gator
  • Posts: 2505
  • Marseille, France
Re: .NET GEOMETRY Routines
« Reply #37 on: September 15, 2013, 05:35:46 PM »
GeometryExtensions Update: version 1.6

Added: CircularArc2d and CircularArc3d GetTangentsTo methods.
Reorganized: one class per extended type.

GeomExtDoc.chm help file updated.

Attachments in reply #1
Speaking English as a French Frog

Bryco

  • Water Moccasin
  • Posts: 1882
Re: .NET GEOMETRY Routines
« Reply #38 on: May 14, 2016, 02:14:44 PM »
Code to extend a line to the Ucs
Code: [Select]

        [CommandMethod("trt", CommandFlags.UsePickSet)]

        public void TrimToPlane()
        {
            Database db = HostApplicationServices.WorkingDatabase;
            Document doc = acadApp.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;
            PromptEntityOptions peo = new PromptEntityOptions
                ("\nPick a line to extend/trim to the current Ucs:");
            peo.SetRejectMessage("Must be a line:");
            peo.AddAllowedClass(typeof(Line), true);
            PromptEntityResult per = ed.GetEntity(peo);
            if (per.Status != PromptStatus.OK) return;
            Matrix3d Ucs = ed.CurrentUserCoordinateSystem;
            using(Transaction tr = db.TransactionManager.StartTransaction())       
            { 
                Line line=tr.GetObject(per.ObjectId,OpenMode.ForWrite) as Line;
                Point3d p = line.StartPoint;
                Point3d pt = Ucs.CoordinateSystem3d.Origin;
                Vector3d v = line.EndPoint - line.StartPoint; //line.Delta;//.GetNormal();
                Vector3d n = Ucs.CoordinateSystem3d.Zaxis;
                //double Elev = pt.X * n.X + pt.Y * n.Y + pt.Z * n.Z;
                //double Dist = (Elev - (p.X * n.X) - (p.Y * n.Y) - (p.Z * n.Z)) / ((v.X * n.X) + (v.Y * n.Y) + (v.Z * n.Z));
                //Point3d intersectionPt=new Point3d(p.X + Dist * v.X, p.Y + Dist * v.Y, p.Z + Dist * v.Z);
                if (Math.Abs( n.DotProduct(v))<0.00000001)
                {
                    MessageBox.Show("The plane and line-segment are parallel, no intersection:");
                    return;
                }
                double t = n.DotProduct((pt-p))/n.DotProduct(v);
                Point3d ptofIntersection=p + v.MultiplyBy(t);
                if ((p - ptofIntersection).Length > (line.EndPoint - ptofIntersection).Length)
                    line.EndPoint = ptofIntersection;
                else
                    line.StartPoint = ptofIntersection;

            //http://www.thepolygoners.com/tutorials/lineplane/lineplane.html
                //If:
                //t > 0 and t < 1:The intersection occurs between the two end points
                //t = 0:The intersection falls on the first end point
                //t = 1:Intersection falls on the second end point
                //t > 1:Intersection occurs beyond second end Point
                //t < 0:Intersection happens before 1st end point.
                 
                tr.Commit();       
            }

        }

nobody

  • Swamp Rat
  • Posts: 861
  • .net stuff
Re: .NET GEOMETRY Routines
« Reply #39 on: May 14, 2016, 10:27:19 PM »
Thanks..these have been consistently helpful

BKSpurgeon

  • Mosquito
  • Posts: 6
Re: .NET GEOMETRY Routines
« Reply #40 on: August 03, 2017, 04:35:11 AM »
Does it make sense to add these ones as well? Not sure if I know what I'm doing, these are for the PolylineSegmentCollection class, many thanks to Gilles. chrs.

Code: [Select]
 
/// <summary>
        /// Creates a new instance of PolylineSegmentCollection from a Line.
        /// </summary>
        /// <param name="line">A Line instance.</param>
        public PolylineSegmentCollection(Line line)
        {
            Plane plane = new Plane(Point3d.Origin, Vector3d.ZAxis);
            _contents.Add(new PolylineSegment(
                               new LineSegment2d(
                                   line.StartPoint.Convert2d(plane),
                                   line.EndPoint.Convert2d(plane))));
        }

        /// <summary>
        /// Creates a new instance of PolylineSegmentCollection from a spline.
        /// </summary>
        /// <param name="spline">A spline instance.</param>
        public PolylineSegmentCollection(Spline spline)
        {
            _contents.AddRange(new PolylineSegmentCollection((Polyline)spline.ToPolyline()));
        }

        /// <summary>
        /// Creates a new instance of PolylineSegmentCollection from an arc.
        /// </summary>
        /// <param name="spline">An Arc instance.</param>
        public PolylineSegmentCollection(Arc arc)
        {
            Plane plane = new Plane(Point3d.Origin, Vector3d.ZAxis);
            _contents.Add(new PolylineSegment(
                                new CircularArc2d(
                                    arc.Center.Convert2d(plane),
                                    arc.Radius,
                                    arc.StartAngle,
                                    arc.EndAngle,
                                    Vector2d.XAxis,
                                    false)));
        }


Hi,

Some geometry extensions methods for Point2d, Point3d, CircularArc2d, Polyline and Polyline2d classes and two little (maybe usefull) classes: Triangle2d, Triangle3d.

All these classes work together and have to be compiled in a single DLL.

The extension methods requires to reference System.Core (.NET Framework 3.5)

EDIT: extended

The GeomExt class, contains the following extension methods:

Matrix3d Editor.UCS2WCS()
Matrix3d Editor.WCS2UCS()
Matrix3d Editor.DCS2WCS()
Matrix3d Editor.WCS2DCS()
Matrix3d Editor.DCS2PSDCS()
Matrix3d Editor.PSDCS2DCS()

Matrix3d Viewport.DCS2WCS()
Matrix3d Viewport.WCS2DCS()
Matrix3d Viewport.PSDCS2DCS()
Matrix3d Viewport.DCS2PSDCS()

Point3d Point2d.Convert3d()
Point3d Point2d.Convert3d(Plane plane)
Point3d Point2d.Convert3d(Vector3d normal, double elevation)
Point2d Point2d.Flatten(Vector3d normal)
bool IsBetween(Point2d p1, Point2d p2)
bool IsBetween(Point2d p1, Point2d p2, Tolerance tol)
Point2d Point2d.Polar(double angle, double distance)

Point3d Point3d.Convert2d()
Point3d Point3d.Flatten()
bool IsBetween(Point3d p1, Point3d p2)
bool IsBetween(Point3d p1, Point3d p2, Tolerance tol)
Point3d Point3d.Polar(double angle, double distance)
Point3d Point3d.Trans(int from, int to)
Point3d Point3d.Trans(Editor ed, int from, int to)
Point3d Point3d.Trans(CoordSystem from, CoordSystem to)
Point3d Point3d.Trans(Editor ed, CoordSystem from, CoordSystem to)

Vector3d Vector3d .Flatten()

void Point2dCollection.RemoveDuplicate()
void Point2dCollection.RemoveDuplicate(Tolerance tol)
bool Point2dCollection.Contains(Point2d pt, Tolerance tol)

void Point3dCollection.RemoveDuplicate()
void Point3dCollection.RemoveDuplicate(Tolerance tol)
bool Point3dCollection.Contains(Point3d pt, Tolerance tol)

double CircularArc2d.AlgebricArea()
Point2d CircularArc2d.Centroid()

Point2d Polyline.Centroid2d()
Point3d Polyline.Centroid()
Polyline Polyline.GetProjectedPolyline(Plane plane, Vector3d direction)
Polyline Polyline.GetOrthoProjectedPolyline(Plane plane)

Point3d Polyline2d.Centroid()
CircularArc3d Polyline2d.GetArcSegmentAt(int index)
CircularArc2d Polyline2d.GetArcSegment2dAt(int index)
LineSegment3d Polyline2d.GetLineSegmentAt(int index)
LineSegment2d Polyline2d.GetLineSegment2dAt(int index)
Polyline Polyline2d.GetProjectedPolyline(Plane plane, Vector3d direction)
Polyline Polyline2d.GetOrthoProjectedPolyline(Plane plane)
List<Vertex2d> Polyline2d.GetVertices()

Polyline Polyline3d.GetProjectedPolyline(Plane plane, Vector3d direction)
Polyline Polyline3d.GetOrthoProjectedPolyline(Plane plane)

Point3d Region.Centroid()

Point3d Spline.Centroid()

Polyline Ellipse.ToPolyline()


Triangle<T> abstract class

Constructors
Triangle()
Triangle(T[] pts)
Triangle(T a, T b, T c)

Indexor
T Item

Methods
T Inverse()
void Set(T[] pts)
void Set(T a, T b, T c)
T[] ToArray()


Triangle2d : Triangle<Point2d> class

Constructors
Triangle2d() : base()
Triangle2d(Point2d[] pts) : base(pts)
Triangle2d(Point2d a, Point2d b, Point2d c) : base(a, b, c)
Triangle2d(Point2d org, Vector2d v1, Vector2d v2)

Properties
double AlgebricArea
Point2d Centroid
CircularArc2d CircumscribedCircle
CircularArc2d InscribedCircle
bool IsClockwise

Methods
Triangle3d Convert3d(Plane plane)
Triangle3d Convert3d(Vector3d normal, double elevation)
double GetAngleAt(int index)
LineSegment2d GetSegmentAt(int index)
List<Point2d> IntersectWith(LinearEntity2d le2d)
List<Point2d> IntersectWith(LinearEntity2d le2d, Tolerance tol)
bool IsEqualTo(Triangle2d t2d)
bool IsEqualTo(Triangle2d t2d, Tolerance tol)
bool IsPointInside(Point2d pt)
bool IsPointOn(Point2d pt)
void Set(Point2d org, Vector2d v1, Vector2d v2)
Triangle2d TransformBy(Matrix2d mat)


Triangle3d : Triangle<Point3d> class

Constructors
Triangle3d() : base()
Triangle3d(Point3d[] pts) : base(pts)
Triangle3d(Point3d a, Point3d b, Point3d c) : base(a, b, c)
Triangle3d(Point3d org, Vector3d v1, Vector3d v2)

Properties
double Area
Point3d Centroid
CircularArc3d CircumscribedCircle
double Elevation
Vector3d GreatestSlope
Vector3d Horizontal
CircularArc3d InscribedCircle
bool IsHorizontal
Vector3d Normal
double SlopePerCent
Matrix3d SlopeUCS

Methods
Triangle2d Convert2d()
Triangle2d Flatten()
double GetAngleAt(int index)
BoundedPlane GetBoundedPlane()
Plane GetPlane()
LineSegment3d GetSegmentAt(int index)
bool IsEqualTo(Triangle3d t3d)
bool IsEqualTo(Triangle3d t3d, Tolerance tol)
bool IsPointInside(Point3d pt)
bool IsPointOn(Point3d pt)
void Set(Point3d org, Vector3d v1, Vector3d v2)
Triangle3d Transformby(Matrix3d mat)


PolylineSegment class

Constructors

PolylineSegment(Point2d startPoint, Point2d endPoint)
PolylineSegment(Point2d startPoint, Point2d endPoint, double bulge)
PolylineSegment(Point2d startPoint, Point2d endPoint, double bulge, double constantWidth)
PolylineSegment(Point2d startPoint, Point2d endPoint, double bulge, double startWidth, double endWidth)
PolylineSegment(Line2dSegment line)
PolylineSegment(CircularArc2d arc)

Properties

double Bulge
Point2d EndPoint
double EndWidth
bool IsLinear
Point2d StartPoint
double StartWidth

Methods

bool Equals(object obj)
PolylineSegment Clone()
int GetHashCode()
double GetParameterOf(Point3d pt)
void Inverse()
CircularArc2d ToCircularArc()
Curve2d ToCurve2d()
LineSegment2d ToLineSegment()
string ToString()


PolylineSegmentCollection : IList<PolylineSegment> class

Constructors

PolylineSegmentCollection()
PolylineSegmentCollection(Circle circle)
PolylineSegmentCollection(Ellipse ellipse)
PolylineSegmentCollection(Polyline pline)
PolylineSegmentCollection(Polyline2d pline)
PolylineSegmentCollection(IEnumerable<PolylineSegment> segments)

Methods

void Add(PolylineSegment segment)
void AddRange(IEnumerable<PolylineSegment> range)
void Clear()
bool Contains(PolylineSegment segment)
int FinIindex(Predicate<PolylineSegment> match)
int GetClosestSegmentTo(Point2d pt)
IEnumerator<PolylineSegment> GetEnumerator()
int IndexOf(PolylineSegment item)
void Insert(int index, PolylineSegment item)
void InsertRange(int index, IEnumerable<PolylineSegment> collection)
List<PolylineSegmentCollection> Join()
List<PolylineSegmentCollection> Join(Tolerance tol)
bool Remove(PolylineSegment item)
void RemoveAt(int index)
public void RemoveRange(int index, int count)
Polyline ToPolyline()

For more information, see the attached documentation.

GeomExtDoc.zip contains a .chm documentation file.
GeometryExtensions(1.6).zip contains the C# source code files and the DLLs (GeometryExtensions_18.dll for A2010-2012 and GeometryExtensions_19 for A2013+)

<EDIT: version 1.6> added CircularArc2d and CircularArc3d GetTangentsTo methods, reorganized: one class per extended type.

BKSpurgeon

  • Mosquito
  • Posts: 6
Re: .NET GEOMETRY Routines
« Reply #41 on: August 07, 2017, 12:09:12 AM »
Why not allow for pull requests for GeometryExtensions classes? That way people can contribute, i'm sure many will.

Here is a small method but handy method i've added to the PolylineExtensions class which you all may find useful:

Code: [Select]
public static Point3d[] GetPolylinePoints(this Polyline pline)
        {
               
            int vn = pline.NumberOfVertices;

            Point3d[] pointsInPolyline = new Point3d[vn];
            for (int i = 0; i < vn; i++)
            {               
                Point3d pt = pline.GetPoint3dAt(i);
                pointsInPolyline[i] = pt;
            }

            return pointsInPolyline;
        }




Hi,

Some geometry extensions methods for Point2d, Point3d, CircularArc2d, Polyline and Polyline2d classes and two little (maybe usefull) classes: Triangle2d, Triangle3d.

All these classes work together and have to be compiled in a single DLL.

The extension methods requires to reference System.Core (.NET Framework 3.5)

EDIT: extended

The GeomExt class, contains the following extension methods:

Matrix3d Editor.UCS2WCS()
Matrix3d Editor.WCS2UCS()
Matrix3d Editor.DCS2WCS()
Matrix3d Editor.WCS2DCS()
Matrix3d Editor.DCS2PSDCS()
Matrix3d Editor.PSDCS2DCS()

Matrix3d Viewport.DCS2WCS()
Matrix3d Viewport.WCS2DCS()
Matrix3d Viewport.PSDCS2DCS()
Matrix3d Viewport.DCS2PSDCS()

Point3d Point2d.Convert3d()
Point3d Point2d.Convert3d(Plane plane)
Point3d Point2d.Convert3d(Vector3d normal, double elevation)
Point2d Point2d.Flatten(Vector3d normal)
bool IsBetween(Point2d p1, Point2d p2)
bool IsBetween(Point2d p1, Point2d p2, Tolerance tol)
Point2d Point2d.Polar(double angle, double distance)

Point3d Point3d.Convert2d()
Point3d Point3d.Flatten()
bool IsBetween(Point3d p1, Point3d p2)
bool IsBetween(Point3d p1, Point3d p2, Tolerance tol)
Point3d Point3d.Polar(double angle, double distance)
Point3d Point3d.Trans(int from, int to)
Point3d Point3d.Trans(Editor ed, int from, int to)
Point3d Point3d.Trans(CoordSystem from, CoordSystem to)
Point3d Point3d.Trans(Editor ed, CoordSystem from, CoordSystem to)

Vector3d Vector3d .Flatten()

void Point2dCollection.RemoveDuplicate()
void Point2dCollection.RemoveDuplicate(Tolerance tol)
bool Point2dCollection.Contains(Point2d pt, Tolerance tol)

void Point3dCollection.RemoveDuplicate()
void Point3dCollection.RemoveDuplicate(Tolerance tol)
bool Point3dCollection.Contains(Point3d pt, Tolerance tol)

double CircularArc2d.AlgebricArea()
Point2d CircularArc2d.Centroid()

Point2d Polyline.Centroid2d()
Point3d Polyline.Centroid()
Polyline Polyline.GetProjectedPolyline(Plane plane, Vector3d direction)
Polyline Polyline.GetOrthoProjectedPolyline(Plane plane)

Point3d Polyline2d.Centroid()
CircularArc3d Polyline2d.GetArcSegmentAt(int index)
CircularArc2d Polyline2d.GetArcSegment2dAt(int index)
LineSegment3d Polyline2d.GetLineSegmentAt(int index)
LineSegment2d Polyline2d.GetLineSegment2dAt(int index)
Polyline Polyline2d.GetProjectedPolyline(Plane plane, Vector3d direction)
Polyline Polyline2d.GetOrthoProjectedPolyline(Plane plane)
List<Vertex2d> Polyline2d.GetVertices()

Polyline Polyline3d.GetProjectedPolyline(Plane plane, Vector3d direction)
Polyline Polyline3d.GetOrthoProjectedPolyline(Plane plane)

Point3d Region.Centroid()

Point3d Spline.Centroid()

Polyline Ellipse.ToPolyline()


Triangle<T> abstract class

Constructors
Triangle()
Triangle(T[] pts)
Triangle(T a, T b, T c)

Indexor
T Item

Methods
T Inverse()
void Set(T[] pts)
void Set(T a, T b, T c)
T[] ToArray()


Triangle2d : Triangle<Point2d> class

Constructors
Triangle2d() : base()
Triangle2d(Point2d[] pts) : base(pts)
Triangle2d(Point2d a, Point2d b, Point2d c) : base(a, b, c)
Triangle2d(Point2d org, Vector2d v1, Vector2d v2)

Properties
double AlgebricArea
Point2d Centroid
CircularArc2d CircumscribedCircle
CircularArc2d InscribedCircle
bool IsClockwise

Methods
Triangle3d Convert3d(Plane plane)
Triangle3d Convert3d(Vector3d normal, double elevation)
double GetAngleAt(int index)
LineSegment2d GetSegmentAt(int index)
List<Point2d> IntersectWith(LinearEntity2d le2d)
List<Point2d> IntersectWith(LinearEntity2d le2d, Tolerance tol)
bool IsEqualTo(Triangle2d t2d)
bool IsEqualTo(Triangle2d t2d, Tolerance tol)
bool IsPointInside(Point2d pt)
bool IsPointOn(Point2d pt)
void Set(Point2d org, Vector2d v1, Vector2d v2)
Triangle2d TransformBy(Matrix2d mat)


Triangle3d : Triangle<Point3d> class

Constructors
Triangle3d() : base()
Triangle3d(Point3d[] pts) : base(pts)
Triangle3d(Point3d a, Point3d b, Point3d c) : base(a, b, c)
Triangle3d(Point3d org, Vector3d v1, Vector3d v2)

Properties
double Area
Point3d Centroid
CircularArc3d CircumscribedCircle
double Elevation
Vector3d GreatestSlope
Vector3d Horizontal
CircularArc3d InscribedCircle
bool IsHorizontal
Vector3d Normal
double SlopePerCent
Matrix3d SlopeUCS

Methods
Triangle2d Convert2d()
Triangle2d Flatten()
double GetAngleAt(int index)
BoundedPlane GetBoundedPlane()
Plane GetPlane()
LineSegment3d GetSegmentAt(int index)
bool IsEqualTo(Triangle3d t3d)
bool IsEqualTo(Triangle3d t3d, Tolerance tol)
bool IsPointInside(Point3d pt)
bool IsPointOn(Point3d pt)
void Set(Point3d org, Vector3d v1, Vector3d v2)
Triangle3d Transformby(Matrix3d mat)


PolylineSegment class

Constructors

PolylineSegment(Point2d startPoint, Point2d endPoint)
PolylineSegment(Point2d startPoint, Point2d endPoint, double bulge)
PolylineSegment(Point2d startPoint, Point2d endPoint, double bulge, double constantWidth)
PolylineSegment(Point2d startPoint, Point2d endPoint, double bulge, double startWidth, double endWidth)
PolylineSegment(Line2dSegment line)
PolylineSegment(CircularArc2d arc)

Properties

double Bulge
Point2d EndPoint
double EndWidth
bool IsLinear
Point2d StartPoint
double StartWidth

Methods

bool Equals(object obj)
PolylineSegment Clone()
int GetHashCode()
double GetParameterOf(Point3d pt)
void Inverse()
CircularArc2d ToCircularArc()
Curve2d ToCurve2d()
LineSegment2d ToLineSegment()
string ToString()


PolylineSegmentCollection : IList<PolylineSegment> class

Constructors

PolylineSegmentCollection()
PolylineSegmentCollection(Circle circle)
PolylineSegmentCollection(Ellipse ellipse)
PolylineSegmentCollection(Polyline pline)
PolylineSegmentCollection(Polyline2d pline)
PolylineSegmentCollection(IEnumerable<PolylineSegment> segments)

Methods

void Add(PolylineSegment segment)
void AddRange(IEnumerable<PolylineSegment> range)
void Clear()
bool Contains(PolylineSegment segment)
int FinIindex(Predicate<PolylineSegment> match)
int GetClosestSegmentTo(Point2d pt)
IEnumerator<PolylineSegment> GetEnumerator()
int IndexOf(PolylineSegment item)
void Insert(int index, PolylineSegment item)
void InsertRange(int index, IEnumerable<PolylineSegment> collection)
List<PolylineSegmentCollection> Join()
List<PolylineSegmentCollection> Join(Tolerance tol)
bool Remove(PolylineSegment item)
void RemoveAt(int index)
public void RemoveRange(int index, int count)
Polyline ToPolyline()

For more information, see the attached documentation.

GeomExtDoc.zip contains a .chm documentation file.
GeometryExtensions(1.6).zip contains the C# source code files and the DLLs (GeometryExtensions_18.dll for A2010-2012 and GeometryExtensions_19 for A2013+)

<EDIT: version 1.6> added CircularArc2d and CircularArc3d GetTangentsTo methods, reorganized: one class per extended type.

gile

  • Gator
  • Posts: 2505
  • Marseille, France
Re: .NET GEOMETRY Routines
« Reply #42 on: November 17, 2021, 02:41:50 PM »
Hi,

Looking to answer a question on the Autodesk forum, I thought I'd try to do something more generic to get the curves making up the boundaries of a region, including any islands and separate boundary. If the boundary allows it, the returned curve is a closed polyline.

Code - C#: [Select]
  1. using Autodesk.AutoCAD.BoundaryRepresentation;
  2. using Autodesk.AutoCAD.DatabaseServices;
  3. using Autodesk.AutoCAD.Geometry;
  4.  
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Linq;
  8.  
  9. namespace Gile.AutoCAD.Geometry
  10. {
  11.     public static class Extension
  12.     {
  13.         /// <summary>
  14.         /// Gets the curves constituting the boundaries of the region.
  15.         /// </summary>
  16.         /// <param name="region">The region this method applies to.</param>
  17.         /// <returns>Curve collection.</returns>
  18.         public static IEnumerable<Curve> GetCurves(this Region region)
  19.         {
  20.             using (var brep = new Brep(region))
  21.             {
  22.                 var loops = brep.Complexes
  23.                     .SelectMany(complex => complex.Shells)
  24.                     .SelectMany(shell => shell.Faces)
  25.                     .SelectMany(face => face.Loops);
  26.                 foreach (var loop in loops)
  27.                 {
  28.                     var curves3d = loop.Edges.Select(edge => ((ExternalCurve3d)edge.Curve).NativeCurve);
  29.                     if (1 < curves3d.Count())
  30.                     {
  31.                         if (curves3d.All(curve3d => curve3d is CircularArc3d || curve3d is LineSegment3d))
  32.                         {
  33.                             var pline = (Polyline)Curve.CreateFromGeCurve(new CompositeCurve3d(curves3d.ToOrderedArray()));
  34.                             pline.Closed = true;
  35.                             yield return pline;
  36.                         }
  37.                         else
  38.                         {
  39.                             foreach (Curve3d curve3d in curves3d)
  40.                             {
  41.                                 yield return Curve.CreateFromGeCurve(curve3d);
  42.                             }
  43.                         }
  44.                     }
  45.                     else
  46.                     {
  47.                         yield return Curve.CreateFromGeCurve(curves3d.First());
  48.                     }
  49.                 }
  50.             }
  51.         }
  52.  
  53.         /// <summary>
  54.         /// Order the collection by contiguous curves ([n].EndPoint equals to [n+1].StartPoint)
  55.         /// </summary>
  56.         /// <param name="source">Collection this method applies to.</param>
  57.         /// <returns>Ordered array of Curve3d.</returns>
  58.         public static Curve3d[] ToOrderedArray(this IEnumerable<Curve3d> source)
  59.         {
  60.             var list = source.ToList();
  61.             int count = list.Count;
  62.             var array = new Curve3d[count];
  63.             int i = 0;
  64.             array[0] = list[0];
  65.             list.RemoveAt(0);
  66.             int index;
  67.             while (i < count - 1)
  68.             {
  69.                 var pt = array[i++].EndPoint;
  70.                 if ((index = list.FindIndex(c => c.StartPoint.IsEqualTo(pt))) != -1)
  71.                     array[i] = list[index];
  72.                 else if ((index = list.FindIndex(c => c.EndPoint.IsEqualTo(pt))) != -1)
  73.                     array[i] = list[index].GetReverseParameterCurve();
  74.                 else
  75.                     throw new ArgumentException("Not contiguous curves.");
  76.                 list.RemoveAt(index);
  77.             }
  78.             return array;
  79.         }
  80.     }
  81. }
  82.  
« Last Edit: November 18, 2021, 05:08:06 AM by gile »
Speaking English as a French Frog

gile

  • Gator
  • Posts: 2505
  • Marseille, France
Re: .NET GEOMETRY Routines
« Reply #43 on: February 07, 2022, 06:25:57 AM »
GeometryExtensions is now available on GitHub.
Speaking English as a French Frog

Atook

  • Swamp Rat
  • Posts: 1027
  • AKA Tim
Re: .NET GEOMETRY Routines
« Reply #44 on: February 07, 2022, 05:14:54 PM »
Thanks Gile! :)