Files
MsAddIns/CenterCurveAddins/SharedCellTunnelLengthHelper.cs
2026-02-28 21:01:57 +08:00

243 lines
10 KiB
C#
Raw Permalink 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.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
}
}