.NET

Reply
Member
ydsoo8
Posts: 4
Registered: ‎09-11-2013
Message 1 of 8 (1,984 Views)
Accepted Solution

how to drawing a line tangent to two circles in C#?

1984 Views, 7 Replies
09-11-2013 09:54 AM

 how to drawing a line tangent to two circles in C#?

 

struct lineDist
{
public Line l;
public double dist;
}
[CommandMethod("tt")]
static public void test()
{
Point3d pickedP1;
Point3d pickedP2;
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
PromptEntityOptions peo = new PromptEntityOptions("\nSelect a circle: ");
peo.SetRejectMessage("Only a circle.");
peo.AddAllowedClass(typeof(Circle), true);
PromptEntityResult per = ed.GetEntity(peo);
if (per.Status != PromptStatus.OK)
return;
ObjectId id1 = per.ObjectId;
pickedP1 = per.PickedPoint;
peo.Message = "\nSelect another circle: ";
ObjectId id2;
while (true)
{
per = ed.GetEntity(peo);
if (per.Status != PromptStatus.OK)
return;
id2 = per.ObjectId;
pickedP2 = per.PickedPoint;
if (id1 == id2)
ed.WriteMessage("\nThe second circle is the same as the first one.");
else break;
}
try
{
using (Transaction tr = db.TransactionManager.StartTransaction())
{
Circle c1 = (Circle)tr.GetObject(id1, OpenMode.ForRead);
Circle c2 = (Circle)tr.GetObject(id2, OpenMode.ForRead);
CircularArc3d ca1 = new CircularArc3d(c1.Center, c1.Normal, c1.Radius);
CircularArc3d ca2 = new CircularArc3d(c2.Center, c2.Normal, c2.Radius);
List<LineSegment3d> lines = ydsCommands.GetTangentsToCircle(ca1, ca2);
BlockTableRecord btr =
(BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
List<lineDist> ld = new List<lineDist>(lines.Count);
double dist = 0;
lineDist ldx = new lineDist();
foreach (LineSegment3d l in lines)
{
Line line = new Line(l.StartPoint, l.EndPoint);
dist = line.GetClosestPointTo(pickedP1, true).DistanceTo(pickedP1) + line.GetClosestPointTo(pickedP2, true).DistanceTo(pickedP2);
ldx.l = line;
ldx.dist = dist;
ld.Add(ldx);
}
foreach (lineDist d in ld)
{
if (d.dist < ldx.dist)
{
ldx = d;
}
}
btr.AppendEntity(ldx.l);
tr.AddNewlyCreatedDBObject(ldx.l, true);
tr.Commit();
}
}
catch (Autodesk.AutoCAD.Runtime.Exception exn)
{
ed.WriteMessage("\n" + exn.Message);
}
catch (System.Exception exn)
{
ed.WriteMessage("\n" + exn.Message);
}
}
public static List<LineSegment3d> GetTangentsToCircle(CircularArc3d circle, CircularArc3d other)
{
// check if circles lies on the same plane
Vector3d normal = circle.Normal;
Plane plane = new Plane(Point3d.Origin, normal);
double elev1 = circle.Center.TransformBy(Matrix3d.WorldToPlane(plane)).Z;
double elev2 = other.Center.TransformBy(Matrix3d.WorldToPlane(plane)).Z;
if (!(normal.IsParallelTo(other.Normal) &&
Math.Abs(elev1 - elev2) < Tolerance.Global.EqualPoint))
throw new Autodesk.AutoCAD.Runtime.Exception(
Autodesk.AutoCAD.Runtime.ErrorStatus.NonCoplanarGeometry);
List<LineSegment3d> result = new List<LineSegment3d>();
// check if a circle is not inside the other
double dist = circle.Center.DistanceTo(other.Center);
if (dist <= Math.Abs(circle.Radius - other.Radius))
return result;
CircularArc3d tmp1, tmp2;
Point3d center;
Point3d[] inters;
Vector3d vec, vec1, vec2;
// external tangents
if (circle.Radius == other.Radius)
{
center = circle.Center;
normal = circle.Normal;
vec = other.Center - center;
Line3d perp = new Line3d(center, vec.CrossProduct(normal));
inters = circle.IntersectWith(perp);
if (inters != null)
{
result.Add(new LineSegment3d(inters[0], inters[0] + vec));
result.Add(new LineSegment3d(inters[1], inters[1] + vec));
}
}
else
{
if (circle.Radius < other.Radius)
{
tmp1 = circle;
circle = other;
other = tmp1;
}
center = circle.Center;
normal = circle.Normal;
vec = other.Center - center;
tmp1 = new CircularArc3d(circle.Center, normal, circle.Radius - other.Radius);
tmp2 = new CircularArc3d(center + vec / 2.0, normal, dist / 2.0);
inters = tmp1.IntersectWith(tmp2);
if (inters != null)
{
vec1 = (inters[0] - center).GetNormal();
vec2 = (inters[1] - center).GetNormal();
result.Add(new LineSegment3d(center + vec1 * circle.Radius, other.Center + vec1 * other.Radius));
result.Add(new LineSegment3d(center + vec2 * circle.Radius, other.Center + vec2 * other.Radius));
}
}
// crossing tangents
if (circle.Radius + other.Radius < dist)
{
double ratio = (circle.Radius / (circle.Radius + other.Radius)) / 2.0;
tmp1 = new CircularArc3d(center + vec * ratio, normal, dist * ratio);
inters = circle.IntersectWith(tmp1);
if (inters != null)
{
vec1 = (inters[0] - center).GetNormal();
vec2 = (inters[1] - center).GetNormal();
result.Add(new LineSegment3d(center + vec1 * circle.Radius, other.Center + vec1.Negate() * other.Radius));
result.Add(new LineSegment3d(center + vec2 * circle.Radius, other.Center + vec2.Negate() * other.Radius));
}
}
return result;
}

 

*Expert Elite*
_gile
Posts: 2,114
Registered: ‎04-29-2006
Message 2 of 8 (1,968 Views)

Re : how to drawing a line tangent to two circles in C#?

09-11-2013 10:54 AM in reply to: ydsoo8
*Expert Elite*
dgorsman
Posts: 5,596
Registered: ‎10-12-2006
Message 3 of 8 (1,962 Views)

Re: how to drawing a line tangent to two circles in C#?

09-11-2013 11:48 AM in reply to: ydsoo8

Break out the math (all that work in high school you never thought would be useful... who knew).  A line that is tangent to a circle will be at 90 degrees to the radius of that circle.  For a line to be tangent to two circles, you need to find a line that is perpendicular to the radius of each circle.  Under this cirumstance, the radii of both circles will be parallel.  From there its just a matter of having a line extending from each circles center to its respective radius, using the same angle for each, and the tangent line will connect them.

----------------------------------
If you are going to fly by the seat of your pants, expect friction burns.
Adopt. Adapt. Overcome. Or be overcome.
A good question will be halfway to a good answer.


Member
ydsoo8
Posts: 4
Registered: ‎09-11-2013
Message 4 of 8 (1,931 Views)

Re: how to drawing a line tangent to two circles in C#?

09-12-2013 09:34 AM in reply to: dgorsman

我的意思是想用C#实现  

LINE <enter>

TAN <enter>

Pick the first point

TAN <enter>

Pick the second point

<enter>

这样的一个功能,而不是将两圆的所有公切线都画出来,仅画出自已所需的一条公切线。

本人初学对autocad一些函数用法不熟悉。希望老师用C#代码将上述命令模拟出来。

本人英语水水很菜,只能写中文了

*Expert Elite*
_gile
Posts: 2,114
Registered: ‎04-29-2006
Message 5 of 8 (1,877 Views)

Re : how to drawing a line tangent to two circles in C#?

09-14-2013 01:18 AM in reply to: ydsoo8

Hi,

 

Here's an extension method for the CicularArc3d class.

It returns a List of LineSegment3d for the tangents between two circles (maybe 0, 2 or 4).

An exception is thrown if the circles do not lie on the same plane.

 

using System;
using System.Collections.Generic;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;

namespace TangentsToCircle
{
    public static class Tangents
    {
        public static List<LineSegment3d> GetTangentsToCircle(this CircularArc3d circle, CircularArc3d other)
        {
            // check if circles lies on the same plane
            Vector3d normal = circle.Normal;
            Plane plane = new Plane(Point3d.Origin, normal);
            double elev1 = circle.Center.TransformBy(Matrix3d.WorldToPlane(plane)).Z;
            double elev2 = other.Center.TransformBy(Matrix3d.WorldToPlane(plane)).Z;
            if (!(normal.IsParallelTo(other.Normal) &&
                Math.Abs(elev1 - elev2) < Tolerance.Global.EqualPoint))
                throw new Autodesk.AutoCAD.Runtime.Exception(
                    Autodesk.AutoCAD.Runtime.ErrorStatus.NonCoplanarGeometry);

            List<LineSegment3d> result = new List<LineSegment3d>();

            // check if a circle is not inside the other
            double dist = circle.Center.DistanceTo(other.Center);
            if (dist <= Math.Abs(circle.Radius - other.Radius))
                return result;

            CircularArc3d tmp1, tmp2;
            Point3d center;
            Point3d[] inters;
            Vector3d vec, vec1, vec2;

            // external tangents
            if (circle.Radius == other.Radius)
            {
                center = circle.Center;
                normal = circle.Normal;
                vec = other.Center - center;
                Line3d perp = new Line3d(center, vec.CrossProduct(normal));
                inters = circle.IntersectWith(perp);
                if (inters != null)
                {
                    result.Add(new LineSegment3d(inters[0], inters[0] + vec));
                    result.Add(new LineSegment3d(inters[1], inters[1] + vec));
                }
            }
            else
            {
                if (circle.Radius < other.Radius)
                {
                    tmp1 = circle;
                    circle = other;
                    other = tmp1;
                }
                center = circle.Center;
                normal = circle.Normal;
                vec = other.Center - center;
                tmp1 = new CircularArc3d(circle.Center, normal, circle.Radius - other.Radius);
                tmp2 = new CircularArc3d(center + vec / 2.0, normal, dist / 2.0);
                inters = tmp1.IntersectWith(tmp2);
                if (inters != null)
                {
                    vec1 = (inters[0] - center).GetNormal();
                    vec2 = (inters[1] - center).GetNormal();
                    result.Add(new LineSegment3d(center + vec1 * circle.Radius, other.Center + vec1 * other.Radius));
                    result.Add(new LineSegment3d(center + vec2 * circle.Radius, other.Center + vec2 * other.Radius));
                }
            }

            // crossing tangents
            if (circle.Radius + other.Radius < dist)
            {
                double ratio = (circle.Radius / (circle.Radius + other.Radius)) / 2.0;
                tmp1 = new CircularArc3d(center + vec * ratio, normal, dist * ratio);
                inters = circle.IntersectWith(tmp1);
                if (inters != null)
                {
                    vec1 = (inters[0] - center).GetNormal();
                    vec2 = (inters[1] - center).GetNormal();
                    result.Add(new LineSegment3d(center + vec1 * circle.Radius, other.Center + vec1.Negate() * other.Radius));
                    result.Add(new LineSegment3d(center + vec2 * circle.Radius, other.Center + vec2.Negate() * other.Radius));
                }
            }
            return result;
        }
    }
}

 

A test command:

 

using System.Collections.Generic;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;

[assembly: CommandClass(typeof(TangentsToCircle.CommandMethods))]

namespace TangentsToCircle
{
    public class CommandMethods
    {
        [CommandMethod("Test", CommandFlags.Modal)]
        public void Test()
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;

            PromptEntityOptions peo = new PromptEntityOptions("\nSelect a circle: ");
            peo.SetRejectMessage("Only a circle.");
            peo.AddAllowedClass(typeof(Circle), true);
            PromptEntityResult per = ed.GetEntity(peo);
            if (per.Status != PromptStatus.OK)
                return;
            ObjectId id1 = per.ObjectId;

            peo.Message = "\nSelect another circle: ";
            ObjectId id2;
            while (true)
            {
                per = ed.GetEntity(peo);
                if (per.Status != PromptStatus.OK)
                    return;
                id2 = per.ObjectId;
                if (id1 == id2)
                    ed.WriteMessage("\nThe second circle is the same as the first one.");
                else break;
            }

            try
            {
                using (Transaction tr = db.TransactionManager.StartTransaction())
                {
                    Circle c1 = (Circle)tr.GetObject(id1, OpenMode.ForRead);
                    Circle c2 = (Circle)tr.GetObject(id2, OpenMode.ForRead);
                    CircularArc3d ca1 = new CircularArc3d(c1.Center, c1.Normal, c1.Radius);
                    CircularArc3d ca2 = new CircularArc3d(c2.Center, c2.Normal, c2.Radius);
                    List<LineSegment3d> lines = ca1.GetTangentsToCircle(ca2);
                    BlockTableRecord btr =
                        (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                    foreach (LineSegment3d l in lines)
                    {
                        Line line = new Line(l.StartPoint, l.EndPoint);
                        btr.AppendEntity(line);
                        tr.AddNewlyCreatedDBObject(line, true);
                    }
                    tr.Commit();
                }
            }
            catch (Autodesk.AutoCAD.Runtime.Exception exn)
            {
                ed.WriteMessage("\n" + exn.Message);
            }
            catch (System.Exception exn)
            {
                ed.WriteMessage("\n" + exn.Message);
            }
        }
    }
}

 

Gilles Chanteau
*Expert Elite*
_gile
Posts: 2,114
Registered: ‎04-29-2006
Message 6 of 8 (1,862 Views)

Re : how to drawing a line tangent to two circles in C#?

09-14-2013 09:40 AM in reply to: _gile

A better (more robust and xml documented) implementation.

 

using System;
using Autodesk.AutoCAD.Geometry;

namespace GeometryExtensions
{
    /// <summary>
    /// Tangent type enum
    /// </summary>
    [Flags]
    public enum TangentType { Inner = 1, Outer = 2 }

    /// <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 theme 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);

            // check if a circle is inside the other
            double dist = arc.Center.DistanceTo(other.Center);
            if (dist - Math.Abs(arc.Radius - other.Radius) <= Tolerance.Global.EqualPoint)
                return null;

            // check if circles overlap
            bool overlap = arc.Radius + other.Radius >= dist;
            if (overlap && flags == TangentType.Inner)
                return null;

            CircularArc3d tmp1, tmp2;
            Point3d[] inters;
            Vector3d vec1, vec2, vec = other.Center - arc.Center;
            int i, j;
            LineSegment3d[] result = new LineSegment3d[(int)flags == 3 && !overlap ? 4 : 2];

            // outer tangents
            if (flags.HasFlag(TangentType.Outer))
            {
                if (arc.Radius == other.Radius)
                {
                    Line3d perp = new Line3d(arc.Center, vec.CrossProduct(normal));
                    inters = arc.IntersectWith(perp);
                    vec1 = (inters[0] - arc.Center).GetNormal();
                    vec2 = (inters[1] - arc.Center).GetNormal();
                    i = vec.GetAngleTo(vec1, normal) < vec.GetAngleTo(vec2, normal) ? 0 : 1;
                    j = i ^ 1;
                    result[i] = new LineSegment3d(inters[0], inters[0] + vec);
                    result[j] = new LineSegment3d(inters[1], inters[1] + vec);
                }
                else
                {
                    Point3d center = arc.Radius < other.Radius ? other.Center : arc.Center;
                    tmp1 = new CircularArc3d(center, normal, Math.Abs(arc.Radius - other.Radius));
                    tmp2 = new CircularArc3d(arc.Center + vec / 2.0, normal, dist / 2.0);
                    inters = tmp1.IntersectWith(tmp2);
                    vec1 = (inters[0] - center).GetNormal();
                    vec2 = (inters[1] - center).GetNormal();
                    i = vec.GetAngleTo(vec1, normal) < vec.GetAngleTo(vec2, normal) ? 0 : 1;
                    j = i ^ 1;
                    result[i] = new LineSegment3d(arc.Center + vec1 * arc.Radius, other.Center + vec1 * other.Radius);
                    result[j] = new LineSegment3d(arc.Center + vec2 * arc.Radius, other.Center + vec2 * other.Radius);
                }
            }

            // inner tangents
            if (flags.HasFlag(TangentType.Inner) && !overlap)
            {
                double ratio = (arc.Radius / (arc.Radius + other.Radius)) / 2.0;
                tmp1 = new CircularArc3d(arc.Center + vec * ratio, normal, dist * ratio);
                inters = arc.IntersectWith(tmp1);
                vec1 = (inters[0] - arc.Center).GetNormal();
                vec2 = (inters[1] - arc.Center).GetNormal();
                i = vec.GetAngleTo(vec1, normal) < vec.GetAngleTo(vec2, normal) ? 2 : 3;
                j = i == 2 ? 3 : 2;
                result[i] = new LineSegment3d(arc.Center + vec1 * arc.Radius, other.Center + vec1.Negate() * other.Radius);
                result[j] = new LineSegment3d(arc.Center + vec2 * arc.Radius, other.Center + vec2.Negate() * other.Radius);
            }
            return result;
        }

        /// <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 theme 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;

            Vector3d vec = pt.GetVectorTo(center) / 2.0;
            CircularArc3d tmp = new CircularArc3d(pt + vec, arc.Normal, vec.Length);
            Point3d[] inters = arc.IntersectWith(tmp);
            LineSegment3d[] result = new LineSegment3d[2];
            int i = vec.GetAngleTo(inters[0] - center, normal) < vec.GetAngleTo(inters[1] - center, normal) ? 0 : 1;
            int j = i ^ 1;
            result[i] = new LineSegment3d(inters[0], pt);
            result[j] = new LineSegment3d(inters[1], pt);
            return result;
        }
    }
}

 

