- 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 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;
}
}
}
|
|