using Autodesk.Revit.DB; namespace ShrlAlgoToolkit.Revit.Assists; internal 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 GetProfileTranform(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; } ///// ///// 连成线串 ///// ///// ///// //private static void SortOpenedContinuousCurves(Curve initCurve, List sourceCurves) //{ // if (sourceCurves == null) // { // return; // } // //if (sourceCurves.Count <= 2) // //{ // // return; // //} // var start = initCurve.GetEndPoint(0); // var end = initCurve.GetEndPoint(1); // //curvesSorted.Add(initCurve); // sourceCurves.Remove(initCurve); // for (var i = sourceCurves.Count - 1; i >= 0; i--) // { // if (sourceCurves.Count == 0) // { // break; // } // if (i >= sourceCurves.Count) // { // i = sourceCurves.Count - 1; // } // //var anotherCurve = sourceCurves[i]; // var comparisonR = initCurve.Intersect(sourceCurves[i], out var _); // //圆 // if (comparisonR == SetComparisonResult.Disjoint && initCurve is Arc && sourceCurves[i] is Arc) // { // var curves = new List() { initCurve, sourceCurves[i] }; // try // { // var loop = CurveLoop.Create(curves);//如果报错,说明两个半圆没形成圆,是不连续的; // _curvesSorted = curves; // //移除当前的线段 // sourceCurves.Remove(sourceCurves[i]); // return; // } // catch (Exception) // { // } // } // if (SetComparisonResult.Overlap == comparisonR) // { // //XYZ point = null; // //if (intersectionR != null && !intersectionR.IsEmpty) // //{ // // point = intersectionR.get_Item(0).XYZPoint; // //} // var start1 = sourceCurves[i].GetEndPoint(0); // var end1 = sourceCurves[i].GetEndPoint(1); // if (end.IsAlmostEqualTo(start1))//顺序连接 // { // _curvesSorted.Add(sourceCurves[i]); // } // if (end.IsAlmostEqualTo(end1))//终点一样,反向加到后面 // { // sourceCurves[i] = sourceCurves[i].CreateReversed();//替换掉,才能保证移除的对象是同一个 // _curvesSorted.Add(sourceCurves[i]); // } // if (start.IsAlmostEqualTo(start1))//起点一样,反向插到前面 // { // sourceCurves[i] = sourceCurves[i].CreateReversed(); // _curvesSorted.Insert(_curvesSorted.IndexOf(initCurve), sourceCurves[i]); // } // if (start.IsAlmostEqualTo(end1))//顺序连接,但是在前面 // { // _curvesSorted.Insert(_curvesSorted.IndexOf(initCurve), sourceCurves[i]); // } // SortOpenedContinuousCurves(sourceCurves[i], sourceCurves); // } // } //} /// /// 转线串 /// /// /// //public static List> ToCurveLoops(List curves) //{ // List> list = []; // while (curves.Any()) // { // _curvesSorted = // [ // curves[0] // ]; // if (!curves[0].IsBound) // { // curves.Remove(curves[0]); // list.Add(_curvesSorted); // continue; // } // SortOpenedContinuousCurves(curves[0], curves); // list.Add(_curvesSorted); // } // //for (var i = 0; i < 100; i++) // //{ // // try // // { // // if (!curves.Any()) // // { // // break; // // } // // _curvesSorted = new() // // { // // curves[0] // // }; // // if (!curves[0].IsBound) // // { // // curves.Remove(curves[0]); // // list.Add(_curvesSorted); // // continue; // // } // // SortOpenedContinuousCurves(curves[0], curves); // // } // // catch (Exception ex) // // { // // Debug.Write(ex.StackTrace); // // } // // list.Add(_curvesSorted); // // if (!curves.Any()) // // { // // break; // // } // //} // return list; //} } internal 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; }