using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Text.RegularExpressions; using Autodesk.Revit.DB; using SAGA.DotNetUtils; using SAGA.DotNetUtils.Extend; using SAGA.DotNetUtils.Geometry; using SAGA.RevitUtils.Infrastructure; using SAGA.RevitUtils.Utils; using Point = System.Windows.Point; namespace SAGA.RevitUtils.Extends { public static class UvExtend { public static UV MiddlePoint(this UV first, UV second) { double u = (first.U + second.U)/2; double v = (first.V + second.V)/2; UV midPoint = new UV(u, v); return midPoint; } } public static class XyzExtend { /// /// 获取两点距离信息 /// /// /// /// public static PointDistanceInfo DistanceInfoTo(this XYZ p1, XYZ p2) { return new PointDistanceInfo(p1, p2); } /// /// 判断多点是否在同一直线上,另外判断点是否在线段上 /// /// 所要判断点 /// 另外一点或线起点 /// 另外一点或线段终点 /// false:判断是否在同一直线 true:判断是否在线段上 /// /// 增加可选参数flag用于判断当前点是否在两点所组成的线段上 public static bool IsInLine(this XYZ p1, XYZ p2, XYZ p3, bool flag = false) { PointDistanceInfo distance1 = p1.DistanceInfoTo(p2); PointDistanceInfo distance2 = p2.DistanceInfoTo(p3); PointDistanceInfo distance3 = p3.DistanceInfoTo(p1); PointDistanceInfo max = PointDistanceInfo.Max(new PointDistanceInfo[] {distance1, distance2, distance3}); Line lineMaxLength =max.P1.NewLine( max.P2); XYZ[] points = new XYZ[] {p1, p2, p3}; foreach (XYZ p in points) { if (!lineMaxLength.IsOnCurve(p)) { return false; } } if (flag == true) //判断p1是否在线段p2,p3上 { double length = distance1.Distance + distance3.Distance; if (length.IsEqual(distance2.Distance)) //若点在线段上,则点到两端点的距离之和为线段长度 { return true; } else { return false; } } return true; } /// /// 判断多点是否在同一直线 /// /// /// /// public static bool IsInLine(this XYZ pt, XYZ[] points) { if (points == null || points.Length < 2) { throw new ArgumentException("points"); } List listPs = new List(); listPs.Add(pt); listPs.AddRange(points); for (int i = 0; i < listPs.Count; i++) { int intMaxIndex = i + 2; if (intMaxIndex < listPs.Count) { XYZ p1 = listPs[i]; XYZ p2 = listPs[i + 1]; XYZ p3 = listPs[i + 2]; if (!p1.IsInLine(p2, p3)) { return false; } } } return true; } /// /// 将点移到指定点 /// /// /// /// public static XYZ ConvertToPoint(this XYZ point, XYZ origin) { Transform tf = new Transform(Transform.Identity); { tf.BasisX = XYZ.BasisX; tf.BasisY = XYZ.BasisY; tf.BasisZ = XYZ.BasisZ; tf.Origin = origin; } return tf.OfPoint(point); } /// /// 将水平面三维坐标转换为二维坐标求叉积判断旋转关系 /// 两个点若是水平面的点可以直接使用,若是不是水平面需要进行坐标转换 /// 大于0:顺时针 等于0:共线 /// /// /// /// public static double VectorProduct(this XYZ left, XYZ right) { UV uv1 = new UV(left.X, left.Y); UV uv2 = new UV(right.X, right.Y); return uv1.CrossProduct(uv2); } /// /// 判断多点是否在同一直线上 /// /// /// /// public static bool IsOnLine(this XYZ pt, XYZ[] points) { return pt.IsInLine(points); } /// /// 判断点在线上 /// /// /// /// public static bool IsOnCurve(this XYZ pt, Curve curve) { if (curve is Line) { Line line = curve as Line; return pt.IsOnLine(line); } if (curve is Arc) { Arc arc = curve as Arc; return pt.IsInArc(arc); } return false; } /// /// 点在线段上 /// /// /// /// public static bool IsOnLine(this XYZ pt, Line line) { return line.IsOnCurve(pt); } /// /// 判断点是否在弧上 /// /// /// /// public static bool IsInArc(this XYZ pt, Curve arc) { return arc.IsOnCurve(pt); } /// /// 判断曲线是否存在于一个曲线集合里 /// /// /// /// public static bool ExsitsInlist(this XYZ pt, IList listPoints, double tolerance = 0) { if (listPoints == null || listPoints.Count <= 0) { return false; } return listPoints.Contains(pt, new XyzEqualComparer(tolerance)); } /// /// 转UV /// /// /// public static UV ToUv(this XYZ pt) { return new UV(pt.X, pt.Y); } /// /// 转2DPoint /// /// /// public static XYZ To2DPoint(this XYZ pt) { return pt.To2DPoint(XyzOptions.Z); } public static Point ToW2DPoint(this XYZ pt) { if (pt == null) return default(Point); return new Point(pt.X,pt.Y); } public static Geometry2D.PointD ToPointD(this XYZ pt) { return new Geometry2D.PointD(pt.X, pt.Y); } /// /// 转2DPoint /// /// /// /// public static XYZ To2DPoint(this XYZ pt, XyzOptions optionWhereToZero) { switch (optionWhereToZero) { case XyzOptions.X: return new XYZ(0, pt.Y, pt.Z); case XyzOptions.Y: return new XYZ(pt.X, 0, pt.Z); case XyzOptions.Z: default: return new XYZ(pt.X, pt.Y, 0); } } /// /// 比较某一值 /// /// /// /// /// public static int CompareTo(this XYZ pt1, XYZ pt2, XyzOptions whereToCompare) { double a = 0, b = 0; switch (whereToCompare) { case XyzOptions.X: a = pt1.X; b = pt2.X; break; case XyzOptions.Y: a = pt1.Y; b = pt2.Y; break; case XyzOptions.Z: a = pt1.Z; b = pt2.Z; break; } if (a == b) { return 0; } return (a > b) ? 1 : -1; } /// /// 比较 /// /// /// /// /// public static int CompareTo(this XYZ first, XYZ second, DirectionEnum optionHowCompare, bool ignoreZ = false) { if (!first.Z.IsEqual(second.Z, 0.0) && !ignoreZ) { if (first.Z <= second.Z) { return -1; } return 1; } switch (optionHowCompare) { case DirectionEnum.LeftRight: if (!first.X.IsEqual(second.X, 0.0)) { if (first.X <= second.X) { return -1; } return 1; } return 0; case DirectionEnum.LeftRightBottomTop: if (!first.X.IsEqual(second.X, 0.0)) { if (first.X <= second.X) { return -1; } return 1; } if (!first.Y.IsEqual(second.Y, 0.0)) { if (first.Y >= second.Y) { return 1; } return -1; } return 0; case DirectionEnum.LeftRightTopBottom: if (!first.X.IsEqual(second.X, 0.0)) { if (first.X <= second.X) { return -1; } return 1; } if (!first.Y.IsEqual(second.Y, 0.0)) { if (first.Y >= second.Y) { return -1; } return 1; } return 0; case DirectionEnum.RightLeft: if (!first.X.IsEqual(second.X, 0.0)) { if (first.X <= second.X) { return 1; } return -1; } return 0; case DirectionEnum.RightLeftBottomTop: if (!first.X.IsEqual(second.X, 0.0)) { if (first.X <= second.X) { return 1; } return -1; } if (!first.Y.IsEqual(second.Y, 0.0)) { if (first.Y >= second.Y) { return 1; } return -1; } return 0; case DirectionEnum.RightLeftTopBottom: if (!first.X.IsEqual(second.X, 0.0)) { if (first.X <= second.X) { return 1; } return -1; } if (!first.Y.IsEqual(second.Y, 0.0)) { if (first.Y >= second.Y) { return -1; } return 1; } return 0; case DirectionEnum.BottomTop: if (!first.Y.IsEqual(second.Y, 0.0)) { if (first.Y <= second.Y) { return -1; } return 1; } return 0; case DirectionEnum.BottomTopLeftRight: if (!first.Y.IsEqual(second.Y, 0.0)) { if (first.Y >= second.Y) { return 1; } return -1; } if (!first.X.IsEqual(second.X, 0.0)) { if (first.X <= second.X) { return -1; } return 1; } return 0; case DirectionEnum.BottomTopRightLeft: if (!first.Y.IsEqual(second.Y, 0.0)) { if (first.Y >= second.Y) { return 1; } return -1; } if (!first.X.IsEqual(second.X, 0.0)) { if (first.X <= second.X) { return 1; } return -1; } return 0; case DirectionEnum.TopBottom: if (!first.Y.IsEqual(second.Y, 0.0)) { if (first.Y <= second.Y) { return 1; } return -1; } return 0; case DirectionEnum.TopBottomLeftRight: case DirectionEnum.LeftTopRightBottom: if (!first.Y.IsEqual(second.Y, 0.0)) { if (first.Y >= second.Y) { return -1; } return 1; } if (!first.X.IsEqual(second.X, 0.0)) { if (first.X <= second.X) { return -1; } return 1; } return 0; case DirectionEnum.TopBottomRightLeft: if (!first.Y.IsEqual(second.Y, 0.0)) { if (first.Y >= second.Y) { return -1; } return 1; } if (!first.X.IsEqual(second.X, 0.0)) { if (first.X <= second.X) { return 1; } return -1; } return 0; } if (first.Y.IsEqual(second.Y, 0.0)) { if (first.X.IsEqual(second.X, 0.0)) { return 0; } if (optionHowCompare == DirectionEnum.LeftBottomRightTop) { if (first.X <= second.X) { return -1; } return 1; } if (first.X >= second.X) { return -1; } return 1; } if (first.Y <= second.Y) { return -1; } return 1; } /// /// 获取相对X轴倾斜角度,忽略Z轴,如果取圆上的点,则应该把圆上的点作为,起点 startPoint, 而圆心作为终点 endPoint /// /// /// /// public static double GetSlopeAngle(this XYZ endPt, XYZ centerPt) { XYZ vec = endPt.Subtract(centerPt); return (vec.QuadrantAngle().ToAngle() + 360)%360; } /// /// 获取相对X轴倾斜弧度 /// /// /// /// public static double GetSlopeRadian(this XYZ endPt, XYZ centerPt) { XYZ vec = endPt.Subtract(centerPt); return vec.QuadrantAngle(); } /// /// 矢量的象限角0到2Pi /// /// /// /// public static double QuadrantAngle(this XYZ vec, XYZ xAxis = null) { if (xAxis == null) { xAxis = XYZ.BasisX; } double dRtn = xAxis.AngleOnPlaneTo(vec, XYZ.BasisZ); if (dRtn.IsEqual(2*Math.PI)) { dRtn = 0; } return dRtn; } /// /// 两个平面向量的夹角(锐角) /// /// /// /// public static double GetAngle(this XYZ vec1, XYZ vec2) { double dRtn; if (vec1.IsSameDirection(vec2) || vec1.IsOppositeDirection(vec2)) dRtn = 0; else //主要区别在这里,因为Z轴的方向不同 dRtn = vec1.AngleOnPlaneTo(vec2, (vec1.CrossProduct(vec2)).Normalize()); if (dRtn.IsEqual(2*Math.PI)) { dRtn = 0; } return dRtn; } /// /// 两个平面向量的夹角,逆时针角 /// /// /// /// public static double GetAngle2(this XYZ vec1, XYZ vec2) { double dRtn = vec1.AngleOnPlaneTo(vec2, XYZ.BasisZ); if (dRtn.IsEqual(2*Math.PI)) { dRtn = 0; } return dRtn; } /// /// 圆弧凸度 /// /// 圆心 /// 起点 /// 终点 /// public static double GetArcBulge(this XYZ ptC, XYZ ptS, XYZ ptE) { if (ptE.IsEqual(ptS)) return 0; XYZ vec1 = ptS - ptC; XYZ vec2 = ptE - ptC; double angle = vec1.AngleOnPlaneTo(vec2, XYZ.BasisZ); if (angle.IsLess(-Math.PI)) angle += Math.PI*2; else if (angle.IsThan(Math.PI)) angle -= Math.PI*2; return Math.Tan(angle/4); } /// /// 修改x值 /// /// /// public static XYZ NewX(this XYZ p1) { return p1.NewX(null); } /// /// 修改x值 /// /// /// /// public static XYZ NewX(this XYZ p1, double? x) { double xValue = x.HasValue ? x.Value : 0; double y = p1.Y; double z = p1.Z; XYZ result = new XYZ(xValue, y, z); return result; } /// /// 增加x值 /// /// /// /// public static XYZ AddX(this XYZ p1, double? x) { double xValue = x.HasValue ? x.Value : 0; double y = p1.Y; double z = p1.Z; XYZ result = new XYZ(p1.X + xValue, y, z); return result; } /// /// 修改y值 /// /// /// public static XYZ NewY(this XYZ p1) { return p1.NewY(null); } /// /// 修改y值 /// /// /// /// public static XYZ NewY(this XYZ p1, double? y) { double x = p1.X; double yValue = y.HasValue ? y.Value : 0; double z = p1.Z; XYZ result = new XYZ(x, yValue, z); return result; } /// /// 增加y值 /// /// /// /// public static XYZ AddY(this XYZ p1, double? y) { double x = p1.X; double yValue = y.HasValue ? y.Value : 0; double z = p1.Z; XYZ result = new XYZ(x, p1.Y + yValue, z); return result; } /// /// 修改z值 /// /// /// public static XYZ NewZ(this XYZ p1) { return p1.NewZ(null); } /// /// 修改z值 /// /// /// /// public static XYZ NewZ(this XYZ p1, double? z) { double x = p1.X; double y = p1.Y; double zValue = z.HasValue ? z.Value : 0; XYZ result = new XYZ(x, y, zValue); return result; } /// /// 增加z值 /// /// /// /// public static XYZ AddZ(this XYZ p1, double? z) { double x = p1.X; double y = p1.Y; double zValue = z.HasValue ? z.Value : 0; XYZ result = new XYZ(x, y, p1.Z + zValue); return result; } /// /// 创建线 /// /// /// /// public static Line NewLine(this XYZ first, XYZ second) { return Line.CreateBound(first, second); } /// /// 两个坐标是否相等(包含Z坐标) /// /// /// /// /// public static bool IsEqual(this XYZ first, XYZ second, double tolerance = 0) { return (first.X.IsEqual(second.X, tolerance) && first.Y.IsEqual(second.Y, tolerance) && first.Z.IsEqual(second.Z, tolerance)); } /// /// 两个坐标是否相等(不包含Z坐标) /// /// /// /// 误差范围ls 2015-01-04添加 /// public static bool IsEqual2(this XYZ first, XYZ second, double tolerance = 0) { return first.NewZ().IsEqual(second.NewZ(), tolerance); } /// /// 相等处理 /// /// /// /// /// /// public static bool IsEqual(this XYZ first, XYZ second, XyzOptions whereNotEqual, double tolerance = 0) { switch (whereNotEqual) { case XyzOptions.X: return (first.Y.IsEqual(second.Y, tolerance) && first.Z.IsEqual(second.Z, tolerance)); case XyzOptions.Y: return (first.X.IsEqual(second.X, tolerance) && first.Z.IsEqual(second.Z, tolerance)); case XyzOptions.Z: default: return (first.X.IsEqual(second.X, tolerance) && first.Y.IsEqual(second.Y, tolerance)); } } /// /// 转API /// /// /// public static XYZ ConvertToApi(this XYZ xyz) { double x = xyz.X.ToApi(); double y = xyz.Y.ToApi(); double z = xyz.Z.ToApi(); return new XYZ(x, y, z); } /// /// 转项目单位 /// /// /// public static XYZ ConvertFromApi(this XYZ xyz) { double x = xyz.X.FromApi(); double y = xyz.Y.FromApi(); double z = xyz.Z.FromApi(); return new XYZ(x, y, z); } public static XYZ FromApi(this XYZ xyz,DisplayUnitType unitType=DisplayUnitType.DUT_MILLIMETERS) { double x = xyz.X.FromApi(unitType); double y = xyz.Y.FromApi(unitType); double z = xyz.Z.FromApi(unitType); return new XYZ(x, y, z); } /// /// 取整 /// /// /// public static XYZ Round(this XYZ xyz, int digits = 0) { return new XYZ(xyz.X.Round(digits), xyz.Y.Round(digits), xyz.Z.Round(digits)); } /// /// /// /// /// /// public static string ToString(this XYZ xyz, string format) { if (format == null || format.Length <= 0) { format = "{0},{1},{2}"; } return string.Format(format, xyz.X, xyz.Y, xyz.Z); } /// /// 转换为字符串 /// /// /// public static string ToString2(this XYZ xyz) { string format = "[{0},{1},{2}]"; return xyz.ToString(format); } /// /// 转换为二维坐标字符串 /// /// /// public static string ToString2D(this XYZ xyz) { string format = "[{0}, {1}]"; return string.Format(format, Math.Round(xyz.X, 2), Math.Round(xyz.Y, 2)); } /// /// Transform old coordinate system in the new coordinate system /// /// the XYZ which need to be transformed /// the value of the coordinate system to be transformed /// the new XYZ which has been transformed public static XYZ TransformPoint(this XYZ pt, Transform transform) { //get the coordinate value in X, Y, Z axis double x = pt.X; double y = pt.Y; double z = pt.Z; //transform basis of the old coordinate system in the new coordinate system XYZ b0 = transform.get_Basis(0); XYZ b1 = transform.get_Basis(1); XYZ b2 = transform.get_Basis(2); XYZ origin = transform.Origin; //transform the origin of the old coordinate system in the new coordinate system double xTemp = x*b0.X + y*b1.X + z*b2.X + origin.X; double yTemp = x*b0.Y + y*b1.Y + z*b2.Y + origin.Y; double zTemp = x*b0.Z + y*b1.Z + z*b2.Z + origin.Z; return new XYZ(xTemp, yTemp, zTemp); } /// /// Move a pt a give offset along a given direction /// /// the pt need to move /// the direction the pt move to /// indicate how long to move /// the moved pt public static XYZ OffsetPoint(this XYZ pt, XYZ direction, double offset) { XYZ directUnit = direction.Normalize(); XYZ offsetVect = directUnit.Multiply(offset); return pt.Add(offsetVect); } /// /// 两点间的中点 /// /// /// /// public static XYZ MiddlePoint(this XYZ first, XYZ second) { double x = (first.X + second.X)/2; double y = (first.Y + second.Y)/2; double z = (first.Z + second.Z)/2; XYZ midPoint = new XYZ(x, y, z); return midPoint; } /// /// 两点距离(参考z轴) /// /// the first pt /// the first pt /// the distance of two points public static double FindDistance(this XYZ first, XYZ second) { return first.DistanceTo(second); } /// /// 两点距离(忽略z轴) /// /// the first pt /// the first pt /// the distance of two points public static double FindDistance2(this XYZ first, XYZ second) { return first.NewZ().FindDistance(second.NewZ()); } /// /// Find the direction vector from first pt to second pt /// /// the first pt /// the second pt /// the direction vector public static XYZ FindDirection(this XYZ first, XYZ second) { return second.Subtract(first).Normalize(); } /// /// 点在圆内 /// /// /// /// public static bool PointInCircle(this XYZ pt, List curveList) { if (curveList.Count != 2) { return false; } Arc arc1 = curveList[0].GetArc(); Arc arc2 = curveList[1].GetArc(); if ((arc1 == null) || (arc2 == null)) { return false; } CurveLoop loop = CurveLoop.Create(curveList); if (loop.IsOpen()) { return false; } XYZ ptCenter = arc1.StartPoint().MiddlePoint(arc1.EndPoint()); double dR = arc1.StartPoint().FindDistance2(arc1.EndPoint())/2; if (pt.FindDistance2(ptCenter).IsLess(dR)) { return true; } return false; } /// /// 判断点是否在多边形内 /// /// /// 组成多边形的线 /// /// 原理:根据点水平向左做射线,若与多边形单边交点为奇数则此点在内部,反之在外部 public static bool PointInPoly(this XYZ pt, List curveList) { Line line = Line.CreateUnbound(pt, new XYZ(-1, 0, 0)); //水平向左射线 int i = 0; List dList = new List(); curveList.ForEach(delegate(Curve p) { dList.Add(p.StartPoint().Y); dList.Add(p.EndPoint().Y); }); foreach (Curve curve in curveList) { if (curve.StartPoint().Y.IsEqual(curve.EndPoint().Y)) continue; if (curve.IsIntersection(line)) { XYZ xyz = curve.GetIntersections(line)[0]; if (xyz.X > pt.X) continue; double minY = Math.Min(curve.StartPoint().Y, curve.EndPoint().Y); double maxY = Math.Max(curve.StartPoint().Y, curve.EndPoint().Y); //如果交点为最高点或最低点,则点肯定不在多边形内 if (xyz.Y.IsEqual(dList.Max()) || xyz.Y.IsEqual(dList.Min())) continue; //判断是交点为线段端点,只取纵坐标最大的那个 if (xyz.Y != minY) { i++; } } } if (i%2 == 0) return false; return true; } /// /// 判断点是否在多边形中 /// /// /// /// public static bool PointInPolygon2(this XYZ pt, IList listProfile) { try { List listPt = new List(); foreach (Curve curve in listProfile) { XYZ ptS = curve.StartPoint(); XYZ ptE = curve.EndPoint(); if (!ptS.ExsitsInlist(listPt)) { listPt.Add(ptS); } if (!ptE.ExsitsInlist(listPt)) { listPt.Add(ptE); } } double anglesum = 0; int n = listPt.Count; for (int i = 0; i < n; i++) { XYZ pt1 = listPt[i]; XYZ pt2 = listPt[(i + 1)%n]; XYZ v1 = pt1 - pt; XYZ v2 = pt2 - pt; double len1 = v1.GetLength(); double len2 = v2.GetLength(); if ((len1*len2).IsEqual(0)) { return true; } else { double cosa = v1.DotProduct(v2)/(len1*len2); anglesum += Math.Acos(cosa); } } return anglesum.IsEqual(2*Math.PI); } catch { return false; } } /// /// 点按照Z轴旋转 /// /// /// 弧度(逆时针为正角) /// /// public static XYZ PointRotate(this XYZ pt, double angle, XYZ origin) { XYZ vec = new XYZ(pt.X - origin.X, pt.Y - origin.Y, pt.Z - origin.Z); vec = vec.VectorRotate(angle, origin); return origin + vec; } /// /// 向量以Z轴为参照轴绕原点旋转 /// /// /// /// public static XYZ VectorRotate(this XYZ vec, double angle) { return vec.VectorRotate(angle, XYZ.Zero); } /// /// 向量(点)绕任意轴旋转 /// /// /// 参照轴 /// /// public static XYZ VectorRotate(this XYZ vec, XYZ axis, double angle) { return vec.VectorRotate(XYZ.Zero, axis, angle); } /// /// 向量绕Z轴旋转 /// /// /// 弧度 /// 参照点 /// public static XYZ VectorRotate(this XYZ vec, double angle, XYZ origin) { return vec.VectorRotate(origin, XYZ.BasisZ, angle); } /// /// 向量绕任意轴旋转 /// /// /// 旋转所绕点 /// 旋转所绕的轴 /// 旋转角度 /// public static XYZ VectorRotate(this XYZ vec, XYZ origin, XYZ axis, double angle) { Transform transform = Transform.CreateRotationAtPoint(axis,angle,origin); return transform.OfVector(vec); } /// /// 向量反向 /// /// /// [Obsolete("方法已过时,请使用API中方法XYZ.Negate()")] //ls 2015-08-15 public static XYZ Revert(this XYZ vec) { return -vec; } /// /// 两向量垂直 /// /// /// /// public static bool IsVertical(this XYZ vec1, XYZ vec2, double tolerance = 0.0) { return vec1.DotProduct(vec2).IsEqual(0.0, tolerance); } /// /// 两向量平行 /// /// /// /// public static bool IsParallel(this XYZ vec1, XYZ vec2, double tolerance = 0) { return vec1.Normalize().IsEqual(vec2.Normalize(), tolerance) || vec1.Normalize().IsEqual(vec2.Normalize().Negate(), tolerance); } /// /// 向量方向相同 /// /// /// /// public static bool IsSameDirection(this XYZ firstVec, XYZ secondVec) { //a.b = |a|*|b|*cos // get the unit vector for two vectors XYZ first = firstVec.Normalize(); XYZ second = secondVec.Normalize(); // if the dot product of two unit vectors is equal to 1, return true #region ls 2015-03-14注释 double dot = first.DotProduct(second); return (dot.IsEqual(1, 0.001)); #endregion //return firstVec.IsEqual(secondVec); } /// /// 向量方向相反 /// /// /// /// public static bool IsOppositeDirection(this XYZ firstVec, XYZ secondVec) { //a.b = |a|*|b|*cos // get the unit vector for two vectors XYZ first = firstVec.Normalize(); XYZ second = secondVec.Normalize(); // if the dot product of two unit vectors is equal to -1, return true double dot = first.DotProduct(second); return (dot.IsEqual(-1)); } /// /// 比较 /// /// /// /// /// 从起点开始 /// //public static int CompareTo(this XYZ first, XYZ second, Curve curve, bool blnStart) //{ // if (!blnStart) // { // curve = curve.Reverse(); // } // if (curve.IsLine()) // { // Line line = curve.GetLine(); // double xDist = line.StartPoint().FindDistance2(first); // double yDist = line.StartPoint().FindDistance2(second); // if (xDist.IsEqual(yDist)) // { // return 0; // } // else // { // return xDist > yDist ? 1 : -1; // } // } // if (curve.IsLine()) // { // Line line = curve.GetLine(); // double xDist = line.StartPoint().FindDistance2(first); // double yDist = line.StartPoint().FindDistance2(second); // if (xDist.IsEqual(yDist)) // { // return 0; // } // else // { // return xDist > yDist ? 1 : -1; // } // } // return 0; //} public static int CompareTo(this XYZ first, XYZ second, Curve curve, bool blnStart) { if (!blnStart) { curve = curve.Reverse(); } if (curve.IsArc()) { Arc arc = curve.GetArc(); double startAngle = arc.GetStartAngle(first); double num2 = arc.GetStartAngle(second); if (startAngle.IsEqual(num2, 0.0)) { return 0; } if (startAngle <= num2) { return -1; } return 1; } if (!curve.IsLine()) { return 0; } Line line = curve.GetLine(); double num3 = line.StartPoint().FindDistance2(first); double num4 = line.StartPoint().FindDistance2(second); if (num3.IsEqual(num4, 0.0)) { return 0; } if (num3 <= num4) { return -1; } return 1; } /// /// 向量过一点的直线 /// /// /// /// /// /// public static Line VectorToLine(this XYZ vec, XYZ pt, double d, bool blnMid = false) { if (blnMid) { return Line.CreateBound(pt - vec*d, pt + vec*d); } else { return Line.CreateBound(pt, pt + vec*d); } } /// /// 向量过一点的射线 /// /// /// /// public static Line VectorToLine(this XYZ vec, XYZ pt) { return Line.CreateUnbound(pt, vec); } /// /// 创建直线 /// /// /// /// /// /// public static Line PointToLine(this XYZ pt, XYZ vec, double d, bool blnMid = false) { return vec.VectorToLine(pt, d, blnMid); } /// /// 创建射线 /// /// /// /// public static Line PointToLine(this XYZ pt, XYZ vec) { return vec.VectorToLine(pt); } /// /// 参照十字线 /// /// /// /// public static List GetCorssLine(this XYZ pt, double dLen = 0) { ExternalDataWrapper wrapper = ExternalDataWrapper.Current; XYZ basisX = wrapper.ActiveView.RightDirection; XYZ basisY = wrapper.ActiveView.UpDirection; XYZ basisZ = wrapper.ActiveView.ViewDirection; List listCurCross = new List(); if (dLen == 0) dLen = 100000d.ToApi(); Line line = basisX.VectorToLine(pt, dLen, true); DetailCurve detailLine = wrapper.Doc.Create.NewDetailCurve(wrapper.ActiveView, line); detailLine.SetLineStyle(SysLineStyles.LinesHiddenLines); listCurCross.Add(detailLine); line = basisY.VectorToLine(pt, dLen, true); detailLine = wrapper.Doc.Create.NewDetailCurve(wrapper.ActiveView, line); detailLine.SetLineStyle(SysLineStyles.LinesHiddenLines); listCurCross.Add(detailLine); wrapper.Doc.Regenerate(); return listCurCross; } /// /// 项目中用到的迹线 /// /// /// /// public static List NewTraceLine(this XYZ first, XYZ second) { List listCurCross = new List(); ExternalDataWrapper wrapper = ExternalDataWrapper.Current; Line line = Line.CreateBound(first, second); DetailCurve detailLine = wrapper.Doc.Create.NewDetailCurve(wrapper.ActiveView, line); detailLine.SetLineStyle(SysLineStyles.LinesHiddenLines); listCurCross.Add(detailLine); wrapper.Doc.Regenerate(); return listCurCross; } /// /// 根据两顶点获取矩形 wzc /// /// 最大坐标顶点 /// 最小坐标顶点 /// public static List GetRectange(this XYZ maxb, XYZ minb) { Line l1 = Line.CreateBound(maxb.NewX(minb.X), maxb); //上 Line l2 = Line.CreateBound(maxb, maxb.NewY(minb.Y)); //右 Line l3 = Line.CreateBound(maxb.NewY(minb.Y), minb.NewZ(maxb.Z)); //下 Line l4 = Line.CreateBound(minb.NewZ(maxb.Z), maxb.NewX(minb.X)); //左 List lines = new List(); lines.Add(l1); lines.Add(l2); lines.Add(l3); lines.Add(l4); return lines; } /// /// 是否为曲线的端点 /// /// /// /// /// public static bool IsEndPoint(this XYZ pt, Curve curve, double tolerance = 0) { return pt.IsEqual(curve.StartPoint(), tolerance) || pt.IsEqual(curve.EndPoint(), tolerance); } /// /// 按逆时针排序点集(未考虑Z方向) /// /// public static void SortAnticlockwise(this List ptList) { XYZ center = new XYZ(); double x = 0, y = 0, z = 0; for (int i = 0; i < ptList.Count; i++) { x += ptList[i].X; y += ptList[i].Y; z += ptList[i].Z; } double mx = x / ptList.Count; double my = y / ptList.Count; double mz = z / ptList.Count; center = new XYZ(mx, my, mz); for (int i = 0; i < ptList.Count - 1; i++) { for (int j = 0; j < ptList.Count - i - 1; j++) { if (PointCmp(ptList[j], ptList[j + 1], center)) { XYZ tmp = ptList[j]; ptList[j] = ptList[j + 1]; ptList[j + 1] = tmp; } } } } /// /// 若a大于点b,即点a在b顺时针方向 ,返回true,否则false /// 为SortAnticlockwise方法调用 /// /// /// /// /// private static bool PointCmp(XYZ a, XYZ b, XYZ center) { if (a.X >= 0 && b.X < 0) return true; if (a.X == 0 && b.X == 0) return a.Y > b.Y; //向量OA和OB的叉积 double det = ((a.X - center.X) * (b.Y - center.Y) - (b.X - center.X) * (a.Y - center.Y)); if (det < 0) return true; if (det > 0) return false; //向量OA和向量OB共线,以距离判断大小 double d1 = (a.X - center.X) * (a.X - center.X) + (a.Y - center.Y) * (a.Y - center.Y); double d2 = (b.X - center.X) * (b.X - center.X) + (b.Y - center.Y) * (b.Y - center.Y); return d1 > d2; } /// /// 矢量的象限角0到2Pi /// /// /// /// /// public static double QuadrantAngle(this XYZ vec, XYZ xAxis, XYZ normal) { double num = xAxis.AngleOnPlaneTo(vec, normal); if (num.IsEqual(6.2831853071795862, 0.0)) { num = 0.0; } return num; } /// /// 点是否在线上 /// /// /// /// /// public static bool IsInLine(this XYZ pt, Line line, double tolerance = 0.0) { return line.IsContain(pt, tolerance); } /// /// 判断点是否在多边形内 /// /// /// /// public static bool PointInPolygon(this XYZ pt, IList listProfile) { var flag = true; //if (!pt.PointInPoly1(listProfile)) //{ // flag = pt.PointInPoly2(listProfile.ToList()); //} //点在边框上,也要判定为在多边形内部 flag = pt.PointInPolygonByRay(listProfile.OfType().ToList())>=0; return flag; } /// /// 判断点是否在多边形中 ljy /// 此方法李林提供,好象也不准确与PointInPoly2一起使用 /// /// /// /// private static bool PointInPoly1(this XYZ pt, IList listProfile) { try { List listPoints = new List(); foreach (Curve curve in listProfile) { XYZ xyz = curve.StartPoint(); XYZ xyz2 = curve.EndPoint(); if (!xyz.ExsitsInlist(listPoints, 0.0)) { listPoints.Add(xyz); } if (!xyz2.ExsitsInlist(listPoints, 0.0)) { listPoints.Add(xyz2); } } double num = 0.0; int count = listPoints.Count; for (int i = 0; i < count; i++) { XYZ xyz3 = listPoints[i]; XYZ xyz4 = listPoints[(i + 1) % count]; XYZ xyz5 = xyz3 - pt; XYZ source = xyz4 - pt; double length = xyz5.GetLength(); double num5 = source.GetLength(); if ((length * num5).IsEqual(0.0, 0.0)) { return true; } double d = xyz5.DotProduct(source) / (length * num5); num += Math.Acos(d); } return num.IsEqual(6.2831853071795862, 0.0); } catch { return false; } } /// /// 判断点是否在多边形内(水平射线法) /// 此方法网上提供,好象也不准确与PointInPoly1一起使用 /// /// /// /// public static bool PointInPoly2(this XYZ pt, List curveList) { Line line = Line.CreateUnbound(pt, new XYZ(-1.0, 0.0, 0.0)); int num = 0; List dList = new List(); curveList.ForEach(delegate (Curve p) { dList.Add(p.StartPoint().Y); dList.Add(p.EndPoint().Y); }); foreach (Curve curve in curveList) { if (!curve.StartPoint().Y.IsEqual(curve.EndPoint().Y, 0.0) && curve.IsIntersection(line, 0.0)) { XYZ xyz = curve.GetIntersections(line, 0.0)[0]; if (xyz.X <= pt.X) { double num2 = Math.Min(curve.StartPoint().Y, curve.EndPoint().Y); Math.Max(curve.StartPoint().Y, curve.EndPoint().Y); if ((!xyz.Y.IsEqual(((IEnumerable)dList).Max(), 0.0) && !xyz.Y.IsEqual(((IEnumerable)dList).Min(), 0.0)) && (xyz.Y != num2)) { num++; } } } } if ((num % 2) == 0) { return false; } return true; } /// /// 通过射线法判断点是否在封闭区域内 /// /// /// /// /// 如果点在多边形内: 返回1 /// 如果点在多边形边上: 返回0 /// 如果点在多边形外: 返回-1 /// public static int PointInPolygonByRay(this XYZ inputPoint, List lines) { #region 描述 /* * 判断点是否在直线所围成的区域内; * 结果三种,-1,在外侧;0,在边上,1,在多边形内 * 判断焦点奇偶 * 如果交点是线段的端点,则记录这个点的信息,同一个交点算一次焦点。 * 如果线段恰巧和射线共线,如果点在射线中,则记录一个点。否则该记录几个点,就记录几个点; * 这个不考虑阿拉伯数字⑧字形这种种,轮廓线有非端点相交情况,这种情况需要记录焦点的具体值 */ #endregion //以给定点,向x正方向做射线 //线段端点在射线上的集合 //List points = new List(); List groups = new List(); //默认是偶数 bool isEven = true; double baseX = inputPoint.X; double baseY = inputPoint.Y; foreach (var line in lines) { var start = line.StartPoint(); var end = line.EndPoint(); if (start.IsEqual(inputPoint) || end.IsEqual(inputPoint)) { return 0; } //判断给定线的端点是否在射线两侧,利用水平线的性质 if ((start.Y.IsLessEq(baseY) && baseY.IsLessEq(end.Y)) || (end.Y.IsLessEq(baseY) && baseY.IsLessEq(start.Y))) { double minX = Math.Min(start.X, end.X); double maxX = Math.Min(start.X, end.X); if (start.Y.IsEqual(end.Y)) { #region 与给定射线共线处理 //给定线段与射线平行 if (minX.IsLessEq(baseX) && baseX.IsLessEq(maxX)) { return 0; } else if (baseX.IsLess(minX)) { PointGroup.AddGroup(groups, new PointGroup() { start, end }); } #endregion } else if (baseX.IsLessEq(maxX)) { //当给定线,小于等于线最大坐标时,才有可能相交 /* * p1(x1,x2) vecter(xv,yv) * x1+xv*c=x * y1+yv*c=y * 求出c,带入公式1 */ double c = (baseY - start.Y) / (end.Y - start.Y); double useX = start.X + c * (end.X - start.X); if (useX.IsEqual(baseX)) { //给定点,在线上 return 0; } if (baseX.IsLessEq(useX)) { //这种情况下肯定相交 var intersectionPoint = new XYZ(useX, baseY,0); if (start.IsEqual(intersectionPoint)) { PointGroup.AddGroup(groups, new PointGroup() { start }); } else if (end.IsEqual(intersectionPoint)) { PointGroup.AddGroup(groups, new PointGroup() { end }); } else { isEven = !isEven; } } } } } //整理通过的端点 if (groups.Any()) { foreach (var group in groups) { var usePoint = group.FirstOrDefault(); var refLines = lines.Where(l => LineUtil.GetPosition(l, usePoint) != -1).ToList(); if (refLines.Count < 2) { continue; } List results = new List(); foreach (Line line in refLines) { List useLines = new List(lines); useLines.Remove(line); var extendPoint = LineUtil.GetFirstPoint(useLines, usePoint, p => !p.Y.IsEqual(usePoint.Y)); results.Add(extendPoint.Y); } if (results[0].IsLess(baseY) == results[1].IsThan(baseY)) { if (!results[0].IsEqual(baseY) && !results[1].IsEqual(baseY)) { isEven = !isEven; } } } } return isEven ? -1 : 1; } /// /// 通过射线法判断点是否在封闭区域内 /// /// /// /// /// 如果点在多边形内: 返回1 /// 如果点在多边形边上: 返回0 /// 如果点在多边形外: 返回-1 /// public static int PointInPolygonByRay(this XYZ inputPoint, List points) { #region 老方法 //List lines = new List(); //for (int i = 0; i < points.Count; i++) //{ // var start = points[i]; // var end = points[(i + 1) % points.Count]; // lines.Add(Line.CreateBound(start, end)); //} //return PointInPolygonByRay(inputPoint, lines); #endregion bool isEven = true; double baseX = inputPoint.X; double baseY = inputPoint.Y; var total = points.Count; for (int i = 0; i < total; i++) { var endIndex = (i + 1) % total; var start = points[i]; var end = points[endIndex]; if (start.IsEqual2(inputPoint) || end.IsEqual2(inputPoint)) { return 0; } bool isEndIntersection = false;//判断交点是否是end //判断给定线的端点是否在射线两侧,利用水平线的性质 if ((start.Y.IsLessEq(baseY) && baseY.IsLessEq(end.Y)) || (end.Y.IsLessEq(baseY) && baseY.IsLessEq(start.Y))) { double minX = Math.Min(start.X, end.X); double maxX = Math.Min(start.X, end.X); if (start.Y.IsEqual(end.Y)) { #region 与给定射线共线处理 //给定线段与射线平行 if (minX.IsLessEq(baseX) && baseX.IsLessEq(maxX)) { return 0; } else if (baseX.IsLess(minX)) { isEndIntersection = true; } #endregion } else if (baseX.IsLessEq(maxX)) { double c = (baseY - start.Y) / (end.Y - start.Y); double useX = start.X + c * (end.X - start.X); if (useX.IsEqual(baseX)) { //给定点,在线上 return 0; } if (baseX.IsLessEq(useX)) { //这种情况下肯定相交 var intersectionPoint = new XYZ(useX, baseY,0); if (end.IsEqual2(intersectionPoint)) { //开始点不处理 isEndIntersection = true; } else if (start.IsEqual2(intersectionPoint)) { isEndIntersection = false; } else { isEven = !isEven; } } } if (isEndIntersection) { var end2 = points[(endIndex + 1) % total]; if (!baseY.IsEqual(end2.Y)) { var point = points.GetFirstElement(endIndex, p => !p.Y.IsEqual(baseY), false); if (end2.Y.IsLess(baseY) == point.Y.IsThan(baseY)) { //排除同时相等的情况 if (!end2.Y.IsEqual(baseY) && !point.Y.IsEqual(baseY)) { isEven = !isEven; } } } } } } return isEven ? -1 : 1; } } }