using Autodesk.Revit.DB; using ShrlAlgoToolkit.RevitCore.Extensions; namespace ShrlAlgoToolkit.RevitCore.Assists; public static class SpatialAssist { //private static List _curvesSorted; /// /// 拆分线串变成固定长度的曲线段。 /// /// /// /// public static List SplitCurveChainByFixedLength(CurveLoop curveChain, double segmentLength) { List container = new List(); if (curveChain.GetExactLength() - segmentLength < 10e-6)//总长度小于分割长度 { return [.. curveChain.Select(c => new SingleCurve(c))]; } //double currentParam = 0.0; //Curve currentCurve; //Curve remainingCurve; //int currentCurveIndex = 0; CurveList mergeList = null; //double tempLength = 0.0; //double currentStartParam = 0.0; //还需要的曲线长度才能满足分割长度 double neededLength = 0.0; //List loops = new List(); for (int i = 0; i < curveChain.Count(); i++) { Curve currentCurve = curveChain.ElementAt(i); //如果需要的长度大于曲线长度,说明整条曲线都应该被包含在内 if (neededLength > currentCurve.Length) { mergeList.Curves.Add(currentCurve); neededLength -= currentCurve.Length; continue; } var splitList = currentCurve.SplitByFixedLength( neededLength, segmentLength, out var previousNeedCurve, out var remainingCurve); //需要将前置分割曲线添加上一段的列表中 if (previousNeedCurve != null) { mergeList.Curves.Add(previousNeedCurve); //扣除已经添加的曲线长度,得到剩余需要的长度 neededLength = segmentLength - mergeList.Curves.Sum(c => c.Length); } //可以分割 if (splitList.Count > 0) { container.AddRange(splitList.Select(c => new SingleCurve(c))); } //已经满足分割长度,新建下一个列表 if (neededLength < 10e-6) { mergeList = new CurveList([]); container.Add(mergeList); } if (remainingCurve == null)//完全均分时,重置起点 { neededLength = 0.0; } else//剩余曲线添加到下一个列表中 { mergeList.Curves.Add(remainingCurve); neededLength = segmentLength - mergeList.Curves.Sum(c => c.Length); } } //container.Add(mergeList); // 添加最后的合并列表 return container; } /// /// 拆分成点和右侧朝向。 /// /// /// /// public static Dictionary EvalutePointCurveChainByFixedLength(CurveLoop curveChain, double segmentLength) { Dictionary container = new(); if (curveChain.GetExactLength() - segmentLength < 10e-6)//总长度小于分割长度时,取起点 { var curve = curveChain.FirstOrDefault(); var startPoint = curve.GetEndPoint(0); var orientation = curve.ComputeDerivatives(0, true).BasisX.Normalize(); return new Dictionary { { startPoint, orientation } }; } //CurveList mergeList = null; double currentLength = 0.0; //还需要的曲线长度才能满足分割长度 double neededLength = 0.0; for (int i = 0; i < curveChain.Count(); i++) { Curve currentCurve = curveChain.ElementAt(i); //如果需要的长度大于曲线长度,说明整条曲线都应该被包含在内 if (neededLength > currentCurve.Length) { //mergeList.Curves.Add(currentCurve); currentLength += currentCurve.Length; neededLength -= currentCurve.Length; continue; } var splitList = currentCurve.EvalutePointByFixedLength( neededLength, segmentLength, out var previous, out var remaining); //需要将前置分割曲线添加上一段的列表中 if (previous > 0.0) { currentLength += previous; //扣除已经添加的曲线长度,得到剩余需要的长度 neededLength = segmentLength - currentLength; } //可以分割 if (splitList.Count > 0) { foreach (var item in splitList) { if (!container.Any(p => p.Key.IsAlmostEqualTo(item.Key)))//闭合曲线起终点有可能一样 { container.Add(item.Key, item.Value); } } } //已经满足分割长度 if (neededLength < 10e-6) { currentLength = 0; //var point = currentCurve.Evaluate(1, false); //var orientation = currentCurve.Evaluate(1, false); //var p = new XYZ(-411.791042284402, 1330.9543320873, 0); //if (p.IsAlmostEqualTo(point)) //{ //} //container.Add(point,orientation); } if (remaining == 0.0)//完全均分时,重置起点 { neededLength = 0.0; currentLength = 0.0; if (i < curveChain.Count() - 1)//如果还有下一个的时候,移除最后一个点 { var last = container.Last(); container.Remove(last.Key); } } else//剩余曲线添加到下一个列表中 { currentLength += remaining; neededLength = segmentLength - currentLength; } } //container.Add(mergeList); // 添加最后的合并列表 return container; } public static Transform GetProfileTransform(Curve referCurve) { //非刚性变换,会改变原几何,此变换在曲线计算导数时,为非刚性变换,各个basis的模不等于1 var point = referCurve.GetEndPoint(0); var transform = referCurve.ComputeDerivatives(0, true); var tangent = transform.BasisX.Normalize(); var rightBasis = tangent.CrossProduct(XYZ.BasisZ).Normalize(); var topBasis = rightBasis.CrossProduct(tangent).Normalize(); //构造新的变换 var profileTransform = Transform.Identity; profileTransform.Origin = point; profileTransform.BasisX = rightBasis; profileTransform.BasisY = topBasis; profileTransform.BasisZ = tangent; return profileTransform; } /// /// 多段线 /// /// /// public static PolyLine ByJoinedCurves(List curves) { List points = []; foreach (var c in curves) { points.Add(c.GetEndPoint(0)); } points.Add(curves.Last().GetEndPoint(1)); if (points.Count == 0) { return null; } return PolyLine.Create(points); } /// /// 将一组离散的曲线整理成多条连续的线串。 /// /// 输入的曲线集合,可能包含直线、圆弧、样条曲线等。 /// 一个包含多条线串的列表,每条线串本身也是一个曲线列表,且内部曲线方向连续。 public static List> GroupContinuousCurves(IEnumerable curves) { // 最终返回的所有线串集合 var allChains = new List>(); // 可被消耗的曲线列表 var remainingCurves = new List(curves); // Revit API 中用于几何比较的默认精度 double tolerance = 1e-9; // 当还有未处理的曲线时,持续循环 while (remainingCurves.Any()) { // 开始一条新的线串 var currentChain = new List(); // 从剩余曲线中取第一条作为新线串的起点 var firstCurve = remainingCurves[0]; currentChain.Add(firstCurve); remainingCurves.RemoveAt(0); // 持续延长当前线串,直到无法再延长 while (true) { bool chainExtended = false; // 获取当前线串的头尾端点 XYZ chainStartPoint = currentChain.First().GetEndPoint(0); XYZ chainEndPoint = currentChain.Last().GetEndPoint(1); // 从后向前遍历以安全地在循环中移除元素 for (int i = remainingCurves.Count - 1; i >= 0; i--) { var candidate = remainingCurves[i]; XYZ candidateStartPoint = candidate.GetEndPoint(0); XYZ candidateEndPoint = candidate.GetEndPoint(1); // 尝试连接到线串的尾部 if (chainEndPoint.IsAlmostEqualTo(candidateStartPoint, tolerance)) { currentChain.Add(candidate); remainingCurves.RemoveAt(i); chainExtended = true; break; // 找到一个后就跳出内层for循环,重新获取线串端点 } else if (chainEndPoint.IsAlmostEqualTo(candidateEndPoint, tolerance)) { currentChain.Add(candidate.CreateReversed()); // 反向后添加 remainingCurves.RemoveAt(i); chainExtended = true; break; } // 尝试连接到线串的头部 else if (chainStartPoint.IsAlmostEqualTo(candidateEndPoint, tolerance)) { currentChain.Insert(0, candidate); // 插入到头部 remainingCurves.RemoveAt(i); chainExtended = true; break; } else if (chainStartPoint.IsAlmostEqualTo(candidateStartPoint, tolerance)) { currentChain.Insert(0, candidate.CreateReversed()); // 反向后插入到头部 remainingCurves.RemoveAt(i); chainExtended = true; break; } } // 如果本轮没有延长线串,说明这条线串已经构建完毕 if (!chainExtended) { break; // 跳出 while(true) 循环 } } // 将构建完成的线串添加到最终结果中 allChains.Add(currentChain); } return allChains; } } public interface ICurveContainer { } public class SingleCurve : ICurveContainer { public SingleCurve(Curve curve) { Curve = curve; } public Curve Curve { get; } } public class CurveList : ICurveContainer { public List Curves { get; } public CurveList(List curves) => Curves = curves; }