找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 1688|回复: 2

[分享] 两圆公切线

[复制链接]

已领礼包: 859个

财富等级: 财运亨通

发表于 2014-5-16 08:39:38 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
  1. using System;
  2. using Autodesk.AutoCAD.Geometry;

  3. namespace GeometryExtensions
  4. {
  5.     /// <summary>
  6.     /// Tangent type enum
  7.     /// </summary>
  8.     [Flags]
  9.     public enum TangentType { Inner = 1, Outer = 2 }

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

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

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

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

  51.             // outer tangents
  52.             if (flags.HasFlag(TangentType.Outer))
  53.             {
  54.                 if (arc.Radius == other.Radius)
  55.                 {
  56.                     Line3d perp = new Line3d(arc.Center, vec.CrossProduct(normal));
  57.                     inters = arc.IntersectWith(perp);
  58.                     vec1 = (inters[0] - arc.Center).GetNormal();
  59.                     vec2 = (inters[1] - arc.Center).GetNormal();
  60.                     i = vec.GetAngleTo(vec1, normal) < vec.GetAngleTo(vec2, normal) ? 0 : 1;
  61.                     j = i ^ 1;
  62.                     result[i] = new LineSegment3d(inters[0], inters[0] + vec);
  63.                     result[j] = new LineSegment3d(inters[1], inters[1] + vec);
  64.                 }
  65.                 else
  66.                 {
  67.                     Point3d center = arc.Radius < other.Radius ? other.Center : arc.Center;
  68.                     tmp1 = new CircularArc3d(center, normal, Math.Abs(arc.Radius - other.Radius));
  69.                     tmp2 = new CircularArc3d(arc.Center + vec / 2.0, normal, dist / 2.0);
  70.                     inters = tmp1.IntersectWith(tmp2);
  71.                     vec1 = (inters[0] - center).GetNormal();
  72.                     vec2 = (inters[1] - center).GetNormal();
  73.                     i = vec.GetAngleTo(vec1, normal) < vec.GetAngleTo(vec2, normal) ? 0 : 1;
  74.                     j = i ^ 1;
  75.                     result[i] = new LineSegment3d(arc.Center + vec1 * arc.Radius, other.Center + vec1 * other.Radius);
  76.                     result[j] = new LineSegment3d(arc.Center + vec2 * arc.Radius, other.Center + vec2 * other.Radius);
  77.                 }
  78.             }

  79.             // inner tangents
  80.             if (flags.HasFlag(TangentType.Inner) && !overlap)
  81.             {
  82.                 double ratio = (arc.Radius / (arc.Radius + other.Radius)) / 2.0;
  83.                 tmp1 = new CircularArc3d(arc.Center + vec * ratio, normal, dist * ratio);
  84.                 inters = arc.IntersectWith(tmp1);
  85.                 vec1 = (inters[0] - arc.Center).GetNormal();
  86.                 vec2 = (inters[1] - arc.Center).GetNormal();
  87.                 i = vec.GetAngleTo(vec1, normal) < vec.GetAngleTo(vec2, normal) ? 2 : 3;
  88.                 j = i == 2 ? 3 : 2;
  89.                 result[i] = new LineSegment3d(arc.Center + vec1 * arc.Radius, other.Center + vec1.Negate() * other.Radius);
  90.                 result[j] = new LineSegment3d(arc.Center + vec2 * arc.Radius, other.Center + vec2.Negate() * other.Radius);
  91.             }
  92.             return result;
  93.         }

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

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

  119.             Vector3d vec = pt.GetVectorTo(center) / 2.0;
  120.             CircularArc3d tmp = new CircularArc3d(pt + vec, arc.Normal, vec.Length);
  121.             Point3d[] inters = arc.IntersectWith(tmp);
  122.             LineSegment3d[] result = new LineSegment3d[2];
  123.             int i = vec.GetAngleTo(inters[0] - center, normal) < vec.GetAngleTo(inters[1] - center, normal) ? 0 : 1;
  124.             int j = i ^ 1;
  125.             result[i] = new LineSegment3d(inters[0], pt);
  126.             result[j] = new LineSegment3d(inters[1], pt);
  127.             return result;
  128.         }
  129.     }
  130. }

