Files
MsAddIns/CenterCurveAddins/SharedCellTunnelLengthHelper.cs

243 lines
10 KiB
C#
Raw Permalink Normal View History

2026-02-28 21:01:57 +08:00
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using Bentley.DgnPlatformNET;
using Bentley.DgnPlatformNET.DgnEC;
using Bentley.DgnPlatformNET.Elements;
using Bentley.ECObjects.Instance;
using Bentley.ECObjects.Schema;
using Bentley.GeometryNET;
using Bentley.MstnPlatformNET;
namespace CenterCurveAddins
{
internal class SharedCellTunnelLengthHelper
{
#region
/// <summary>
/// 包围盒中心点
/// </summary>
/// <returns></returns>
private static HashSet<DPoint3d> GetBoundingBoxCentroid(HashSet<SharedCellElement> cellElements)
{
var hashSet = new HashSet<DPoint3d>();
foreach (var element in cellElements)
{
// 获取元素的范围,使用单位矩阵获取模型坐标系中的范围
var status = element.CalcElementRange(out var range);
if (!range.IsNull() && status == StatusInt.Success)
{
var center = (range.Low + range.High) * 0.5;
hashSet.Add(center);
}
}
return hashSet;
}
/// <summary>
/// 判断元素是否是曲线
/// </summary>
/// <param name="elem">元素</param>
/// <returns>是否是曲线</returns>
private static bool IsCurve(Element elem)
{
return elem is LineElement ||
elem is ComplexStringElement ||
elem is LineStringBaseElement ||
elem is EllipseElement ||
elem is ComplexShapeElement ||
elem is BSplineCurveElement;
}
/// <summary>
/// 通过点分布获取中心线
/// </summary>
/// <param name="listLineMilGeoData"></param>
/// <param name="listPtAll"></param>
/// <returns></returns>
private static Element GetCenterLine(List<Element> listLineMilGeoData, HashSet<DPoint3d> listPtAll)
{
Element targetLine = null;
//随机取点
var pt3dMid = listPtAll.FirstOrDefault();
if (listPtAll == null || listPtAll.Count == 0)
{
return targetLine;
}
double dDisMin = double.MaxValue;
//找到距离点最近的线元素
foreach (var item in listLineMilGeoData)
{
CurveVector cv = CurvePathQuery.ElementToCurveVector(item);
if (cv == null)
{
continue;
}
CurveLocationDetail curLocDetail = cv.ClosestPointBounded(pt3dMid);
if (curLocDetail == null)
{
continue;
}
double dDis = pt3dMid.DistanceXY(curLocDetail.Point);
if (dDis < dDisMin)
{
dDisMin = dDis;
targetLine = item;
}
}
return targetLine;
}
/// <summary>
/// 获取共享单元在最近的中线投影长度
/// </summary>
/// <param name="cellElements">同一个类型的Cell实体</param>
/// <param name="centerLineLevel">中心线所在图层起始字符如DG-ZZX</param>
/// <returns></returns>
private static double GetCellsProjectLength(HashSet<SharedCellElement> cellElements, string centerLineLevel)
{
if (cellElements.Count == 0)
{
return 0.0;
}
DgnModel dgnModel = Session.Instance.GetActiveDgnModel();
var levelCache = dgnModel.GetLevelCache();
//过滤获取线条元素,即所有中心线
var listLineMilGeoData = dgnModel.GetElements()
.Where(
e => e.IsValid &&
!e.IsInvisible &&
levelCache.GetLevel(e.LevelId)?.DisplayName.Trim().StartsWith(centerLineLevel) == true &&
IsCurve(e))
.ToList();
//曲面拍平的所有点
var listPtAll = GetBoundingBoxCentroid(cellElements);
//通过点分布获取中心线
var targetLine = GetCenterLine(listLineMilGeoData, listPtAll);
if (targetLine != null)
{
CurveVector curveVector = CurvePathQuery.ElementToCurveVector(targetLine);
//找到曲面拍平的 所有点 到 平面距离最近中心线上的点
var locs = listPtAll.Select(curveVector.ClosestPointBoundedXY);
var ordered = locs.OrderBy(loc => curveVector.CurveLocationDetailIndex(loc)).ThenBy(loc => loc.Fraction);
var min = ordered.FirstOrDefault();
var max = ordered.LastOrDefault();
var minIndex = curveVector.CurveLocationDetailIndex(min);
var maxIndex = curveVector.CurveLocationDetailIndex(max);
var minCurve = curveVector.GetPrimitive((int)minIndex);
var maxCurve = curveVector.GetPrimitive((int)maxIndex);
//拿到最大最小线段距离
minCurve.SignedDistanceBetweenFractions(0, min.Fraction, out var dist);
maxCurve.SignedDistanceBetweenFractions(0, max.Fraction, out var dist1);
//var l = (dist1 - dist) / Session.Instance.GetActiveDgnModel().GetModelInfo().UorPerMeter > 5000;
if (minIndex == maxIndex) //是否在同一条线上
{
return (dist1 - dist) / Session.Instance.GetActiveDgnModel().GetModelInfo().UorPerMeter;
}
else if (maxIndex > minIndex)
{
minCurve.Length(out var minLength);
//maxCurve.Length(out var maxlength);
var minDis = minLength - dist;//前置曲线的后半段
//var maxDis = max.Fraction * maxlength;//后置曲线的前半段
var length = minDis + dist1;
if (maxIndex - minIndex > 1)//不连续,中间还有其他的线
{
for (var i = minIndex + 1; i < maxIndex; i++)
{
curveVector.GetPrimitive((int)i).Length(out var l);
length += l;
}
}
return length / Session.Instance.GetActiveDgnModel().GetModelInfo().UorPerMeter;
}
}
return 0.0;
}
/// <summary>
/// 根据元素类型名称,获取对应元素在中心线上的投影长度
/// </summary>
/// <param name="centerLineLevel">中心线图层起始字符串中线可能在两个图层上DG-ZZX</param>
/// <param name="modelLevel">共享单元所在图层</param>
/// <returns>网格元素和投影长度的集合</returns>
/// <remarks>如果是</remarks>
public static Dictionary<string, double> GetSharedCellProjectLength(string centerLineLevel, string modelLevel)
{
Dictionary<string, double> cellLengthDictionary = new Dictionary<string, double>();
DgnModel dgnModel = Session.Instance.GetActiveDgnModel();
var levelCache = dgnModel.GetLevelCache();
try
{
var sharedCellElements = dgnModel.GetElements()
.Where(e => e.IsValid && !e.IsInvisible && (levelCache.GetLevel(e.LevelId)?.DisplayName.Trim().ToUpper() == modelLevel) && e is SharedCellElement).Cast<SharedCellElement>().ToHashSet();
var groups = sharedCellElements.GroupBy(cell => GetProperyValues(cell, "ID-100-名称").FirstOrDefault().NativeValue.ToString());
foreach (var group in groups)
{
var length = GetCellsProjectLength(sharedCellElements, centerLineLevel);
cellLengthDictionary.Add(group.Key, length);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
return cellLengthDictionary;
}
/// <summary>
/// 获取所有属性
/// </summary>
/// <param name="element"></param>
private static List<IECPropertyValue> GetProperyValues(Element element, string propName)
{
if (null == element)
{
throw new ArgumentNullException(nameof(element), "所提供ElemId无效");
}
List<IECPropertyValue> eCProperties = new List<IECPropertyValue>();
DgnECManager ecManager = DgnECManager.Manager;
int count = 0;
DgnECInstanceCollection instCol = ecManager.GetElementProperties(element, ECQueryProcessFlags.SearchAllClasses);
foreach (IDgnECInstance inst in instCol)
{
count++;
IEnumerator<IECProperty> propertyEnum = inst.ClassDefinition.GetEnumerator();
while (propertyEnum.MoveNext())
{
IECPropertyValue propertyValue = inst.GetPropertyValue(propertyEnum.Current.Name);
if (propertyValue == null)
{
continue;
}
if (propertyValue.IsArray)
{
IECArrayValue arrayVal = propertyValue as IECArrayValue;
if (arrayVal.Count >= 1)
propertyValue = arrayVal[0];
}
var prop = propertyEnum.Current.Name;
ECNameValidation.DecodeFromValidName(ref prop);
if (propName == prop)
{
eCProperties.Add(propertyValue);
}
}
}
return eCProperties;
}
#endregion
}
}