找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 1532|回复: 0

[分享] Circle tangents

[复制链接]

已领礼包: 859个

财富等级: 财运亨通

发表于 2014-6-7 01:30:19 | 显示全部楼层 |阅读模式

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

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

×
    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 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);
     
               // 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 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;
     
               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;
           }
       }
    }
     
论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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

GMT+8, 2024-12-28 06:11 , Processed in 0.407933 second(s), 31 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

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