a test command
  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.             PromptEntityOptions peo = new PromptEntityOptions("\nSelect a circle: ");
  8.             peo.SetRejectMessage("Only a circle.");
  9.             peo.AddAllowedClass(typeof(Circle), true);
  10.             PromptEntityResult per = ed.GetEntity(peo);
  11.             if (per.Status != PromptStatus.OK)
  12.                 return;
  13.             ObjectId id1 = per.ObjectId;

  14.             peo.Message = "\nSelect another circle: ";
  15.             ObjectId id2;
  16.             while (true)
  17.             {
  18.                 per = ed.GetEntity(peo);
  19.                 if (per.Status != PromptStatus.OK)
  20.                     return;
  21.                 id2 = per.ObjectId;
  22.                 if (id1 == id2)
  23.                     ed.WriteMessage("\nThe second circle is the same as the first one.");
  24.                 else break;
  25.             }

  26.             try
  27.             {
  28.                 using (Transaction tr = db.TransactionManager.StartTransaction())
  29.                 {
  30.                     Circle c1 = (Circle)tr.GetObject(id1, OpenMode.ForRead);
  31.                     Circle c2 = (Circle)tr.GetObject(id2, OpenMode.ForRead);
  32.                     CircularArc3d ca1 = new CircularArc3d(c1.Center, c1.Normal, c1.Radius);
  33.                     CircularArc3d ca2 = new CircularArc3d(c2.Center, c2.Normal, c2.Radius);
  34.                     LineSegment3d[] lines = ca1.GetTangentsTo(ca2, TangentType.Outer);
  35.                     if (lines != null)
  36.                     {
  37.                         BlockTableRecord btr =
  38.                             (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
  39.                         Vector3d vec = c1.Center.GetVectorTo(c2.Center);
  40.                         Plane plane = new Plane(Point3d.Origin, c1.Normal);
  41.                         double a1 = vec.GetAngleTo(ca1.Center.GetVectorTo(lines[1].StartPoint), ca1.Normal) -
  42.                             vec.GetAngleTo(ca1.Center.GetVectorTo(lines[0].StartPoint), ca1.Normal);
  43.                         double a2 = vec.Negate().GetAngleTo(ca2.Center.GetVectorTo(lines[0].EndPoint), ca1.Normal) -
  44.                             vec.Negate().GetAngleTo(ca2.Center.GetVectorTo(lines[1].EndPoint), ca1.Normal);
  45.                         Polyline pline = new Polyline(4);
  46.                         pline.AddVertexAt(0, lines[0].StartPoint.Convert2d(plane), Math.Tan(a1 / 4.0), 0.0, 0.0);
  47.                         pline.AddVertexAt(1, lines[1].StartPoint.Convert2d(plane), 0.0, 0.0, 0.0);
  48.                         pline.AddVertexAt(2, lines[1].EndPoint.Convert2d(plane), Math.Tan(a2 / 4.0), 0.0, 0.0);
  49.                         pline.AddVertexAt(3, lines[0].EndPoint.Convert2d(plane), 0.0, 0.0, 0.0);
  50.                         pline.Closed = true;
  51.                         pline.Normal = c1.Normal;
  52.                         pline.Elevation = c1.Center.TransformBy(Matrix3d.WorldToPlane(c1.Normal)).Z;
  53.                         btr.AppendEntity(pline);
  54.                         tr.AddNewlyCreatedDBObject(pline, true);
  55.                         c1.UpgradeOpen();
  56.                         c2.UpgradeOpen();
  57.                         c1.Erase();
  58.                         c2.Erase();
  59.                     }
  60.                     tr.Commit();
  61.                 }
  62.             }
  63.             catch (System.Exception exn)
  64.             {
  65.                 ed.WriteMessage("\nError: " + exn.Message);
  66.             }
  67.         }


论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!

已领礼包: 859个

