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