- UID
- 658062
- 积分
- 2147
- 精华
- 贡献
-
- 威望
-
- 活跃度
-
- D豆
-
- 在线时间
- 小时
- 注册时间
- 2008-10-22
- 最后登录
- 1970-1-1
|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
- 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
- [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);
- }
- }
|
|