财富等级: 财运亨通

 楼主| 发表于 2014-5-16 08:41:16 | 显示全部楼层
  1. struct lineDist
  2.         {
  3.             public Line  l;
  4.             public double dist;
  5.         }
  6.         [CommandMethod("tt")]
  7.         static public void test()
  8.         {
  9.             Point3d pickedP1;
  10.             Point3d pickedP2;

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

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

  22.             peo.Message = "\nSelect another circle: ";
  23.             ObjectId id2;
  24.             while (true)
  25.             {
  26.                 per = ed.GetEntity(peo);
  27.                 if (per.Status != PromptStatus.OK)
  28.                     return;
  29.                 id2 = per.ObjectId;
  30.                 pickedP2 = per.PickedPoint;
  31.                 if (id1 == id2)
  32.                     ed.WriteMessage("\nThe second circle is the same as the first one.");
  33.                 else break;
  34.             }

  35.             try
  36.             {
  37.                 using (Transaction tr = db.TransactionManager.StartTransaction())
  38.                 {
  39.                     Circle c1 = (Circle)tr.GetObject(id1, OpenMode.ForRead);
  40.                     Circle c2 = (Circle)tr.GetObject(id2, OpenMode.ForRead);
  41.                     CircularArc3d ca1 = new CircularArc3d(c1.Center, c1.Normal, c1.Radius);
  42.                     CircularArc3d ca2 = new CircularArc3d(c2.Center, c2.Normal, c2.Radius);
  43.                     List<LineSegment3d> lines = ydsCommands.GetTangentsToCircle(ca1, ca2);
  44.                     BlockTableRecord btr =
  45.                         (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
  46.                     List<lineDist> ld = new List<lineDist>(lines.Count);
  47.                     double dist = 0;
  48.                     lineDist ldx = new lineDist();
  49.                     foreach (LineSegment3d l in lines)
  50.                     {
  51.                         Line line = new Line(l.StartPoint, l.EndPoint);
  52.                         dist = line.GetClosestPointTo(pickedP1, true).DistanceTo(pickedP1) + line.GetClosestPointTo(pickedP2, true).DistanceTo(pickedP2);
  53.                         ldx.l = line;
  54.                         ldx.dist = dist;
  55.                         ld.Add(ldx);
  56.                     }
  57.                     foreach (lineDist d in ld)
  58.                     {
  59.                         if (d.dist < ldx.dist)
  60.                         {
  61.                             ldx = d;
  62.                         }
  63.                     }
  64.                     btr.AppendEntity(ldx.l);
  65.                     tr.AddNewlyCreatedDBObject(ldx.l, true);
  66.                     tr.Commit();
  67.                 }
  68.             }
  69.             catch (Autodesk.AutoCAD.Runtime.Exception exn)
  70.             {
  71.                 ed.WriteMessage("\n" + exn.Message);
  72.             }
  73.             catch (System.Exception exn)
  74.             {
  75.                 ed.WriteMessage("\n" + exn.Message);
  76.             }
  77.         }
  78.          public static List<LineSegment3d> GetTangentsToCircle(CircularArc3d circle, CircularArc3d other)
  79.         {
  80.             // check if circles lies on the same plane
  81.             Vector3d normal = circle.Normal;
  82.             Plane plane = new Plane(Point3d.Origin, normal);
  83.             double elev1 = circle.Center.TransformBy(Matrix3d.WorldToPlane(plane)).Z;
  84.             double elev2 = other.Center.TransformBy(Matrix3d.WorldToPlane(plane)).Z;
  85.             if (!(normal.IsParallelTo(other.Normal) &&
  86.                 Math.Abs(elev1 - elev2) < Tolerance.Global.EqualPoint))
  87.                 throw new Autodesk.AutoCAD.Runtime.Exception(
  88.                     Autodesk.AutoCAD.Runtime.ErrorStatus.NonCoplanarGeometry);

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

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

  94.             CircularArc3d tmp1, tmp2;
  95.             Point3d center;
  96.             Point3d[] inters;
  97.             Vector3d vec, vec1, vec2;

  98.             // external tangents
  99.             if (circle.Radius == other.Radius)
  100.             {
  101.                 center = circle.Center;
  102.                 normal = circle.Normal;
  103.                 vec = other.Center - center;
  104.                 Line3d perp = new Line3d(center, vec.CrossProduct(normal));
  105.                 inters = circle.IntersectWith(perp);
  106.                 if (inters != null)
  107.                 {
  108.                     result.Add(new LineSegment3d(inters[0], inters[0] + vec));
  109.                     result.Add(new LineSegment3d(inters[1], inters[1] + vec));
  110.                 }
  111.             }
  112.             else
  113.             {
  114.                 if (circle.Radius < other.Radius)
  115.                 {
  116.                     tmp1 = circle;
  117.                     circle = other;
  118.                     other = tmp1;
  119.                 }
  120.                 center = circle.Center;
  121.                 normal = circle.Normal;
  122.                 vec = other.Center - center;
  123.                 tmp1 = new CircularArc3d(circle.Center, normal, circle.Radius - other.Radius);
  124.                 tmp2 = new CircularArc3d(center + vec / 2.0, normal, dist / 2.0);
  125.                 inters = tmp1.IntersectWith(tmp2);
  126.                 if (inters != null)
  127.                 {
  128.                     vec1 = (inters[0] - center).GetNormal();
  129.                     vec2 = (inters[1] - center).GetNormal();
  130.                     result.Add(new LineSegment3d(center + vec1 * circle.Radius, other.Center + vec1 * other.Radius));
  131.                     result.Add(new LineSegment3d(center + vec2 * circle.Radius, other.Center + vec2 * other.Radius));
  132.                 }
  133.             }

  134.             // crossing tangents
  135.             if (circle.Radius + other.Radius < dist)
  136.             {
  137.                 double ratio = (circle.Radius / (circle.Radius + other.Radius)) / 2.0;
  138.                 tmp1 = new CircularArc3d(center + vec * ratio, normal, dist * ratio);
  139.                 inters = circle.IntersectWith(tmp1);
  140.                 if (inters != null)
  141.                 {
  142.                     vec1 = (inters[0] - center).GetNormal();
  143.                     vec2 = (inters[1] - center).GetNormal();
  144.                     result.Add(new LineSegment3d(center + vec1 * circle.Radius, other.Center + vec1.Negate() * other.Radius));
  145.                     result.Add(new LineSegment3d(center + vec2 * circle.Radius, other.Center + vec2.Negate() * other.Radius));
  146.                 }
  147.             }
  148.             return result;
  149.         }



[url]http://forums.autodesk.com/t5/NET/how-to-drawing-a-line-tangent-to-two-circles-in-C/td-p/4418373[/url]
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

已领礼包: 33个

财富等级: 招财进宝

发表于 2014-5-17 14:23:16 | 显示全部楼层
强大无比。作用很大。
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|申请友链|Archiver|手机版|小黑屋|辽公网安备|晓东CAD家园 ( 辽ICP备15016793号 )

GMT+8, 2024-11-15 13:37 , Processed in 0.181272 second(s), 35 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表