1332 lines
43 KiB
C#
1332 lines
43 KiB
C#
using Autodesk.Revit.DB;
|
||
|
||
using ShrlAlgoToolkit.Revit.Assists;
|
||
|
||
namespace ShrlAlgoToolkit.Revit.Assists;
|
||
|
||
public static class SpatialExtensions
|
||
{
|
||
/// <summary>
|
||
/// 容差
|
||
/// </summary>
|
||
private const double VbTolerance = 10E-9;
|
||
|
||
|
||
/// <summary>
|
||
///
|
||
/// </summary>
|
||
/// <typeparam name="T"></typeparam>
|
||
/// <param name="geoObject"></param>
|
||
/// <returns></returns>
|
||
private static List<T> GetGeoObjects<T>(this GeometryObject geoObject)
|
||
where T : GeometryObject
|
||
{
|
||
List<T> geometryObjects = [];
|
||
|
||
if (geoObject is Solid instSolid)
|
||
{
|
||
if (typeof(T) == typeof(Solid))
|
||
{
|
||
geometryObjects.Add(instSolid as T);
|
||
}
|
||
if (typeof(T) == typeof(Face) && instSolid.Faces.Size > 0)
|
||
{
|
||
geometryObjects.AddRange(instSolid.Faces.Cast<T>());
|
||
}
|
||
else if (typeof(T) == typeof(Edge) && instSolid.Edges.Size > 0)
|
||
{
|
||
geometryObjects.AddRange(instSolid.Edges.Cast<T>());
|
||
}
|
||
}
|
||
|
||
return geometryObjects;
|
||
}
|
||
|
||
public static XYZ ProjectOnPlane(this XYZ q, Plane plane)
|
||
{
|
||
//The projection of a point q = (x, y, z) onto a plane given by a point p = (a, b, c) and a normal n = (d1, e, f) is
|
||
// q_proj = q - dot(q - p, n) * n
|
||
|
||
var p = plane.Origin;
|
||
var n = plane.Normal.Normalize();
|
||
var qProj = q - n.Multiply(n.DotProduct(q - p));
|
||
|
||
return qProj;
|
||
}
|
||
|
||
|
||
/// <summary>创建一个新的实体,它是输入实体的副本</summary>
|
||
/// <param name="solid">要复制的输入实体</param>
|
||
/// <returns>新的实体</returns>
|
||
public static Solid Clone(this Solid solid)
|
||
{
|
||
return SolidUtils.Clone(solid);
|
||
}
|
||
|
||
/// <summary>创建一个新的实体,它是输入实体的转换</summary>
|
||
/// <param name="solid">要转换的输入实体</param>
|
||
/// <param name="transform">变换(必须是保角变换)</param>
|
||
/// <returns>新的实体</returns>
|
||
/// <exception cref="Command:Autodesk.Revit.Exceptions.ArgumentOutOfRangeException">
|
||
/// 变换不保形。
|
||
/// 或变换的比例为负或零
|
||
/// </exception>
|
||
public static Solid CreateTransformed(this Solid solid, Transform transform)
|
||
{
|
||
return SolidUtils.CreateTransformed(solid, transform);
|
||
}
|
||
/// <summary>
|
||
/// 直线间距离,无边界的情况
|
||
/// </summary>
|
||
/// <param name="line1"></param>
|
||
/// <param name="line2"></param>
|
||
/// <returns></returns>
|
||
public static double Distance(this Line line1, Line line2)
|
||
{
|
||
double distance;
|
||
|
||
var v1 = line1.Direction;
|
||
var p1 = line1.GetEndPoint(0);
|
||
var v2 = line2.Direction;
|
||
var p2 = line2.GetEndPoint(0);
|
||
|
||
var a = p1.X - p2.X;
|
||
var b = p1.Y - p2.Y;
|
||
var c = p1.Z - p2.Z;
|
||
var pq = (v1.X * v2.Y) - (v2.X * v1.Y);
|
||
var qr = (v1.Y * v2.Z) - (v2.Y * v1.Z);
|
||
var rp = (v1.Z * v2.X) - (v2.Z * v1.X);
|
||
var dev = Math.Sqrt(Math.Pow(qr, 2) + Math.Pow(rp, 2) + Math.Pow(pq, 2));
|
||
|
||
if (dev < 1e-9)
|
||
{
|
||
var bp = b * v1.X;
|
||
var br = b * v1.Z;
|
||
var cp = c * v1.X;
|
||
var cq = c * v1.Y;
|
||
var aq = a * v1.Y;
|
||
var ar = a * v1.Z;
|
||
distance =
|
||
Math.Sqrt(Math.Pow(br - cq, 2) + Math.Pow(cp - ar, 2) + Math.Pow(aq - bp, 2))
|
||
/ Math.Sqrt(Math.Pow(v1.X, 2) + Math.Pow(v1.Y, 2) + Math.Pow(v1.Z, 2));
|
||
}
|
||
else
|
||
{
|
||
distance = Math.Abs(((qr * a) + (rp * b) + (pq * c)) / dev);
|
||
}
|
||
|
||
return distance;
|
||
}
|
||
|
||
public static List<XYZ> DrawMesh(this Sweep sweep)
|
||
{
|
||
Options option = new() { ComputeReferences = true, DetailLevel = ViewDetailLevel.Fine };
|
||
var geomElement = sweep.get_Geometry(option);
|
||
List<XYZ> triangularPoints = [];
|
||
foreach (var geomObj in geomElement)
|
||
{
|
||
if (geomObj is Solid geomSolid)
|
||
{
|
||
foreach (Face geomFace in geomSolid.Faces)
|
||
{
|
||
var mesh = geomFace.Triangulate();
|
||
|
||
for (var i = 0; i < mesh.NumTriangles; i++)
|
||
{
|
||
var triangular = mesh.get_Triangle(i);
|
||
for (var n = 0; n < 3; n++)
|
||
{
|
||
var point = triangular.get_Vertex(n);
|
||
triangularPoints.Add(point);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return triangularPoints;
|
||
}
|
||
/// <summary>
|
||
/// 扩展包围盒的大小
|
||
/// </summary>
|
||
/// <param name="boundingBox"></param>
|
||
/// <param name="distance"></param>
|
||
/// <returns></returns>
|
||
public static BoundingBoxXYZ Extend(this BoundingBoxXYZ boundingBox, double distance = 2.0)
|
||
{
|
||
var transform = boundingBox.Transform;
|
||
var max = boundingBox.Max + distance * (transform.BasisX + transform.BasisY + transform.BasisZ);
|
||
var min = boundingBox.Min - distance * (transform.BasisX + transform.BasisY + transform.BasisZ);
|
||
return new BoundingBoxXYZ() { Max = max, Min = min, Transform = transform };
|
||
}
|
||
|
||
/// <summary>
|
||
/// 延长直线
|
||
/// </summary>
|
||
/// <param name="line"></param>
|
||
/// <param name="distance"></param>
|
||
/// <param name="isInteractive">是否双向延申,单向延长终点</param>
|
||
/// <returns></returns>
|
||
public static Line ExtendLine(this Line line, double distance, bool isInteractive = false)
|
||
{
|
||
var endPoint = line.GetEndPoint(1) + (line.Direction * distance);
|
||
var startPoint = line.GetEndPoint(0);
|
||
if (isInteractive)
|
||
{
|
||
startPoint += line.Direction.Negate() * distance;
|
||
}
|
||
|
||
return Line.CreateBound(startPoint, endPoint);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 延长或缩短直线
|
||
/// </summary>
|
||
/// <param name="line"></param>
|
||
/// <param name="endPoint"></param>
|
||
/// <param name="startSection">点在直线内时,保留部分,为null时,保留长的部分</param>
|
||
/// <returns></returns>
|
||
public static Line ExtendLine(this Line line, XYZ endPoint, bool? startSection = null)
|
||
{
|
||
if (line == null)
|
||
{
|
||
throw new ArgumentNullException(nameof(line), "延长线为空!");
|
||
}
|
||
if (endPoint == null)
|
||
{
|
||
throw new ArgumentNullException(nameof(endPoint), "延长点为空!");
|
||
}
|
||
var v = endPoint - line.GetEndPoint(0);
|
||
var v2 = endPoint - line.GetEndPoint(1);
|
||
//点刚好是直线端点
|
||
if (v.IsZeroLength() || v2.IsZeroLength())
|
||
{
|
||
return line;
|
||
}
|
||
//必须平行才能延伸
|
||
|
||
if (v.IsParallelTo(v2))
|
||
{
|
||
//点在直线外,同方向
|
||
if (line.Direction.DotProduct(v) > 0.0 && line.Direction.DotProduct(v2) > 0.0)
|
||
{
|
||
return Line.CreateBound(line.GetEndPoint(0), endPoint);
|
||
}
|
||
//点在直线外,反方向
|
||
if (line.Direction.DotProduct(v) < 0.0 && line.Direction.DotProduct(v2) < 0.0)
|
||
{
|
||
return Line.CreateBound(endPoint, line.GetEndPoint(1));
|
||
}
|
||
//点在直线内
|
||
return v.DotProduct(v2) < 0.0
|
||
? startSection == null
|
||
? v.GetLength() >= v2.GetLength()
|
||
? Line.CreateBound(line.GetEndPoint(0), endPoint)
|
||
: Line.CreateBound(endPoint, line.GetEndPoint(1))
|
||
: startSection == true
|
||
? Line.CreateBound(line.GetEndPoint(0), endPoint)
|
||
: Line.CreateBound(endPoint, line.GetEndPoint(1))
|
||
: null;
|
||
}
|
||
|
||
return line;
|
||
//throw new InvalidOperationException("不可延伸到该点");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 重心,质心
|
||
/// </summary>
|
||
/// <param name="points"></param>
|
||
/// <returns></returns>
|
||
public static XYZ GetCentroid(this List<XYZ> points)
|
||
{
|
||
var sourceX = from XYZ point in points select point.X;
|
||
var sourceY = from XYZ point in points select point.Y;
|
||
var sourceZ = from XYZ point in points select point.Z;
|
||
var count = points.Count;
|
||
var x = sourceX.Sum() / count;
|
||
var y = sourceY.Sum() / count;
|
||
var z = sourceZ.Sum() / count;
|
||
return new XYZ(x, y, z);
|
||
}
|
||
public static HermiteSpline ConverToHermiteSpline(this PolyLine polyLine)
|
||
{
|
||
var list = polyLine.GetCoordinates();
|
||
return HermiteSpline.Create(list, false);
|
||
}
|
||
/// <summary>
|
||
/// 将几何实例的实例集合的PolyLine的线条转换成曲线组
|
||
/// </summary>
|
||
/// <param name="geometryObjects"></param>
|
||
/// <returns></returns>
|
||
public static List<CurveArray> GetCurveArray(IEnumerable<GeometryObject> geometryObjects)
|
||
{
|
||
List<CurveArray> curves = [];
|
||
foreach (var geo in geometryObjects)
|
||
{
|
||
CurveArray lines = new();
|
||
|
||
if (geo is not PolyLine pl)
|
||
{
|
||
return curves;
|
||
}
|
||
var points = pl.GetCoordinates();
|
||
|
||
var n = 0;
|
||
for (var i = 0; i < points.Count - 1; i++)
|
||
{
|
||
var dis = points[i].DistanceTo(points[points.Count - 1]);
|
||
if (dis < 1 / 304.8) //重叠线段长度精度大于1mm,排除掉起点
|
||
{
|
||
n = i;
|
||
}
|
||
}
|
||
|
||
var pts = points.Skip(n).ToList();
|
||
|
||
var p0 = pts[0] - (pts[0].Z * XYZ.BasisZ);
|
||
for (var i = 0; i < pts.Count - 1; i++)
|
||
{
|
||
var p1 = pts[i] - (pts[i].Z * XYZ.BasisZ);
|
||
var p2 = pts[i + 1] - (pts[i + 1].Z * XYZ.BasisZ);
|
||
if (i == pts.Count - 2 && !p2.IsAlmostEqualTo(p0))
|
||
{
|
||
p2 = p0;
|
||
}
|
||
|
||
var l = Line.CreateBound(p1, p2);
|
||
lines.Append(l);
|
||
}
|
||
|
||
curves.Add(lines);
|
||
}
|
||
|
||
return curves;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取所有线的交点
|
||
/// </summary>
|
||
/// <param name="curves"></param>
|
||
/// <returns></returns>
|
||
public static List<XYZ> GetCurvesIntersect(List<Curve> curves)
|
||
{
|
||
List<XYZ> points = [];
|
||
foreach (var grid in curves)
|
||
{
|
||
foreach (var grd in curves)
|
||
{
|
||
grid.Intersect(grd, out var ira);
|
||
if (ira != null)
|
||
{
|
||
var ir = ira.get_Item(0);
|
||
// 判断点是否重复
|
||
foreach (var p in points)
|
||
{
|
||
if (!p.IsAlmostEqualTo(ir.XYZPoint))
|
||
{
|
||
points.Add(ir.XYZPoint);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return points;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取平面的边
|
||
/// </summary>
|
||
/// <param name="face"></param>
|
||
/// <returns></returns>
|
||
public static List<Edge> GetEdges(this PlanarFace face)
|
||
{
|
||
List<Edge> list = [];
|
||
var edgeLoops = face.EdgeLoops;
|
||
foreach (var obj in edgeLoops)
|
||
{
|
||
var edgeArray = (EdgeArray)obj;
|
||
list.AddRange(edgeArray.Cast<Edge>());
|
||
}
|
||
|
||
return list;
|
||
}
|
||
|
||
public static ElementOrientation GetElementOrientation(this Curve curve)
|
||
{
|
||
var num = 0.0001;
|
||
var endPoint = curve.GetEndPoint(0);
|
||
var endPoint2 = curve.GetEndPoint(1);
|
||
var result = endPoint.IsAlmostEqualTo(endPoint2)
|
||
? ElementOrientation.Undefined
|
||
: Math.Abs(endPoint.X - endPoint2.X) < num && Math.Abs(endPoint.Y - endPoint2.Y) > num
|
||
? ElementOrientation.Vertical
|
||
: (Math.Abs(endPoint.X - endPoint2.X) > num && Math.Abs(endPoint.Y - endPoint2.Y) < num)
|
||
? ElementOrientation.Horizontal
|
||
: Math.Abs(endPoint2.X - endPoint.X) >= Math.Abs(endPoint2.Y - endPoint.Y)
|
||
? ElementOrientation.CloseToHorizontal
|
||
: ElementOrientation.CloseToVertical;
|
||
return result;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 端点
|
||
/// </summary>
|
||
/// <param name="curve"></param>
|
||
/// <returns></returns>
|
||
public static List<XYZ> GetEndPoints(this Curve curve)
|
||
{
|
||
return [curve.GetEndPoint(0), curve.GetEndPoint(1)];
|
||
}
|
||
|
||
/// <summary>
|
||
/// 根据等分量等分点曲线,得到所有分割点,含起终点
|
||
/// </summary>
|
||
/// <param name="curve"></param>
|
||
/// <param name="num">等分量</param>
|
||
/// <returns></returns>
|
||
public static List<XYZ> GetEquivalentPoints(this Curve curve, int num)
|
||
{
|
||
List<XYZ> result = [];
|
||
if (num <= 0)
|
||
{
|
||
throw new ArgumentException("分段数错误");
|
||
}
|
||
|
||
for (var i = 0; i <= num; i++)
|
||
{
|
||
var parameter = (double)i / num;
|
||
var p = curve.Evaluate(parameter, true);
|
||
result.Add(p);
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
///// <summary>
|
||
///// 步长划分线,含起终点
|
||
///// </summary>
|
||
///// <param name="curve"></param>
|
||
///// <param name="step"></param>
|
||
///// <returns></returns>
|
||
//public static IEnumerable<XYZ> Divide(this Curve curve, double step)
|
||
//{
|
||
// if (curve.Length > step)
|
||
// {
|
||
// double startParameter = curve.GetEndParameter(0);
|
||
// double endParameter = curve.GetEndParameter(1);
|
||
// double parameterStep = (endParameter - startParameter) / (curve.Length / step);
|
||
// double parameterSum = startParameter;
|
||
// do
|
||
// {
|
||
// yield return curve.Evaluate(parameterSum, false);
|
||
// parameterSum += parameterStep;
|
||
// } while (parameterSum < endParameter);
|
||
|
||
// if (Math.Abs(parameterSum - endParameter) > 0.0001)
|
||
// {
|
||
// yield return curve.GetEndPoint(1);
|
||
// }
|
||
// }
|
||
// else
|
||
// {
|
||
// yield return curve.GetEndPoint(0);
|
||
// yield return curve.GetEndPoint(1);
|
||
// }
|
||
//}
|
||
/// <summary>
|
||
/// 根据等距离量分割曲线,得到所有分割点,含起点,不含终点
|
||
/// </summary>
|
||
/// <param name="curve"></param>
|
||
/// <param name="step">等距离量</param>
|
||
/// <returns></returns>
|
||
public static List<XYZ> GetEquivalentPoints(this Curve curve, double step)
|
||
{
|
||
List<XYZ> result = [];
|
||
var num = Math.Floor(curve.Length / step);
|
||
for (var i = 0; i <= num; i++)
|
||
{
|
||
if (curve.IsInside(step * i))
|
||
{
|
||
var p = curve.Evaluate(step * i, true);
|
||
result.Add(p);
|
||
}
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取最远的两个点的扩展方法
|
||
/// </summary>
|
||
/// <param name="points"></param>
|
||
/// <returns></returns>
|
||
public static Tuple<XYZ, XYZ> GetFurthestPoints(this IList<XYZ> points)
|
||
{
|
||
Tuple<XYZ, XYZ> result = default;
|
||
var dist = double.NaN;
|
||
for (var i = 0; i < points.Count; i++)
|
||
{
|
||
var pt1 = points[i];
|
||
for (var j = 0; j < points.Count; j++)
|
||
{
|
||
if (i == j)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
var pt2 = points[j];
|
||
var d = pt1.DistanceTo(pt2);
|
||
if (double.IsNaN(dist) || d > dist)
|
||
{
|
||
result = new Tuple<XYZ, XYZ>(pt1, pt2);
|
||
dist = d;
|
||
}
|
||
}
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取几何对象,嵌套一次
|
||
/// </summary>
|
||
/// <typeparam name="T">对应类型的几何对象,如Solid、Face、Edge</typeparam>
|
||
/// <param name="elem">获取的元素</param>
|
||
/// <returns></returns>
|
||
public static List<T> GetAllGeometryObjects<T>(this Element elem)
|
||
where T : GeometryObject
|
||
{
|
||
List<T> geometryObjects = [];
|
||
Options option = new() { ComputeReferences = true, DetailLevel = ViewDetailLevel.Fine };
|
||
var geometry = elem.get_Geometry(option);
|
||
|
||
foreach (var geomObj in geometry)
|
||
{
|
||
if (geomObj is GeometryInstance geomInstance)
|
||
{
|
||
var usesSymbolGeometry = elem is FamilyInstance instance && !instance.HasModifiedGeometry();
|
||
var geometryElement = usesSymbolGeometry ? geomInstance.GetSymbolGeometry() : geomInstance.GetInstanceGeometry();
|
||
|
||
foreach (var geoObject in geometryElement)
|
||
{
|
||
geometryObjects.AddRange(geoObject.GetGeoObjects<T>());
|
||
}
|
||
}
|
||
else
|
||
{
|
||
geometryObjects.AddRange(geomObj.GetGeoObjects<T>());
|
||
}
|
||
}
|
||
|
||
return geometryObjects;
|
||
}
|
||
/// <summary>
|
||
/// 获取顶层的几何(非嵌套)
|
||
/// </summary>
|
||
/// <typeparam name="T"></typeparam>
|
||
/// <param name="elem"></param>
|
||
/// <returns></returns>
|
||
public static List<GeometryObject> GetGeometryObjects(this Element elem)
|
||
{
|
||
List<GeometryObject> geometryObjects = [];
|
||
Options option = new() { ComputeReferences = true, DetailLevel = ViewDetailLevel.Fine };
|
||
var geometry = elem.get_Geometry(option);
|
||
|
||
foreach (var geomObj in geometry)
|
||
{
|
||
geometryObjects.Add(geomObj);
|
||
}
|
||
|
||
return geometryObjects;
|
||
}
|
||
/// <summary>
|
||
/// 求面和线的交点
|
||
/// </summary>
|
||
/// <param name="face"></param>
|
||
/// <param name="curve"></param>
|
||
/// <returns></returns>
|
||
public static XYZ GetIntersectPoint(this Face face, Curve curve)
|
||
{
|
||
//求交点
|
||
XYZ intersection = null;
|
||
var setComparisonResult = face.Intersect(curve, out var resultArray);
|
||
if (SetComparisonResult.Disjoint != setComparisonResult)
|
||
{
|
||
if (!resultArray.IsEmpty)
|
||
{
|
||
intersection = resultArray.get_Item(0).XYZPoint;
|
||
}
|
||
}
|
||
|
||
return intersection;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取元素定位线
|
||
/// </summary>
|
||
/// <param name="instance">以点定位的实例</param>
|
||
/// <returns></returns>
|
||
public static Curve GetCurve(this Element instance)
|
||
{
|
||
return instance.Location is LocationCurve lc ? lc.Curve : null;
|
||
}
|
||
/// <summary>
|
||
/// 获取元素定位线
|
||
/// </summary>
|
||
/// <param name="instance">以点定位的实例</param>
|
||
/// <returns></returns>
|
||
public static LocationCurve GetLocationCurve(this Element instance)
|
||
{
|
||
return instance.Location is LocationCurve lc ? lc : null;
|
||
}
|
||
/// <summary>
|
||
/// 获取元素定位线
|
||
/// </summary>
|
||
/// <param name="instance">以点定位的实例</param>
|
||
/// <returns></returns>
|
||
public static LocationPoint GetLocationPoint(this Element instance)
|
||
{
|
||
return instance.Location is LocationPoint lp ? lp : null;
|
||
}
|
||
/// <summary>
|
||
/// 获取元素定位点
|
||
/// </summary>
|
||
/// <param name="instance">以点定位的实例</param>
|
||
/// <returns></returns>
|
||
public static XYZ GetLocXYZ(this Element instance)
|
||
{
|
||
return instance.Location is LocationPoint lp ? lp.Point : null;
|
||
}
|
||
|
||
public static double GetMaxX(this PlanarFace face)
|
||
{
|
||
List<XYZ> list = [];
|
||
var edgeLoops = face.EdgeLoops;
|
||
foreach (EdgeArray edgeArray in edgeLoops)
|
||
{
|
||
foreach (Edge edge in edgeArray)
|
||
{
|
||
list.Add(edge.AsCurve().GetEndPoint(0));
|
||
list.Add(edge.AsCurve().GetEndPoint(1));
|
||
}
|
||
}
|
||
|
||
list.Sort((p1, p2) => p1.X.CompareTo(p2.X));
|
||
return list.Last().X;
|
||
}
|
||
|
||
public static double GetMaxY(this PlanarFace face)
|
||
{
|
||
List<XYZ> list = [];
|
||
var edgeLoops = face.EdgeLoops;
|
||
foreach (EdgeArray edgeArray in edgeLoops)
|
||
{
|
||
foreach (Edge edge in edgeArray)
|
||
{
|
||
list.Add(edge.AsCurve().GetEndPoint(0));
|
||
list.Add(edge.AsCurve().GetEndPoint(1));
|
||
}
|
||
}
|
||
|
||
list.Sort((p1, p2) => p1.Y.CompareTo(p2.Y));
|
||
return list.Last().Y;
|
||
}
|
||
|
||
public static double GetMaxZ(this PlanarFace face)
|
||
{
|
||
List<XYZ> list = [];
|
||
var edgeLoops = face.EdgeLoops;
|
||
foreach (EdgeArray edgeArray in edgeLoops)
|
||
{
|
||
foreach (Edge edge in edgeArray)
|
||
{
|
||
list.Add(edge.AsCurve().GetEndPoint(0));
|
||
list.Add(edge.AsCurve().GetEndPoint(1));
|
||
}
|
||
}
|
||
|
||
list.Sort((p1, p2) => p1.Z.CompareTo(p2.Z));
|
||
return list.Last().Z;
|
||
}
|
||
|
||
public static double GetMinX(this PlanarFace face)
|
||
{
|
||
List<XYZ> list = [];
|
||
var edgeLoops = face.EdgeLoops;
|
||
foreach (EdgeArray edgeArray in edgeLoops)
|
||
{
|
||
foreach (Edge edge in edgeArray)
|
||
{
|
||
list.Add(edge.AsCurve().GetEndPoint(0));
|
||
list.Add(edge.AsCurve().GetEndPoint(1));
|
||
}
|
||
}
|
||
|
||
list.Sort((p1, p2) => p1.X.CompareTo(p2.X));
|
||
return list.Last().X;
|
||
}
|
||
|
||
public static double GetMinY(this PlanarFace face)
|
||
{
|
||
List<XYZ> list = [];
|
||
var edgeLoops = face.EdgeLoops;
|
||
foreach (EdgeArray edgeArray in edgeLoops)
|
||
{
|
||
foreach (var obj2 in edgeArray)
|
||
{
|
||
var edge = (Edge)obj2;
|
||
list.Add(edge.AsCurve().GetEndPoint(0));
|
||
list.Add(edge.AsCurve().GetEndPoint(1));
|
||
}
|
||
}
|
||
|
||
list.Sort((p1, p2) => p1.Y.CompareTo(p2.Y));
|
||
return list.First().Y;
|
||
}
|
||
|
||
public static double GetMinZ(this PlanarFace face)
|
||
{
|
||
List<XYZ> list = [];
|
||
var edgeLoops = face.EdgeLoops;
|
||
foreach (EdgeArray edgeArray in edgeLoops)
|
||
{
|
||
foreach (Edge edge in edgeArray)
|
||
{
|
||
list.Add(edge.AsCurve().GetEndPoint(0));
|
||
list.Add(edge.AsCurve().GetEndPoint(1));
|
||
}
|
||
}
|
||
|
||
list.Sort((p1, p2) => p1.Z.CompareTo(p2.Z));
|
||
return list.Last().Z;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 两条异面直线的公垂线(两直线距离长度最短)与异面直线的交点(示例:管线碰撞翻弯)
|
||
/// </summary>
|
||
/// <param name="line1"></param>
|
||
/// <param name="line2"></param>
|
||
/// <returns></returns>
|
||
public static Dictionary<Line, XYZ> GetNearestPoints(this Line line1, Line line2)
|
||
{
|
||
Dictionary<Line, XYZ> dictionary = [];
|
||
var a = line1.Direction.DotProduct(line2.Direction);
|
||
var b = line1.Direction.DotProduct(line1.Direction);
|
||
var c = line2.Direction.DotProduct(line2.Direction);
|
||
|
||
var d = (line2.GetEndPoint(0) - line1.GetEndPoint(0)).DotProduct(line1.Direction);
|
||
var e = (line2.GetEndPoint(0) - line1.GetEndPoint(0)).DotProduct(line2.Direction);
|
||
double t1;
|
||
double t2;
|
||
if (a == 0) //表明原始两条直线互相垂直
|
||
{
|
||
t1 = d / b;
|
||
t2 = -e / c;
|
||
}
|
||
else if (Math.Abs((a * a) - (b * c)) < 0.0001f) //表明共线或平行,注意理想情况下应该是a * a - b * c == 0,才认为共线或平行,但在计算机世界里,有精度这个东西存在,所以我们近视的认为数值小于某一个值则认为等于0
|
||
{
|
||
//说明共线或平行
|
||
return dictionary;
|
||
}
|
||
else
|
||
{
|
||
t1 = ((a * e) - (c * d)) / ((a * a) - (b * c));
|
||
t2 = (b / a * t1) - (d / a);
|
||
}
|
||
|
||
var p1 = line1.GetEndPoint(0) + (t1 * line1.Direction);
|
||
var p2 = line2.GetEndPoint(0) + (t2 * line2.Direction);
|
||
dictionary.Add(line1, p1);
|
||
dictionary.Add(line2, p2);
|
||
return dictionary;
|
||
}
|
||
/// <summary>
|
||
/// 获取平行面分组
|
||
/// </summary>
|
||
/// <param name="faces"></param>
|
||
/// <param name="groups"></param>
|
||
public static void GetParallelFaceGroups(this List<Face> faces, List<List<Face>> groups)
|
||
{
|
||
var face = faces.FirstOrDefault();
|
||
faces = faces.FindAll(f => f is PlanarFace);
|
||
List<Face> group = [face];
|
||
groups.Add(group);
|
||
var pf = face as PlanarFace;
|
||
faces.Remove(face);
|
||
|
||
for (var i = faces.Count - 1; i >= 0; i--)
|
||
{
|
||
if (faces[i] is not PlanarFace)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
var tempFace = faces[i] as PlanarFace;
|
||
|
||
if (pf != null && tempFace != null && tempFace.FaceNormal.CrossProduct(pf.FaceNormal).IsAlmostEqualTo(XYZ.Zero))
|
||
{
|
||
group.Add(tempFace);
|
||
faces.Remove(tempFace);
|
||
|
||
//GetParallelFaceGroups(faces, tempFace, group, groups);
|
||
}
|
||
}
|
||
|
||
if (faces.Count >= 1)
|
||
{
|
||
GetParallelFaceGroups(faces, groups);
|
||
}
|
||
}
|
||
/// <summary>
|
||
/// 获取平行面
|
||
/// </summary>
|
||
/// <param name="faces"></param>
|
||
/// <param name="groups"></param>
|
||
public static void GetParallelFaces(this List<Face> faces, List<List<Face>> groups)
|
||
{
|
||
while (true)
|
||
{
|
||
var firstFace = faces.FirstOrDefault();
|
||
faces = faces.FindAll(face => face is PlanarFace);
|
||
List<Face> group = [firstFace];
|
||
groups.Add(group);
|
||
var pf = firstFace as PlanarFace;
|
||
faces.Remove(firstFace);
|
||
|
||
for (var i = faces.Count - 1; i >= 0; i--)
|
||
{
|
||
if (faces[i] is not PlanarFace)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
var tempFace = faces[i] as PlanarFace;
|
||
|
||
if (pf != null && tempFace != null && tempFace.FaceNormal.CrossProduct(pf.FaceNormal).IsAlmostEqualTo(XYZ.Zero))
|
||
{
|
||
group.Add(tempFace);
|
||
faces.Remove(tempFace);
|
||
|
||
//GetParallelFaces(faces, tempFace, group, groups);
|
||
}
|
||
}
|
||
|
||
if (faces.Count >= 1)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
break;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 递归找到所有长度相同的平行线集合
|
||
/// </summary>
|
||
public static void GetParallelLineGroups(List<Curve> lines, List<List<Curve>> groups)
|
||
{
|
||
while (true)
|
||
{
|
||
var firstLine = lines.FirstOrDefault();
|
||
lines = lines.FindAll(curve => curve is Line);
|
||
List<Curve> group = [firstLine];
|
||
groups.Add(group);
|
||
var line = firstLine as Line;
|
||
lines.Remove(firstLine);
|
||
|
||
for (var i = lines.Count - 1; i >= 0; i--)
|
||
{
|
||
if (lines[i] is Line tempLine)
|
||
{
|
||
if (
|
||
line != null
|
||
&& tempLine.Direction.CrossProduct(line.Direction).IsAlmostEqualTo(XYZ.Zero)
|
||
&& Math.Abs(tempLine.Length - line.Length) < 0.00001
|
||
)
|
||
{
|
||
group.Add(tempLine);
|
||
lines.Remove(tempLine);
|
||
}
|
||
}
|
||
}
|
||
|
||
if (lines.Count >= 1)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
break;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 投影到一个平面
|
||
/// </summary>
|
||
/// <param name="plane"></param>
|
||
/// <param name="point"></param>
|
||
/// <returns></returns>
|
||
public static XYZ GetProjectPoint(this Plane plane, XYZ point)
|
||
{
|
||
var tf = Transform.Identity;
|
||
tf.BasisX = plane.XVec;
|
||
tf.BasisY = plane.YVec;
|
||
tf.BasisZ = plane.Normal;
|
||
tf.Origin = plane.Origin;
|
||
//把point转到plane的逆矩阵坐标系上
|
||
var p = tf.Inverse.OfPoint(point);
|
||
//z为法向,等于0时,点在平面上
|
||
p = new XYZ(p.X, p.Y, 0);
|
||
|
||
return tf.OfPoint(p);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 计算两条线的交点
|
||
/// </summary>
|
||
/// <param name="curve1"></param>
|
||
/// <param name="curve2"></param>
|
||
/// <returns></returns>
|
||
public static XYZ IntersectionPoint(this Curve curve1, Curve curve2, bool makeUnbound = false)
|
||
{
|
||
var unboundCurve1 = curve1.Clone();
|
||
var unboundCurve2 = curve2.Clone();
|
||
if (makeUnbound && !curve1.IsBound)
|
||
{
|
||
unboundCurve1.MakeUnbound();
|
||
}
|
||
if (makeUnbound && !curve2.IsBound)
|
||
{
|
||
unboundCurve2.MakeUnbound();
|
||
}
|
||
var comparisonR = unboundCurve1.Intersect(unboundCurve2, out var intersectionR);
|
||
XYZ intersectionResult = null;
|
||
if (SetComparisonResult.Disjoint != comparisonR) // Disjoint无交点
|
||
{
|
||
try
|
||
{
|
||
if (intersectionR != null && !intersectionR.IsEmpty)
|
||
{
|
||
intersectionResult = intersectionR.get_Item(0).XYZPoint;
|
||
}
|
||
}
|
||
catch
|
||
{
|
||
// ignored
|
||
}
|
||
}
|
||
|
||
return intersectionResult;
|
||
}
|
||
|
||
/// <summary>
|
||
/// </summary>
|
||
/// <param name="upstreamBranch">上游分支</param>
|
||
/// <param name="downstreamBranch">下游分支</param>
|
||
/// <param name="downstreamMain">下游主线</param>
|
||
/// <param name="upstreamMain">上游主线</param>
|
||
/// <returns></returns>
|
||
public static XYZ IntersectionTwoVectors(XYZ upstreamBranch, XYZ downstreamBranch, XYZ downstreamMain, XYZ upstreamMain)
|
||
{
|
||
var main = upstreamMain - downstreamMain;
|
||
var branch = upstreamBranch - downstreamBranch;
|
||
var xyz = downstreamMain - downstreamBranch;
|
||
|
||
var num1 = main.DotProduct(main); //main*main
|
||
var num2 = main.DotProduct(branch); //main*branch*cos α1
|
||
var num3 = branch.DotProduct(branch); //branch*branch
|
||
var num4 = main.DotProduct(xyz); //main*xyz*cos α2
|
||
var num5 = branch.DotProduct(xyz); //branch*xyz*cos α3
|
||
var num6 = (num1 * num3) - (num2 * num2); //(1-cos α1*cos α1)*num1*num3
|
||
double num7;
|
||
double num8;
|
||
if (num6 < 1E-08) //main和branch同向
|
||
{
|
||
num7 = 0.0;
|
||
if (num2 > num3) //main>branch
|
||
{
|
||
num8 = num4 / num2; //xyz*cos α2/branch
|
||
}
|
||
else
|
||
{
|
||
num8 = num5 / num3; //xyz*cos α3/branch
|
||
}
|
||
}
|
||
else
|
||
{
|
||
num7 = ((num2 * num5) - (num3 * num4)) / num6; //xyz*(cos α1*cos α3-cos α2)/((1-cos α1*cos α1)*main)
|
||
num8 = ((num1 * num5) - (num2 * num4)) / num6; //xyz*(cos α3-cos α1*cos α2)/((1-cos α1*cos α1)*branch)
|
||
}
|
||
|
||
var xyz4 = downstreamMain + (num7 * main);
|
||
var xyz5 = downstreamBranch + (num8 * branch);
|
||
return (xyz5 + xyz4) / 2.0;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 平面与直线的交点,平行时为null
|
||
/// </summary>
|
||
/// <param name="plane"></param>
|
||
/// <param name="line"></param>
|
||
/// <returns></returns>
|
||
public static XYZ IntersectPoint(this Plane plane, Line line)
|
||
{
|
||
var startPoint = line.Origin;
|
||
|
||
var projectPoint = plane.ProjectOf(startPoint);
|
||
if (Math.Abs(line.Direction.DotProduct(plane.Normal)) < VbTolerance) //是否平行
|
||
{
|
||
return null;
|
||
}
|
||
|
||
var length = startPoint.DistanceTo(projectPoint);
|
||
if (length < VbTolerance) //不平行,但刚好是Origin,即为交点
|
||
{
|
||
return projectPoint;
|
||
}
|
||
|
||
var vector = projectPoint - startPoint;
|
||
//var per = Line.CreateBound(startPoint, projectPoint);//垂线
|
||
if (vector.IsParallelTo(line.Direction))
|
||
{
|
||
return projectPoint;
|
||
}
|
||
|
||
var cos = plane.Normal.DotProduct(line.Direction);
|
||
if (cos < 0)
|
||
{
|
||
cos = plane.Normal.Negate().DotProduct(line.Direction);
|
||
}
|
||
var distance = length / cos;
|
||
return vector.Normalize().DotProduct(line.Direction) < 0
|
||
? startPoint - (line.Direction * distance)
|
||
: startPoint + (line.Direction * distance);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 是否水平
|
||
/// </summary>
|
||
/// <param name="face"></param>
|
||
/// <returns></returns>
|
||
public static bool IsHorizontal(this PlanarFace face)
|
||
{
|
||
return Math.Abs(face.GetMinY() - face.GetMaxY()) < VbTolerance;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 点是否在直线范围内,且与端点距离大于等于一定距离
|
||
/// </summary>
|
||
/// <param name="line"></param>
|
||
/// <param name="point"></param>
|
||
/// <param name="endParameter">两边端点距离</param>
|
||
/// <returns></returns>
|
||
public static bool IsInsideEx(this Line line, XYZ point, double endParameter = 0.0)
|
||
{
|
||
if (line == null)
|
||
{
|
||
throw new ArgumentNullException(nameof(line));
|
||
}
|
||
if (line.IsBound)
|
||
{
|
||
var d1 = point.DistanceTo(line.GetEndPoint(0));
|
||
var d2 = point.DistanceTo(line.GetEndPoint(1));
|
||
return d1 + d2 - line.Length < VbTolerance && d1 >= endParameter && d2 >= endParameter;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 判断方向是否平行
|
||
/// </summary>
|
||
/// <param name="direction1"></param>
|
||
/// <param name="direction2"></param>
|
||
/// <returns></returns>
|
||
public static bool IsParallelTo(this XYZ direction1, XYZ direction2)
|
||
{
|
||
return direction1.CrossProduct(direction2).IsZeroLength() || direction1.CrossProduct(direction2).IsAlmostEqualTo(XYZ.Zero);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 判断直线是否平行或重合
|
||
/// </summary>
|
||
/// <param name="line"></param>
|
||
/// <param name="checkedLine"></param>
|
||
/// <returns></returns>
|
||
public static bool IsParallelTo(this Line line, Line checkedLine)
|
||
{
|
||
var a = line.Direction.CrossProduct(checkedLine.Direction).IsZeroLength();
|
||
var b = line.Direction.CrossProduct(checkedLine.Direction).IsAlmostEqualTo(XYZ.Zero);
|
||
var c = 1 - Math.Abs(line.Direction.DotProduct(checkedLine.Direction)) < VbTolerance;
|
||
return a || b || c;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 判断直线是否垂直
|
||
/// </summary>
|
||
/// <param name="line"></param>
|
||
/// <param name="checkedLine"></param>
|
||
/// <param name="tolerance"></param>
|
||
/// <returns></returns>
|
||
public static bool IsPerpendicularTo(this Line line, Line checkedLine, double tolerance = VbTolerance)
|
||
{
|
||
return Math.Abs(line.Direction.DotProduct(checkedLine.Direction)) < tolerance; //点乘满足交换律不影响计算结果
|
||
}
|
||
|
||
/// <summary>测试输入的实体或壳体是否可用于细分曲面</summary>
|
||
/// <param name="solid">固体或外壳</param>
|
||
/// <returns>如果实体或外壳对细分有效,则为 true,否则为 false</returns>
|
||
public static bool IsValidForTessellation(this Solid solid)
|
||
{
|
||
return SolidUtils.IsValidForTessellation(solid);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 是否是垂直面
|
||
/// </summary>
|
||
/// <param name="face"></param>
|
||
/// <returns></returns>
|
||
public static bool IsVertical(this PlanarFace face)
|
||
{
|
||
return Math.Abs(face.GetMinX() - face.GetMaxX()) < VbTolerance;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 得到垂足
|
||
/// </summary>
|
||
/// <param name="p0"></param>
|
||
/// <param name="p1"></param>
|
||
/// <param name="pX">经过该点作与p0,p1所在直线的垂线</param>
|
||
/// <returns></returns>
|
||
public static XYZ PerpendicularIntersection(this XYZ pX, XYZ p0, XYZ p1)
|
||
{
|
||
//直线向量和p0点到px点的点积
|
||
var v0 = pX - p0;
|
||
var v1 = p1 - p0;
|
||
var dotProduct = v0.DotProduct(v1); //|v0||v1|cos α
|
||
var length = v1.GetLength(); //直线的长度|v1|
|
||
var normalize = v1 / length; //直线单位向量
|
||
var m = dotProduct / length; //垂足的模
|
||
return (normalize * m) + p0;
|
||
//var nu3 = nu / (nu2 * nu2);
|
||
//XYZ result = p0 + v1 * nu3;
|
||
//return result;
|
||
//double num = (pX.X - p0.X) * (p1.X - p0.X) + (pX.Y - p0.Y) * (p1.Y - p0.Y) + (pX.Z - p0.Z) * (p1.Z - p0.Z);
|
||
//double num2 = p0.DistanceTo(p1);//直线的长度
|
||
//num /= num2 * num2;
|
||
//return new XYZ(p0.X + num * (p1.X - p0.X), p0.Y + num * (p1.Y - p0.Y), p0.Z + num * (p1.Z - p0.Z));
|
||
}
|
||
|
||
/// <summary>
|
||
/// 点在平面的投影
|
||
/// </summary>
|
||
/// <param name="plane"></param>
|
||
/// <param name="p"></param>
|
||
/// <returns></returns>
|
||
public static XYZ ProjectOf(this PlanarFace plane, XYZ p)
|
||
{
|
||
var v = p - plane.Origin;
|
||
//垂向距离(可正可负,夹角钝角为负)
|
||
var d = v.DotProduct(plane.FaceNormal);
|
||
return p - (d * plane.FaceNormal);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 点在平面的投影
|
||
/// </summary>
|
||
/// <param name="plane"></param>
|
||
/// <param name="p"></param>
|
||
/// <returns></returns>
|
||
public static XYZ ProjectOf(this Plane plane, XYZ p)
|
||
{
|
||
var v = p - plane.Origin;
|
||
//垂向距离(可正可负,夹角钝角为负)
|
||
var d = v.DotProduct(plane.Normal);
|
||
return p - (d * plane.Normal);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 直线在几何平面上的投影
|
||
/// </summary>
|
||
/// <param name="plane"></param>
|
||
/// <param name="line"></param>
|
||
/// <returns></returns>
|
||
public static Line ProjectOnto(this PlanarFace plane, Line line)
|
||
{
|
||
return Line.CreateBound(plane.ProjectOf(line.GetEndPoint(0)), plane.ProjectOf(line.GetEndPoint(1)));
|
||
}
|
||
|
||
/// <summary>
|
||
/// 直线在平面上的投影
|
||
/// </summary>
|
||
/// <param name="plane"></param>
|
||
/// <param name="line"></param>
|
||
/// <returns></returns>
|
||
public static Line ProjectOnto(this Plane plane, Line line)
|
||
{
|
||
return Line.CreateBound(plane.ProjectOf(line.GetEndPoint(0)), plane.ProjectOf(line.GetEndPoint(1)));
|
||
}
|
||
|
||
///// <summary>
|
||
///// 点在几何面的投影
|
||
///// </summary>
|
||
///// <param name="plane"></param>
|
||
///// <param name="p"></param>
|
||
///// <returns></returns>
|
||
//public static XYZ ProjectOnto(this PlanarFace plane, XYZ p)
|
||
//{
|
||
// var d1 = plane.ProjectOf(p, out _);
|
||
// var q = p - (d1 * plane.FaceNormal);
|
||
|
||
// return q;
|
||
//}
|
||
|
||
/// <summary>
|
||
/// 点拍平到xy平面
|
||
/// </summary>
|
||
/// <param name="xyz"></param>
|
||
/// <returns></returns>
|
||
public static XYZ Flatten(this XYZ xyz)
|
||
{
|
||
return xyz.Subtract(XYZ.BasisZ * xyz.Z);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置元素定位线
|
||
/// </summary>
|
||
/// <param name="instance">以点定位的实例</param>
|
||
/// <param name="curve"></param>
|
||
/// <returns></returns>
|
||
public static void SetLocationCurve(this Element instance, Curve curve)
|
||
{
|
||
if (instance == null)
|
||
{
|
||
throw new ArgumentNullException(nameof(instance));
|
||
}
|
||
if (curve == null)
|
||
{
|
||
throw new ArgumentNullException(nameof(curve));
|
||
}
|
||
//var sourceCurve=instance.GetCurve();
|
||
|
||
if (instance.Location is LocationCurve lc)
|
||
{
|
||
try
|
||
{
|
||
lc.Curve = curve;
|
||
}
|
||
catch (Exception)
|
||
{
|
||
throw new InvalidOperationException("无法修改定位线");
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取元素定位线
|
||
/// </summary>
|
||
/// <param name="instance">以点定位的实例</param>
|
||
/// <param name="xyz"></param>
|
||
/// <returns></returns>
|
||
public static void SetLocationPoint(this Element instance, XYZ xyz)
|
||
{
|
||
if (instance == null)
|
||
{
|
||
throw new ArgumentNullException(nameof(instance));
|
||
}
|
||
if (xyz == null)
|
||
{
|
||
throw new ArgumentNullException(nameof(xyz));
|
||
}
|
||
if (instance.Location is LocationPoint lp)
|
||
{
|
||
try
|
||
{
|
||
lp.Point = xyz;
|
||
}
|
||
catch (Exception)
|
||
{
|
||
throw new InvalidOperationException("无法修改定位点");
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>将实体几何分割成多个独立实体</summary>
|
||
/// <remarks>
|
||
/// 如果不进行拆分,输出数组将返回输入实体的副本
|
||
/// </remarks>
|
||
/// <param name="solid">The solid</param>
|
||
/// <returns>分割实体几何图形</returns>
|
||
/// <exception cref="Command:Autodesk.Revit.Exceptions.InvalidOperationException">
|
||
/// 分割实体几何体失败
|
||
/// </exception>
|
||
public static IList<Solid> SplitVolumes(this Solid solid)
|
||
{
|
||
return SolidUtils.SplitVolumes(solid);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 此函数对实体或开口壳体进行切面(即三角化)。实体或外壳的每个边界
|
||
/// 实体或外壳的每个边界部分都由一个三角形结构来表示
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// 实体(或壳体)边界组件三角剖分上的每一点都应位于某个 "精度 "输入项指定的三维距离之内。
|
||
/// 壳体)上的每一点都应位于 "精确度 "输入所指定的三维距离内,反之亦然。
|
||
/// 三角剖面上的某一点的 "精度 "输入所指定的三维距离之内,反之亦然。在某些情况下,可以
|
||
/// 启发式地(而非严格地)执行
|
||
/// </remarks>
|
||
/// <param name="solid">要切面的固体或外壳</param>
|
||
/// <param name="tessellationControls">
|
||
/// 该输入可控制三角测量的各个方面
|
||
/// </param>
|
||
/// <returns>
|
||
/// 与输入实体的边界成分或输入壳体的成分相对应的三角形结构
|
||
/// 输入实体或输入壳体的分量
|
||
/// </returns>
|
||
/// <exception cref="Command:Autodesk.Revit.Exceptions.ArgumentException">
|
||
/// solidOrShell 对三角剖分无效(例如,它不包含任何面)
|
||
/// </exception>
|
||
/// <exception cref="Command:Autodesk.Revit.Exceptions.InvalidOperationException">
|
||
/// 无法对实体或外壳进行三角测量
|
||
/// </exception>
|
||
public static TriangulatedSolidOrShell TessellateSolidOrShell(this Solid solid, SolidOrShellTessellationControls tessellationControls)
|
||
{
|
||
return SolidUtils.TessellateSolidOrShell(solid, tessellationControls);
|
||
}
|
||
/// <summary>
|
||
/// 变换坐标点等同于transform.OfPoint()
|
||
/// </summary>
|
||
/// <param name="point">点,坐标值为在transform(相对坐标系)坐标系上的值</param>
|
||
/// <param name="transform">用于变换的坐标系</param>
|
||
/// <returns>在transform坐标系上的点,在绝对坐标系上的值</returns>
|
||
public static XYZ TransformPoint(this XYZ point, Transform transform)
|
||
{
|
||
var x = point.X;
|
||
var y = point.Y;
|
||
var z = point.Z;
|
||
var b0 = transform.get_Basis(0);
|
||
var b1 = transform.get_Basis(1);
|
||
var b2 = transform.get_Basis(2);
|
||
var origin = transform.Origin;
|
||
var xTemp = (x * b0.X) + (y * b1.X) + (z * b2.X) + origin.X;
|
||
var yTemp = (x * b0.Y) + (y * b1.Y) + (z * b2.Y) + origin.Y;
|
||
var zTemp = (x * b0.Z) + (y * b1.Z) + (z * b2.Z) + origin.Z;
|
||
return new XYZ(xTemp, yTemp, zTemp);
|
||
}
|
||
|
||
#if REVIT2025
|
||
|
||
/// <summary>查找输入 EdgeEndPoint 所标识顶点上的所有 EdgeEndPoints</summary>
|
||
/// <param name="edgeEndPoint">标识顶点的输入 EdgeEndPoint</param>
|
||
/// <returns>顶点上的所有边缘端点。输入的边缘端点也包括在内</returns>
|
||
/// <exception cref="T:Autodesk.Revit.Exceptions.InvalidOperationException">
|
||
/// 查找输入 EdgeEndPoint 所标识顶点上的所有 EdgeEndPoints失败
|
||
/// </exception>
|
||
[Pure]
|
||
public static IList<EdgeEndPoint> FindAllEdgeEndPointsAtVertex(this EdgeEndPoint edgeEndPoint)
|
||
{
|
||
return SolidUtils.FindAllEdgeEndPointsAtVertex(edgeEndPoint);
|
||
}
|
||
#endif
|
||
}
|