A test command which draws a closed polyline  along the outer tangents and the trimmed selected circles.

 

        [CommandMethod("JoinCircles", CommandFlags.Modal)]
        public void JoinCircles()
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;

            PromptEntityOptions peo = new PromptEntityOptions("\nSelect a circle: ");
            peo.SetRejectMessage("Only a circle.");
            peo.AddAllowedClass(typeof(Circle), true);
            PromptEntityResult per = ed.GetEntity(peo);
            if (per.Status != PromptStatus.OK)
                return;
            ObjectId id1 = per.ObjectId;

            peo.Message = "\nSelect another circle: ";
            ObjectId id2;
            while (true)
            {
                per = ed.GetEntity(peo);
                if (per.Status != PromptStatus.OK)
                    return;
                id2 = per.ObjectId;
                if (id1 == id2)
                    ed.WriteMessage("\nThe second circle is the same as the first one.");
                else break;
            }

            try
            {
                using (Transaction tr = db.TransactionManager.StartTransaction())
                {
                    Circle c1 = (Circle)tr.GetObject(id1, OpenMode.ForRead);
                    Circle c2 = (Circle)tr.GetObject(id2, OpenMode.ForRead);
                    CircularArc3d ca1 = new CircularArc3d(c1.Center, c1.Normal, c1.Radius);
                    CircularArc3d ca2 = new CircularArc3d(c2.Center, c2.Normal, c2.Radius);
                    LineSegment3d[] lines = ca1.GetTangentsTo(ca2, TangentType.Outer);
                    if (lines != null)
                    {
                        BlockTableRecord btr =
                            (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                        Vector3d vec = c1.Center.GetVectorTo(c2.Center);
                        Plane plane = new Plane(Point3d.Origin, c1.Normal);
                        double a1 = vec.GetAngleTo(ca1.Center.GetVectorTo(lines[1].StartPoint), ca1.Normal) -
                            vec.GetAngleTo(ca1.Center.GetVectorTo(lines[0].StartPoint), ca1.Normal);
                        double a2 = vec.Negate().GetAngleTo(ca2.Center.GetVectorTo(lines[0].EndPoint), ca1.Normal) -
                            vec.Negate().GetAngleTo(ca2.Center.GetVectorTo(lines[1].EndPoint), ca1.Normal);
                        Polyline pline = new Polyline(4);
                        pline.AddVertexAt(0, lines[0].StartPoint.Convert2d(plane), Math.Tan(a1 / 4.0), 0.0, 0.0);
                        pline.AddVertexAt(1, lines[1].StartPoint.Convert2d(plane), 0.0, 0.0, 0.0);
                        pline.AddVertexAt(2, lines[1].EndPoint.Convert2d(plane), Math.Tan(a2 / 4.0), 0.0, 0.0);
                        pline.AddVertexAt(3, lines[0].EndPoint.Convert2d(plane), 0.0, 0.0, 0.0);
                        pline.Closed = true;
                        pline.Normal = c1.Normal;
                        pline.Elevation = c1.Center.TransformBy(Matrix3d.WorldToPlane(c1.Normal)).Z;
                        btr.AppendEntity(pline);
                        tr.AddNewlyCreatedDBObject(pline, true);
                        c1.UpgradeOpen();
                        c2.UpgradeOpen();
                        c1.Erase();
                        c2.Erase();
                    }
                    tr.Commit();
                }
            }
            catch (System.Exception exn)
            {
                ed.WriteMessage("\nError: " + exn.Message);
            }
        }

 

