/// <summary> /// Provides extension methods for the CircularArc3d class. /// </summary> public static class CircularArc3dExtensions { /// <summary> /// Returns the tangents between the active CircularArc3d instance complete circle and another one. /// </summary> /// <remarks> /// Tangents start points are on the object to which this method applies, end points on the one passed as argument. /// Tangents are always returned in the same order: outer tangents before inner tangents, and for both, /// 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. /// </remarks> /// <param name="arc">The object to which this method applies.</param> /// <param name="other">The CircularArc3d to which searched for tangents.</param> /// <param name="flags">An enum value specifying which type of tangent is returned.</param> /// <returns>An array of LineSegment3d representing the tangents (maybe 2 or 4) or null if there is none.</returns> /// <exception cref="Autodesk.AutoCAD.Runtime.exception">eNonCoplanarGeometry is thrown if the objects do not lies on the same plane.</exception> public static LineSegment3d[] GetTangentsTo(this CircularArc3d arc, CircularArc3d other, TangentType flags) { // check if circles lies on the same plane Vector3d normal = arc.Normal; double elev1 = arc.Center.TransformBy(Matrix3d.WorldToPlane(normal)).Z; double elev2 = other.Center.TransformBy(Matrix3d.WorldToPlane(normal)).Z; if (!(normal.IsParallelTo(other.Normal) && Math.Abs(elev1 - elev2) < Tolerance.Global.EqualPoint)) throw new Autodesk.AutoCAD.Runtime.Exception( Autodesk.AutoCAD.Runtime.ErrorStatus.NonCoplanarGeometry);

/// <summary> /// Returns the tangents between the active CircularArc3d instance complete circle and a point. /// </summary> /// <remarks> /// Tangents start points are on the object to which this method applies, end points on the point passed as argument. /// Tangents are always returned in the same order: the tangent on the left side of the line from the circular arc center /// to the point before the one on the right side. /// </remarks> /// <param name="arc">The object to which this method applies.</param> /// <param name="pt">The Point3d to which tangents are searched</param> /// <returns>An array of LineSegement3d representing the tangents (2) or null if there is none.</returns> /// <exception cref="Autodesk.AutoCAD.Runtime.exception">eNonCoplanarGeometry is thrown if the objects do not lies on the same plane.</exception> public static LineSegment3d[] GetTangentsTo(this CircularArc3d arc, Point3d pt) { // check if circle and point lies on the plane Vector3d normal = arc.Normal; double elev1 = arc.Center.TransformBy(Matrix3d.WorldToPlane(normal)).Z; double elev2 = pt.TransformBy(Matrix3d.WorldToPlane(normal)).Z; if (Math.Abs(elev1 - elev2) < Tolerance.Global.EqualPoint) throw new Autodesk.AutoCAD.Runtime.Exception( Autodesk.AutoCAD.Runtime.ErrorStatus.NonCoplanarGeometry);

// check if the point is inside the circle Point3d center = arc.Center; if (pt.DistanceTo(center) <= arc.Radius) return null;

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.

/// <summary> /// Provides extension methods for the CircularArc3d class. /// </summary> public static class CircularArc3dExtensions { /// <summary> /// Returns the tangents between the active CircularArc3d instance complete circle and a point. /// </summary> /// <remarks> /// Tangents start points are on the object to which this method applies, end points on the point passed as argument. /// Tangents are always returned in the same order: the tangent on the left side of the line from the circular arc center /// to the point before the one on the right side. /// </remarks> /// <param name="arc">The object to which this method applies.</param> /// <param name="pt">The Point3d to which tangents are searched</param> /// <returns>An array of LineSegement3d representing the tangents (2) or null if there is none.</returns> /// <exception cref="Autodesk.AutoCAD.Runtime.exception">eNonCoplanarGeometry is thrown if the objects do not lies on the same plane.</exception> public static LineSegment3d[] GetTangentsTo(this CircularArc3d arc, Point3d pt) { // check if arc and point lies on the plane Vector3d normal = arc.Normal; Matrix3d WCS2OCS = Matrix3d.WorldToPlane(normal); double elevation = arc.Center.TransformBy(WCS2OCS).Z; if (Math.Abs(elevation - pt.TransformBy(WCS2OCS).Z) < Tolerance.Global.EqualPoint) throw new Autodesk.AutoCAD.Runtime.Exception( Autodesk.AutoCAD.Runtime.ErrorStatus.NonCoplanarGeometry);

/// <summary> /// Returns the tangents between the active CircularArc3d instance complete circle and another one. /// </summary> /// <remarks> /// Tangents start points are on the object to which this method applies, end points on the one passed as argument. /// Tangents are always returned in the same order: outer tangents before inner tangents, and for both, /// 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. /// </remarks> /// <param name="arc">The object to which this method applies.</param> /// <param name="other">The CircularArc3d to which searched for tangents.</param> /// <param name="flags">An enum value specifying which type of tangent is returned.</param> /// <returns>An array of LineSegment3d representing the tangents (maybe 2 or 4) or null if there is none.</returns> /// <exception cref="Autodesk.AutoCAD.Runtime.exception">eNonCoplanarGeometry is thrown if the objects do not lies on the same plane.</exception> public static LineSegment3d[] GetTangentsTo(this CircularArc3d arc, CircularArc3d other, TangentType flags) { // check if circles lies on the same plane Vector3d normal = arc.Normal; Matrix3d WCS2OCS = Matrix3d.WorldToPlane(normal); double elevation = arc.Center.TransformBy(WCS2OCS).Z; if (!(normal.IsParallelTo(other.Normal) && Math.Abs(elevation - other.Center.TransformBy(WCS2OCS).Z) < Tolerance.Global.EqualPoint)) throw new Autodesk.AutoCAD.Runtime.Exception( Autodesk.AutoCAD.Runtime.ErrorStatus.NonCoplanarGeometry);

/// <summary> /// Provides extension methods for the CircularArc2d class. /// </summary> public static class CircularArc2dExtensions { /// <summary> /// Returns the tangents between the active CircularArc2d instance complete circle and a point. /// </summary> /// <remarks> /// Tangents start points are on the object to which this method applies, end points on the point passed as argument. /// Tangents are always returned in the same order: the tangent on the left side of the line from the circular arc center /// to the point before the one on the right side. /// </remarks> /// <param name="arc">The object to which this method applies.</param> /// <param name="pt">The Point2d to which tangents are searched</param> /// <returns>An array of LineSegement2d representing the tangents (2) or null if there is none.</returns> public static LineSegment2d[] GetTangentsTo(this CircularArc2d arc, Point2d pt) { // check if the point is inside the circle Point2d center = arc.Center; if (pt.GetDistanceTo(center) <= arc.Radius) return null;

/// <summary> /// Returns the tangents between the active CircularArc2d instance complete circle and another one. /// </summary> /// <remarks> /// Tangents start points are on the object to which this method applies, end points on the one passed as argument. /// Tangents are always returned in the same order: outer tangents before inner tangents, and for both, /// 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. /// </remarks> /// <param name="arc">The object to which this method applies.</param> /// <param name="other">The CircularArc2d to which searched for tangents.</param> /// <param name="flags">An enum value specifying which type of tangent is returned.</param> /// <returns>An array of LineSegment2d representing the tangents (maybe 2 or 4) or null if there is none.</returns> public static LineSegment2d[] GetTangentsTo(this CircularArc2d arc, CircularArc2d other, TangentType flags) { // check if a circle is inside the other double dist = arc.Center.GetDistanceTo(other.Center); if (dist - Math.Abs(arc.Radius - other.Radius) <= Tolerance.Global.EqualPoint) return null;

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).