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

694 lines
27 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.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using Bentley.DgnPlatformNET;
using Bentley.DgnPlatformNET.DgnEC;
using Bentley.DgnPlatformNET.Elements;
using Bentley.ECObjects.Instance;
using Bentley.ECObjects.Schema;
using Bentley.MstnPlatformNET;
using NCalc;
namespace CustomOpenItemAddins
{
/// <summary>
/// 自定义开项
/// </summary>
/// <example>var models = CustomOpenItemHelpers.GetCutstomItemLevelName("JG_ZYJSCS");</example>
public class CustomOpenItemHelpers
{
/// <summary>
/// 公式计算结果
/// </summary>
/// <param name="formula"></param>
/// <param name="parameters"></param>
/// <returns></returns>
public static double EvaluateFormula(string formula, Dictionary<string, object> parameters)
{
double result = default;
try
{
Expression e = new Expression(formula);
e.Parameters = parameters;
var obj = e.Evaluate();
result = Convert.ToDouble(obj);
}
catch (Exception ex)
{
MessageCenter.Instance.ShowInfoMessage($"自定义公式计算出错", $"{ex.Message}", false);
}
return result;
}
/// <summary>
/// 获取元素的图层,如果是一般单元,则按第一个子元素来获取
/// </summary>
/// <param name="element"></param>
/// <returns></returns>
private static LevelHandle GetLevel(Element element)
{
ElementPropertiesGetter getter = new ElementPropertiesGetter(element);
var lvlcache = Session.Instance.GetActiveDgnFile().GetLevelCache();
//一般单元
if (element.GetChildren().Count() > 0)
{
foreach (var elem in element.GetChildren())
{
if (elem is DisplayableElement && !elem.IsInvisible)
{
return GetLevel(elem);
}
}
}
return lvlcache.GetLevel(getter.Level, true);
}
/// <summary>
/// 按图层获取数据
/// </summary>
/// <param name="levelName">自定义开项的图层</param>
/// <returns>数据集合,Key是以逗号分隔的“围岩等级,一级开项,二级开项,三级开项,支护类型,计量方式,单位”Value是自定义开项可以从里面拿到完整的属性信息</returns>
public static Dictionary<string, CustomOpenItem> GetCutstomItemByLevelName(string levelName)
{
//获取当前激活的模型
DgnModel dgnModel = Session.Instance.GetActiveDgnModel();
//获取图层
var layer = dgnModel.GetLevelCache().GetLevelByName(levelName);
if (layer == null)
{
MessageCenter.Instance.ShowInfoMessage($"获取自定义开项出错", $"图层不存在", false);
return new Dictionary<string, CustomOpenItem>();
}
var elements = dgnModel.GetGraphicElements().Where(e => e.LevelId == layer.LevelId || GetLevel(e).LevelId == layer.LevelId);
var items = AnalyzeElements(elements);
//StringBuilder sb = new StringBuilder();
//sb.AppendLine("元素Id,元素类型,围岩等级,一级开项,二级开项,三级开项,支护类型,计量方式,单位,结果");
//foreach (var item in items)
//{
// sb.AppendLine(item.ToString());
//}
//对集合Items中的元素进行对比如果有相同的元素则合并判断相同的元素通过Item的TypeOfSurroundingPrimarySubDetailMeasurementUnitFormula来判断
//合并后的元素的Result为合并后的元素的Result之和
var mergedItems = new Dictionary<string, CustomOpenItem>();
foreach (var item in items)
{
var key = $"{item.TypeOfSurrounding},{item.Primary},{item.Sub},{item.Detail},{item.Proof},{item.Measurement},{item.Unit}";
if (!mergedItems.ContainsKey(key))
{
mergedItems[key] = new CustomOpenItem()
{
Unit = item.Unit,
Measurement = item.Measurement,
Formula = item.Formula,
TypeOfSurrounding = item.TypeOfSurrounding,
Primary = item.Primary,
Sub = item.Sub,
Detail = item.Detail,
Proof = item.Proof,
};
}
mergedItems[key].Result += item.Result;
mergedItems[key].Count++;
}
//foreach (var item in mergedItems)
//{
// sb.AppendLine($",,{item.Key},{item.Value.Result}{item.Value.Unit}数量:{item.Value.Count}");
//}
return mergedItems;
//File.WriteAllText($"{Environment.GetFolderPath(Environment.SpecialFolder.Desktop)}\\ElementOpenItem.csv", sb.ToString(), Encoding.UTF8);
}
private static List<ElementOpenItem> AnalyzeElements(IEnumerable<Element> elements)
{
List<ElementOpenItem> items = new List<ElementOpenItem>();
foreach (var elem in elements)
{
items.Add(ToOpenItem(elem));
}
return items;
}
private static ElementOpenItem ToOpenItem(Element elem)
{
return new ElementOpenItem()
{
TypeOfSurrounding = GetPropertyValueByName(elem, "TC-300-围岩等级")?.ToString().Trim(),
Primary = GetPropertyValueByName(elem, "ID-100-一级开项")?.ToString().Trim(),
Sub = GetPropertyValueByName(elem, "ID-100-二级开项")?.ToString().Trim(),
Detail = GetPropertyValueByName(elem, "ID-100-三级开项")?.ToString().Trim(),
Proof = GetPropertyValueByName(elem, "TC-300-围岩类型")?.ToString().Trim(),
Measurement = GetPropertyValueByName(elem, "ID-100-计量方式")?.ToString().Trim(),
Unit = GetPropertyValueByName(elem, "ID-100-单位")?.ToString().Trim(),
Formula = GetPropertyValueByName(elem, "ID-100-公式")?.ToString().Trim(),
AssociateElement = elem,
};
}
/// <summary>
/// 通过属性名获取属性值
/// </summary>
/// <param name="elem">元素</param>
/// <param name="classDefinitionName">属性分组</param>
/// <param name="propName">属性名</param>
/// <returns>属性值,可根据情况进行转换数据类型</returns>
public static Dictionary<string, object> GetPropertyValueByClass(Element elem, string classDefinitionName)
{
var dict = new Dictionary<string, object>();
var instances = new CustomItemHost(elem, false).CustomItems;
object value = default;
foreach (var instance in instances)
{
if (instance.ClassDefinition.DisplayLabel.Contains(classDefinitionName) && instance.ContainsValues)
{
foreach (var propValue in instance)
{
if (propValue.TryGetNativeValue(out value))
{
dict.Add(propValue.Property.DisplayLabel, value);
}
}
}
}
return dict;
}
/// <summary>
/// 通过属性名获取属性值
/// </summary>
/// <param name="elem">元素</param>
/// <param name="propName">属性名</param>
/// <returns>属性值,可根据情况进行转换数据类型</returns>
public static object GetPropertyValueByName(Element elem, string propName)
{
var instances = new CustomItemHost(elem, false).CustomItems;
object value = default;
foreach (var instance in instances)
{
if (instance.ContainsValues)
{
foreach (var propValue in instance)
{
if (propValue.Property.DisplayLabel == propName && propValue.TryGetNativeValue(out value))
{
break;
}
}
}
}
return value;
}
/// <summary>
/// 获取元素的长度
/// </summary>
/// <param name="elem">元素</param>
/// <returns>长度值单位m</returns>
public static double GetLength(Element elem)
{
var uorMeter = Session.Instance.GetActiveDgnModel().GetModelInfo().UorPerMeter;
double length = default;
if (elem is LineElement line)
{
length = line.GetCurveVector().SumOfLengths();
}
if (elem is ComplexStringElement complexString)
{
length = complexString.GetCurveVector().SumOfLengths();
}
if (elem is LineStringBaseElement lineStringBase)
{
length = lineStringBase.GetCurveVector().SumOfLengths();
}
if (elem is EllipseElement ellipseElement)
{
length = ellipseElement.GetCurveVector().SumOfLengths();
}
if (elem is ComplexShapeElement complexShape)
{
length = complexShape.GetCurveVector().SumOfLengths();
}
if (elem is BSplineCurveElement bSplineCurve)
{
length = bSplineCurve.GetCurveVector().SumOfLengths();
}
return length / uorMeter;
}
/// <summary>
/// 获取属性
/// </summary>
/// <param name="element"></param>
public static List<IECPropertyValue> GetPropertiesByName(Element element, string propName)
{
if (null == element)
{
MessageCenter.Instance.ShowInfoMessage("所提供Element无效", $"{nameof(element)}", false);
return null;
}
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.IsArray)
{
IECArrayValue arrayVal = propertyValue as IECArrayValue;
if (arrayVal.Count >= 1)
propertyValue = arrayVal[0];
}
var prop = propertyEnum.Current.Name;
ECNameValidation.DecodeFromValidName(ref prop);
var displayLabel = propertyEnum.Current.DisplayLabel;
ECNameValidation.DecodeFromValidName(ref displayLabel);
if (propName == prop || displayLabel == propName)
{
eCProperties.Add(propertyValue);
}
}
}
return eCProperties;
}
}
/// <summary>
/// 自定义开项的内容
/// </summary>
public class CustomOpenItem
{
/// <summary>
/// 围岩等级
/// </summary>
public string TypeOfSurrounding { get; set; }
/// <summary>
/// 计量单位
/// </summary>
public string Unit { get; set; }
/// <summary>
/// 表格
/// </summary>
public string Sheet { get; set; }
/// <summary>
/// 一级开项
/// </summary>
public string Primary { get; set; }
/// <summary>
/// 二级开项
/// </summary>
public string Sub { get; set; }
/// <summary>
/// 细项
/// </summary>
public string Detail { get; set; }
/// <summary>
/// 支护类型
/// </summary>
public string Proof { get; set; }
/// <summary>
/// 计量方式
/// </summary>
public string Measurement { get; set; }
/// <summary>
/// 公式
/// </summary>
public string Formula { get; set; }
/// <summary>
/// 结果值
/// </summary>
public virtual double Result { get; set; }
/// <summary>
/// 开项元素个数
/// </summary>
public double Count { get; set; }
}
/// <summary>
/// 元素项,从模型属性读取的数据
/// </summary>
public class ElementOpenItem : CustomOpenItem
{
public Element AssociateElement { get; set; }
private readonly double uorMeter = Session.Instance.GetActiveDgnModel().GetModelInfo().UorPerMeter;
//public ElementOpenItem(string measure, List<Element> elements)
//{
// MeasurementMode = GetMeasurement(measure);
// AssociateElements = elements;
//}
public override string ToString()
{
return $"{AssociateElement.ElementId},{AssociateElement.Description},{TypeOfSurrounding},{Primary},{Sub},{Detail},{Proof},{Measurement},{Unit},{Result}{Unit}";
}
/// <summary>
/// 信息
/// </summary>
public StringBuilder Message { get; private set; }
/// <summary>
/// 平方米
/// </summary>
/// <returns></returns>
private double GetArea()
{
//StringBuilder sb = new StringBuilder();
double area = default;
var prop = CustomOpenItemHelpers.GetPropertiesByName(AssociateElement, "SurfaceArea").FirstOrDefault();
if (prop != null)
{
prop.TryGetNativeValue(out var value);
double d = Convert.ToDouble(value) / (uorMeter * uorMeter);
//sb.AppendLine($"父元素{AssociateElement.ElementId}{AssociateElement.Description};面积:{d}");
area += d;
}
if (AssociateElement is CellHeaderElement cellElem)
{
foreach (var child in cellElem.GetChildren())
{
var childProp = CustomOpenItemHelpers.GetPropertiesByName(child, "SurfaceArea").FirstOrDefault();
if (childProp != null)
{
childProp.TryGetNativeValue(out var value);
double d = Convert.ToDouble(value) / (uorMeter * uorMeter);
//sb.AppendLine($"父元素{AssociateElement.ElementId}{AssociateElement.Description}中的子元素{child.ElementId}{child.Description};面积:{d}");
area += d;
}
}
}
else if (AssociateElement is SharedCellElement sharedCell)
{
var definition = sharedCell.GetDefinition(Session.Instance.GetActiveDgnFile());
foreach (var child in definition.GetChildren())
{
var childProp = CustomOpenItemHelpers.GetPropertiesByName(child, "SurfaceArea").FirstOrDefault();
if (childProp != null)
{
childProp.TryGetNativeValue(out var value);
double d = Convert.ToDouble(value) / (uorMeter * uorMeter);
//sb.AppendLine($"父元素{AssociateElement.ElementId}{AssociateElement.Description}中的子元素{child.ElementId}{child.Description};面积:{d}");
area += d;
}
}
}
return Math.Round(area, 3, MidpointRounding.AwayFromZero);
}
/// <summary>
/// 米
/// </summary>
/// <returns></returns>
private double GetLength()
{
double length = CustomOpenItemHelpers.GetLength(AssociateElement);
//Message = sb;
return Math.Round(length, 3, MidpointRounding.AwayFromZero);
}
private MeasurementMode GetMeasurement(string measure)
{
if (string.IsNullOrEmpty(measure))
{
return MeasurementMode.Unknow;
}
else if (measure == "个数")
{
return MeasurementMode.Count;
}
else if (measure == "长度")
{
return MeasurementMode.Length;
}
else if (measure == "面积")
{
return MeasurementMode.Area;
}
else if (measure == "体积")
{
return MeasurementMode.Volume;
}
else if (measure == "公式")
{
return MeasurementMode.Formula;
}
return MeasurementMode.Unknow;
}
/// <summary>
/// 立方米
/// </summary>
/// <returns></returns>
private double GetVolume()
{
double volume = default;
//StringBuilder sb = new StringBuilder();
//直接可以读取
var prop = CustomOpenItemHelpers.GetPropertiesByName(AssociateElement, "Volume").FirstOrDefault();
if (prop != null)
{
prop.TryGetNativeValue(out var value);
double d = Convert.ToDouble(value) / (uorMeter * uorMeter * uorMeter);
//sb.AppendLine($"父元素{AssociateElement.ElementId}{AssociateElement.Description};体积:{d}");
volume += d;
}
//一般单元,能看到子元素
if (AssociateElement.GetChildren().Count() > 0)
{
foreach (var child in AssociateElement.GetChildren())
{
var childProp = CustomOpenItemHelpers.GetPropertiesByName(child, "Volume").FirstOrDefault();
if (childProp != null)
{
childProp.TryGetNativeValue(out var value);
double d = Convert.ToDouble(value) / (uorMeter * uorMeter * uorMeter);
//sb.AppendLine($"父元素{AssociateElement.ElementId}{AssociateElement.Description}中的子元素{child.ElementId}{child.Description};体积:{d}");
volume += d;
}
}
}
//共享单元看不到子元素
if (AssociateElement is SharedCellElement sharedCell)
{
//var definition = sharedCell.GetDefinition(Session.Instance.GetActiveDgnFile());
DropGeometry geom = new DropGeometry();
geom.SetOptions(DropGeometry.Options.OPTION_SharedCells);
geom.SetSharedCellOptions(DropGeometry.SharedCells.SHAREDCELL_Geometry);
//ElementAgenda agenda = new ElementAgenda();
var status = MstnMixedAssistant.ElementOperation.DropElement(sharedCell, out var agenda, geom);
if (status == StatusInt.Success)
{
for (uint i = 0; i < agenda.GetCount(); i++)
{
var child = agenda.GetEntry(i);
var childProp = CustomOpenItemHelpers.GetPropertiesByName(child, "Volume").FirstOrDefault();
//第一次打散后,但是还是找不到体积属性,需要二次打散
if (childProp == null)
{
DropGeometry geomSub = new DropGeometry();
geomSub.SetOptions(DropGeometry.Options.OPTION_AppData);
geomSub.SetSolidsOptions(DropGeometry.Solids.SOLID_Surfaces);
var statusSub = MstnMixedAssistant.ElementOperation.DropElement(child, out var agendaSub, geomSub);
if (statusSub == StatusInt.Success)
{
for (uint j = 0; j < agendaSub.GetCount(); j++)
{
var childSub = agendaSub.GetEntry(j);
var childPropSub = CustomOpenItemHelpers.GetPropertiesByName(childSub, "Volume").FirstOrDefault();
if (childPropSub != null)
{
childPropSub.TryGetNativeValue(out var valueSub);
double dSub = Convert.ToDouble(valueSub) / (uorMeter * uorMeter * uorMeter);
volume += dSub;
}
}
}
}
else
{
childProp.TryGetNativeValue(out var value);
double d = Convert.ToDouble(value) / (uorMeter * uorMeter * uorMeter);
volume += d;
}
//sb.AppendLine($"父元素{AssociateElement.ElementId}{AssociateElement.Description}中的子元素{child.ElementId}{child.Description};体积:{d}");
}
}
}
//Message = sb;
return Math.Round(volume, 3, MidpointRounding.AwayFromZero);
}
/// <summary>
/// 通过公式计算结果
/// </summary>
/// <returns></returns>
private double GetValueByFormula()
{
if (!string.IsNullOrEmpty(Formula) || !string.IsNullOrWhiteSpace(Formula))
{
try
{
var parameters = CustomOpenItemHelpers.GetPropertyValueByClass(AssociateElement, "计算公式参数");
var result = CustomOpenItemHelpers.EvaluateFormula(Formula, parameters);
return Math.Round(result, 3, MidpointRounding.AwayFromZero);
}
catch (Exception ex)
{
MessageCenter.Instance.ShowInfoMessage($"公式计算失败", $"{ex.Message}", false);
}
}
return 0.0;
}
//private int GetCount()
//{
// StringBuilder sb = new StringBuilder();
// foreach (var AssociateElement in AssociateElements)
// {
// sb.AppendLine($"父元素{AssociateElement.ElementId}{AssociateElement.Description}个数1");
// }
// Message = sb;
// return 1;
//}
/// <summary>
/// 计量方式
/// </summary>
public MeasurementMode MeasurementMode => GetMeasurement(Measurement);
/// <summary>
/// 计算结果
/// </summary>
public override double Result
{
get
{
double result = 0.0;
switch (MeasurementMode)
{
case MeasurementMode.Count:
result = 1;
//result = GetCount();
break;
case MeasurementMode.Length:
result = GetLength();
if (!string.IsNullOrEmpty(Unit))
{
//if (Unit == "m" && Unit == "米")
//{
//}
if (Unit == "cm" || Unit == "厘米")
{
result *= 100;
}
if (Unit == "mm" || Unit == "毫米")
{
result *= 1000;
}
}
else
{
Unit = "m";
}
break;
case MeasurementMode.Area:
result = GetArea();
if (!string.IsNullOrEmpty(Unit))
{
//if (Unit == "m²" && Unit == "m2" && Unit == "平方米")
//{
// result = area;
//}
if (Unit == "cm²" || Unit == "平方厘米" || Unit == "cm2")
{
result *= 10000;
}
if (Unit == "mm²" || Unit == "平方毫米" || Unit == "mm2")
{
result *= 1000000;
}
}
else
{
Unit = "m²";
}
break;
case MeasurementMode.Volume:
result = GetVolume();
if (!string.IsNullOrEmpty(Unit))
{
//if (Unit == "m³" && Unit == "m3" && Unit == "立方米")
//{
//}
if (Unit == "cm³" || Unit == "立方厘米" || Unit == "cm3")
{
result *= 1000000;
}
if (Unit == "mm³" || Unit == "立方毫米" || Unit == "mm3")
{
result *= 1000000000;
}
}
else
{
Unit = "m³";
}
break;
case MeasurementMode.Formula:
result = GetValueByFormula();
break;
case MeasurementMode.Unknow:
break;
}
return result;
}
}
}
/// <summary>
/// 计量方式
/// </summary>
public enum MeasurementMode
{
[Description("未知")]
Unknow,
[Description("个数")]
Count,
[Description("长度")]
Length,
[Description("面积")]
Area,
[Description("体积")]
Volume,
[Description("公式")]
Formula
}
}