Files
SzmediTools/Szmedi.RvKits/Assists/CurveUtils.cs
2025-09-16 16:06:41 +08:00

339 lines
14 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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);
// }
// }
// }
//}
}
}