Files

339 lines
14 KiB
C#
Raw Permalink Normal View History

2025-09-16 16:06:41 +08:00

using System;
using System.Diagnostics;
using System.Linq;
using System.Windows;
using Autodesk.Revit.DB;
namespace Szmedi.RvKits.Assists
{
public class CurveUtils
{
//private List<Curve> curvesSorted;
//private void SortOpenedContinuousCurves(Curve initCurve, List<Curve> 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];
// //当两段直线几乎平行且交于一点时会判断错误变成subset子集关系
// //TODO
// var comparisonR = initCurve.Intersect(sourceCurves[i], out var _);
// if (comparisonR == SetComparisonResult.Disjoint && initCurve is Arc && sourceCurves[i] is Arc)
// {
// var l = new List<Curve>() { initCurve, sourceCurves[i] };
// try
// {
// var cl = CurveLoop.Create(l);//如果报错,说明两个半圆没形成圆,是不连续的;
// curvesSorted = l;
// 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);
// }
// }
//}
/// <summary>
/// 对曲线列表进行排序,使其正确排序和定向,形成闭合回路。
/// </summary>
public static bool SortCurvesContiguous(IList<Curve> curves, bool debug_output = false)
{
const double _inch = 1.0 / 12.0;
const double _sixteenth = _inch / 16.0;
int n = curves.Count;
for (int i = 0; i < n; ++i)
{
Curve curve = curves[i];
XYZ endPoint = curve.GetEndPoint(1);
XYZ p;
// 查找起点 = 终点的曲线
bool found = (i + 1 >= n);
for (int j = i + 1; j < n; ++j)
{
p = curves[j].GetEndPoint(0);
// 如果匹配 end->start、
// 这是下一条曲线
if (_sixteenth > p.DistanceTo(endPoint))
{
if (debug_output)
{
Debug.Print("{0} 起始点, 换成 {1}", j, i + 1);
}
if (i + 1 != j)
{
Curve tmp = curves[i + 1];
curves[i + 1] = curves[j];
curves[j] = tmp;
}
found = true;
break;
}
p = curves[j].GetEndPoint(1);
// 如果有匹配结果 end->end、
// 反转下一条曲线
if (_sixteenth > p.DistanceTo(endPoint))
{
if (i + 1 == j)
{
if (debug_output)
{
Debug.Print("{0} 终点, 反向 {1}", j, i + 1);
}
curves[i + 1] = curves[j].CreateReversed();
}
else
{
if (debug_output)
{
Debug.Print("{0} 终点, 倒换 {1}", j, i + 1);
}
Curve tmp = curves[i + 1];
curves[i + 1] = curves[j].CreateReversed();
curves[j] = tmp;
}
found = true;
break;
}
}
if (!found)
{
return false;
}
}
return true;
}
/// <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--)
{
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 List<List<Curve>> GetCurvesOfLoops(List<Curve> curves)
//{
// List<List<Curve>> list = new();
// 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)
// {
// MessageBox.Show(ex.StackTrace);
// }
// list.Add(curvesSorted);
// if (!curves.Any())
// {
// break;
// }
// }
// return list;
//}
/// <summary>
/// 递归找到所有连接在一起的线圈并分好组
/// </summary>
/// <param name="curves">所有线</param>
/// <param name="initcurve">用于查找与其连接的初始线</param>
/// <param name="initCurveArray">初始的线串</param>
/// <param name="curveArrArray">所有线串的集合</param>
//private void SearchCurveConnected(List<Curve> curves, Curve initcurve, CurveArray initCurveArray, CurveArrArray curveArrArray)
//{
// if (curveArrArray.Size == 0)
// {
// curveArrArray.Append(initCurveArray);
// }
// for (int i = 0; i < curves.Count; i++)
// {
// Curve tempCurve = curves[i];
// XYZ baseEndXyz = initcurve.GetEndPoint(0);
// //把初始的第一个添加进集合
// if (tempCurve.GetEndPoint(0).IsAlmostEqualTo(baseEndXyz) || tempCurve.GetEndPoint(1).IsAlmostEqualTo(baseEndXyz))//可以为重合的线
// {
// initCurveArray.Append(tempCurve);
// curves.Remove(tempCurve);
// //将tempcurve作为起点继续查找
// SearchCurveConnected(curves, tempCurve, initCurveArray, curveArrArray);//最后一次执行方法在此处因为Count为0停止继续执行
// }
// //遍历完一个线串时,寻找下一个线串,即查找到最后,都找不到相连的曲线时
// if (i == curves.Count() - 1)
// {
// initCurveArray = new CurveArray();//下一个线串需重新建立合集
// SearchCurveConnected(curves, curves.FirstOrDefault(), initCurveArray, curveArrArray);//每有一次新的线串时执行一次,查找与其相连的线
// ////由于最后一轮运行完递归后所有线段均成组只执行上面的if内容所以没办法将剩余线加到集合中。
// if (curves.Count() == 0)
// {
// curveArrArray.Append(initCurveArray);
// }
// }
// }
//}
}
}