2025-04-24 20:56:44 +08:00
|
|
|
|
using Autodesk.Revit.DB;
|
|
|
|
|
|
|
|
|
|
|
|
namespace ShrlAlgoToolkit.Revit.Assists;
|
|
|
|
|
|
|
2025-12-28 11:47:54 +08:00
|
|
|
|
public static class SpatialAssist
|
2025-04-24 20:56:44 +08:00
|
|
|
|
{
|
2025-07-11 09:20:23 +08:00
|
|
|
|
//private static List<Curve> _curvesSorted;
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 拆分线串变成固定长度的曲线段。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="curveChain"></param>
|
|
|
|
|
|
/// <param name="segmentLength"></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
public static List<ICurveContainer> SplitCurveChainByFixedLength(CurveLoop curveChain, double segmentLength)
|
|
|
|
|
|
{
|
|
|
|
|
|
List<ICurveContainer> container = new List<ICurveContainer>();
|
|
|
|
|
|
|
|
|
|
|
|
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<CurveLoop> loops = new List<CurveLoop>();
|
|
|
|
|
|
|
|
|
|
|
|
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)));
|
|
|
|
|
|
}
|
2025-04-24 20:56:44 +08:00
|
|
|
|
|
2025-07-11 09:20:23 +08:00
|
|
|
|
//已经满足分割长度,新建下一个列表
|
|
|
|
|
|
if (neededLength < 10e-6)
|
|
|
|
|
|
{
|
|
|
|
|
|
mergeList = new CurveList([]);
|
|
|
|
|
|
container.Add(mergeList);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (remainingCurve == null)//完全均分时,重置起点
|
|
|
|
|
|
{
|
|
|
|
|
|
neededLength = 0.0;
|
|
|
|
|
|
}
|
|
|
|
|
|
else//剩余曲线添加到下一个列表中
|
|
|
|
|
|
{
|
|
|
|
|
|
mergeList.Curves.Add(remainingCurve);
|
2025-04-24 20:56:44 +08:00
|
|
|
|
|
2025-07-11 09:20:23 +08:00
|
|
|
|
neededLength = segmentLength - mergeList.Curves.Sum(c => c.Length);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
//container.Add(mergeList); // 添加最后的合并列表
|
|
|
|
|
|
return container;
|
|
|
|
|
|
}
|
2025-04-24 20:56:44 +08:00
|
|
|
|
/// <summary>
|
2025-07-11 09:20:23 +08:00
|
|
|
|
/// 拆分成点和右侧朝向。
|
2025-04-24 20:56:44 +08:00
|
|
|
|
/// </summary>
|
2025-07-11 09:20:23 +08:00
|
|
|
|
/// <param name="curveChain"></param>
|
|
|
|
|
|
/// <param name="segmentLength"></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
public static Dictionary<XYZ, XYZ> EvalutePointCurveChainByFixedLength(CurveLoop curveChain, double segmentLength)
|
2025-04-24 20:56:44 +08:00
|
|
|
|
{
|
2025-07-11 09:20:23 +08:00
|
|
|
|
Dictionary<XYZ, XYZ> container = new();
|
|
|
|
|
|
|
|
|
|
|
|
if (curveChain.GetExactLength() - segmentLength < 10e-6)//总长度小于分割长度时,取起点
|
2025-04-24 20:56:44 +08:00
|
|
|
|
{
|
2025-07-11 09:20:23 +08:00
|
|
|
|
var curve = curveChain.FirstOrDefault();
|
|
|
|
|
|
var startPoint = curve.GetEndPoint(0);
|
|
|
|
|
|
var orientation = curve.ComputeDerivatives(0, true).BasisX.Normalize();
|
|
|
|
|
|
return new Dictionary<XYZ, XYZ> { { startPoint, orientation } };
|
2025-04-24 20:56:44 +08:00
|
|
|
|
}
|
2025-07-11 09:20:23 +08:00
|
|
|
|
//CurveList mergeList = null;
|
|
|
|
|
|
double currentLength = 0.0;
|
|
|
|
|
|
//还需要的曲线长度才能满足分割长度
|
|
|
|
|
|
double neededLength = 0.0;
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < curveChain.Count(); i++)
|
2025-04-24 20:56:44 +08:00
|
|
|
|
{
|
2025-07-11 09:20:23 +08:00
|
|
|
|
Curve currentCurve = curveChain.ElementAt(i);
|
|
|
|
|
|
//如果需要的长度大于曲线长度,说明整条曲线都应该被包含在内
|
|
|
|
|
|
if (neededLength > currentCurve.Length)
|
2025-04-24 20:56:44 +08:00
|
|
|
|
{
|
2025-07-11 09:20:23 +08:00
|
|
|
|
//mergeList.Curves.Add(currentCurve);
|
|
|
|
|
|
currentLength += currentCurve.Length;
|
|
|
|
|
|
neededLength -= currentCurve.Length;
|
|
|
|
|
|
continue;
|
2025-04-24 20:56:44 +08:00
|
|
|
|
}
|
2025-07-11 09:20:23 +08:00
|
|
|
|
var splitList = currentCurve.EvalutePointByFixedLength(
|
|
|
|
|
|
neededLength,
|
|
|
|
|
|
segmentLength,
|
|
|
|
|
|
out var previous,
|
|
|
|
|
|
out var remaining);
|
|
|
|
|
|
//需要将前置分割曲线添加上一段的列表中
|
|
|
|
|
|
if (previous > 0.0)
|
2025-04-24 20:56:44 +08:00
|
|
|
|
{
|
2025-07-11 09:20:23 +08:00
|
|
|
|
currentLength += previous;
|
|
|
|
|
|
//扣除已经添加的曲线长度,得到剩余需要的长度
|
|
|
|
|
|
neededLength = segmentLength - currentLength;
|
2025-04-24 20:56:44 +08:00
|
|
|
|
}
|
2025-07-11 09:20:23 +08:00
|
|
|
|
//可以分割
|
|
|
|
|
|
if (splitList.Count > 0)
|
2025-04-24 20:56:44 +08:00
|
|
|
|
{
|
2025-07-11 09:20:23 +08:00
|
|
|
|
foreach (var item in splitList)
|
2025-04-24 20:56:44 +08:00
|
|
|
|
{
|
2025-07-11 09:20:23 +08:00
|
|
|
|
if (!container.Any(p => p.Key.IsAlmostEqualTo(item.Key)))//闭合曲线起终点有可能一样
|
|
|
|
|
|
{
|
|
|
|
|
|
container.Add(item.Key, item.Value);
|
|
|
|
|
|
}
|
2025-04-24 20:56:44 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-11 09:20:23 +08:00
|
|
|
|
//已经满足分割长度
|
|
|
|
|
|
if (neededLength < 10e-6)
|
2025-04-24 20:56:44 +08:00
|
|
|
|
{
|
2025-07-11 09:20:23 +08:00
|
|
|
|
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))
|
2025-04-24 20:56:44 +08:00
|
|
|
|
//{
|
|
|
|
|
|
//}
|
2025-07-11 09:20:23 +08:00
|
|
|
|
//container.Add(point,orientation);
|
|
|
|
|
|
}
|
2025-04-24 20:56:44 +08:00
|
|
|
|
|
2025-07-11 09:20:23 +08:00
|
|
|
|
if (remaining == 0.0)//完全均分时,重置起点
|
|
|
|
|
|
{
|
|
|
|
|
|
neededLength = 0.0;
|
|
|
|
|
|
currentLength = 0.0;
|
|
|
|
|
|
if (i < curveChain.Count() - 1)//如果还有下一个的时候,移除最后一个点
|
2025-04-24 20:56:44 +08:00
|
|
|
|
{
|
2025-07-11 09:20:23 +08:00
|
|
|
|
var last = container.Last();
|
|
|
|
|
|
container.Remove(last.Key);
|
2025-04-24 20:56:44 +08:00
|
|
|
|
}
|
2025-07-11 09:20:23 +08:00
|
|
|
|
}
|
|
|
|
|
|
else//剩余曲线添加到下一个列表中
|
|
|
|
|
|
{
|
|
|
|
|
|
currentLength += remaining;
|
|
|
|
|
|
neededLength = segmentLength - currentLength;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
//container.Add(mergeList); // 添加最后的合并列表
|
|
|
|
|
|
return container;
|
|
|
|
|
|
}
|
2026-01-01 10:02:59 +08:00
|
|
|
|
public static Transform GetProfileTransform(Curve referCurve)
|
2025-07-11 09:20:23 +08:00
|
|
|
|
{
|
|
|
|
|
|
//非刚性变换,会改变原几何,此变换在曲线计算导数时,为非刚性变换,各个basis的模不等于1
|
|
|
|
|
|
var point = referCurve.GetEndPoint(0);
|
|
|
|
|
|
var transform = referCurve.ComputeDerivatives(0, true);
|
2025-04-24 20:56:44 +08:00
|
|
|
|
|
2025-07-11 09:20:23 +08:00
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 多段线
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="curves"></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
public static PolyLine ByJoinedCurves(List<Curve> curves)
|
|
|
|
|
|
{
|
|
|
|
|
|
List<XYZ> 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);
|
|
|
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 将一组离散的曲线整理成多条连续的线串。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="curves">输入的曲线集合,可能包含直线、圆弧、样条曲线等。</param>
|
|
|
|
|
|
/// <returns>一个包含多条线串的列表,每条线串本身也是一个曲线列表,且内部曲线方向连续。</returns>
|
|
|
|
|
|
public static List<List<Curve>> GroupContinuousCurves(IEnumerable<Curve> curves)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 最终返回的所有线串集合
|
|
|
|
|
|
var allChains = new List<List<Curve>>();
|
|
|
|
|
|
// 可被消耗的曲线列表
|
|
|
|
|
|
var remainingCurves = new List<Curve>(curves);
|
|
|
|
|
|
// Revit API 中用于几何比较的默认精度
|
|
|
|
|
|
double tolerance = 1e-9;
|
|
|
|
|
|
|
|
|
|
|
|
// 当还有未处理的曲线时,持续循环
|
|
|
|
|
|
while (remainingCurves.Any())
|
|
|
|
|
|
{
|
|
|
|
|
|
// 开始一条新的线串
|
|
|
|
|
|
var currentChain = new List<Curve>();
|
|
|
|
|
|
|
|
|
|
|
|
// 从剩余曲线中取第一条作为新线串的起点
|
|
|
|
|
|
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--)
|
2025-04-24 20:56:44 +08:00
|
|
|
|
{
|
2025-07-11 09:20:23 +08:00
|
|
|
|
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;
|
|
|
|
|
|
}
|
2025-04-24 20:56:44 +08:00
|
|
|
|
}
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
|
|
|
|
|
// 如果本轮没有延长线串,说明这条线串已经构建完毕
|
|
|
|
|
|
if (!chainExtended)
|
2025-04-24 20:56:44 +08:00
|
|
|
|
{
|
2025-07-11 09:20:23 +08:00
|
|
|
|
break; // 跳出 while(true) 循环
|
2025-04-24 20:56:44 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
|
|
|
|
|
// 将构建完成的线串添加到最终结果中
|
|
|
|
|
|
allChains.Add(currentChain);
|
2025-04-24 20:56:44 +08:00
|
|
|
|
}
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
|
|
|
|
|
return allChains;
|
2025-04-24 20:56:44 +08:00
|
|
|
|
}
|
2025-07-11 09:20:23 +08:00
|
|
|
|
}
|
2025-12-28 11:47:54 +08:00
|
|
|
|
|
|
|
|
|
|
public interface ICurveContainer
|
2025-07-11 09:20:23 +08:00
|
|
|
|
{
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public class SingleCurve : ICurveContainer
|
|
|
|
|
|
{
|
|
|
|
|
|
public SingleCurve(Curve curve)
|
2025-04-24 20:56:44 +08:00
|
|
|
|
{
|
2025-07-11 09:20:23 +08:00
|
|
|
|
Curve = curve;
|
2025-04-24 20:56:44 +08:00
|
|
|
|
}
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
|
|
|
|
|
public Curve Curve { get; }
|
|
|
|
|
|
}
|
|
|
|
|
|
public class CurveList : ICurveContainer
|
|
|
|
|
|
{
|
|
|
|
|
|
public List<Curve> Curves { get; }
|
|
|
|
|
|
public CurveList(List<Curve> curves) => Curves = curves;
|
2025-04-24 20:56:44 +08:00
|
|
|
|
}
|