Gilles Chanteau
Member
ydsoo8
Posts: 4
Registered: ‎09-11-2013
Message 7 of 8 (1,851 Views)

Re : how to drawing a line tangent to two circles in C#?

09-15-2013 12:50 AM in reply to: _gile

谢谢你的回复. 可能你没有理解我所表达的意思。虽然你的代码没有实现我所想要的功能,但是我可以根所据你的代码进行更改来实现。

Thank you for your reply. You may not understand what I mean. Although your code does not realize what I want, but I can change according to your code to achieve.. Then I will put out the modified code.

Member
ydsoo8
Posts: 4
Registered: ‎09-11-2013
Message 8 of 8 (1,842 Views)

Re : how to drawing a line tangent to two circles in C#?

09-15-2013 02:41 AM in reply to: _gile
struct lineDist
        {
            public Line  l;
            public double dist;
        }
        [CommandMethod("tt")]
        static public void test() 
        {
            Point3d pickedP1;
            Point3d pickedP2;

            Document doc = Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            Editor ed = doc.Editor;

            PromptEntityOptions peo = new PromptEntityOptions("\nSelect a circle: ");
            peo.SetRejectMessage("Only a circle.");
            peo.AddAllowedClass(typeof(Circle), true);
            PromptEntityResult per = ed.GetEntity(peo);
            if (per.Status != PromptStatus.OK)
                return;
            ObjectId id1 = per.ObjectId;
            pickedP1 = per.PickedPoint;

            peo.Message = "\nSelect another circle: ";
            ObjectId id2;
            while (true)
            {
                per = ed.GetEntity(peo);
                if (per.Status != PromptStatus.OK)
                    return;
                id2 = per.ObjectId;
                pickedP2 = per.PickedPoint;
                if (id1 == id2)
                    ed.WriteMessage("\nThe second circle is the same as the first one.");
                else break;
            }

            try
            {
                using (Transaction tr = db.TransactionManager.StartTransaction())
                {
                    Circle c1 = (Circle)tr.GetObject(id1, OpenMode.ForRead);
                    Circle c2 = (Circle)tr.GetObject(id2, OpenMode.ForRead);
                    CircularArc3d ca1 = new CircularArc3d(c1.Center, c1.Normal, c1.Radius);
                    CircularArc3d ca2 = new CircularArc3d(c2.Center, c2.Normal, c2.Radius);
                    List<LineSegment3d> lines = ydsCommands.GetTangentsToCircle(ca1, ca2);
                    BlockTableRecord btr =
                        (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                    List<lineDist> ld = new List<lineDist>(lines.Count);
                    double dist = 0;
                    lineDist ldx = new lineDist();
                    foreach (LineSegment3d l in lines)
                    {
                        Line line = new Line(l.StartPoint, l.EndPoint);
                        dist = line.GetClosestPointTo(pickedP1, true).DistanceTo(pickedP1) + line.GetClosestPointTo(pickedP2, true).DistanceTo(pickedP2);
                        ldx.l = line;
                        ldx.dist = dist;
                        ld.Add(ldx);
                    }
                    foreach (lineDist d in ld)
                    {
                        if (d.dist < ldx.dist)
                        {
                            ldx = d;
                        }
                    }
                    btr.AppendEntity(ldx.l);
                    tr.AddNewlyCreatedDBObject(ldx.l, true);
                    tr.Commit();
                }
            }
            catch (Autodesk.AutoCAD.Runtime.Exception exn)
            {
                ed.WriteMessage("\n" + exn.Message);
            }
            catch (System.Exception exn)
            {
                ed.WriteMessage("\n" + exn.Message);
            }
        }
         public static List<LineSegment3d> GetTangentsToCircle(CircularArc3d circle, CircularArc3d other)
        {
            // check if circles lies on the same plane
            Vector3d normal = circle.Normal;
            Plane plane = new Plane(Point3d.Origin, normal);
            double elev1 = circle.Center.TransformBy(Matrix3d.WorldToPlane(plane)).Z;
            double elev2 = other.Center.TransformBy(Matrix3d.WorldToPlane(plane)).Z;
            if (!(normal.IsParallelTo(other.Normal) &&
                Math.Abs(elev1 - elev2) < Tolerance.Global.EqualPoint))
                throw new Autodesk.AutoCAD.Runtime.Exception(
                    Autodesk.AutoCAD.Runtime.ErrorStatus.NonCoplanarGeometry);

            List<LineSegment3d> result = new List<LineSegment3d>();

            // check if a circle is not inside the other
            double dist = circle.Center.DistanceTo(other.Center);
            if (dist <= Math.Abs(circle.Radius - other.Radius))
                return result;

            CircularArc3d tmp1, tmp2;
            Point3d center;
            Point3d[] inters;
            Vector3d vec, vec1, vec2;

            // external tangents
            if (circle.Radius == other.Radius)
            {
                center = circle.Center;
                normal = circle.Normal;
                vec = other.Center - center;
                Line3d perp = new Line3d(center, vec.CrossProduct(normal));
                inters = circle.IntersectWith(perp);
                if (inters != null)
                {
                    result.Add(new LineSegment3d(inters[0], inters[0] + vec));
                    result.Add(new LineSegment3d(inters[1], inters[1] + vec));
                }
            }
            else
            {
                if (circle.Radius < other.Radius)
                {
                    tmp1 = circle;
                    circle = other;
                    other = tmp1;
                }
                center = circle.Center;
                normal = circle.Normal;
                vec = other.Center - center;
                tmp1 = new CircularArc3d(circle.Center, normal, circle.Radius - other.Radius);
                tmp2 = new CircularArc3d(center + vec / 2.0, normal, dist / 2.0);
                inters = tmp1.IntersectWith(tmp2);
                if (inters != null)
                {
                    vec1 = (inters[0] - center).GetNormal();
                    vec2 = (inters[1] - center).GetNormal();
                    result.Add(new LineSegment3d(center + vec1 * circle.Radius, other.Center + vec1 * other.Radius));
                    result.Add(new LineSegment3d(center + vec2 * circle.Radius, other.Center + vec2 * other.Radius));
                }
            }

            // crossing tangents
            if (circle.Radius + other.Radius < dist)
            {
                double ratio = (circle.Radius / (circle.Radius + other.Radius)) / 2.0;
                tmp1 = new CircularArc3d(center + vec * ratio, normal, dist * ratio);
                inters = circle.IntersectWith(tmp1);
                if (inters != null)
                {
                    vec1 = (inters[0] - center).GetNormal();
                    vec2 = (inters[1] - center).GetNormal();
                    result.Add(new LineSegment3d(center + vec1 * circle.Radius, other.Center + vec1.Negate() * other.Radius));
                    result.Add(new LineSegment3d(center + vec2 * circle.Radius, other.Center + vec2.Negate() * other.Radius));
                }
            }
            return result;
        }

 

Post to the Community

Have questions about Autodesk products? Ask the community.

New Post
Announcements
Are You Going To Be @ AU 2014? Feel free to drop by our AU topic post and share your plans, plug a class that you're teaching, or simply check out who else from the community might be in attendance. Ohh and don't forgot to stop by the Autodesk Help | Learn | Collaborate booths in the Exhibit Hall and meet our community team if you get a chance!