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 { /// /// 自定义开项 /// /// var models = CustomOpenItemHelpers.GetCutstomItemLevelName("JG_ZYJSCS"); public class CustomOpenItemHelpers { public static double EvaluateFormula(string formula, Dictionary 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; } /// /// 获取元素的图层,如果是一般单元,则按第一个子元素来获取 /// /// /// 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); } /// /// 按图层获取数据 /// /// 自定义开项的图层 /// 数据集合,Key是以逗号分隔的“围岩等级,一级开项,二级开项,三级开项,支护类型,计量方式,单位”;Value是自定义开项,可以从里面拿到完整的属性信息 public static Dictionary GetCutstomItemByLevelName(string levelName) { //获取当前激活的模型 DgnModel dgnModel = Session.Instance.GetActiveDgnModel(); //获取图层 var layer = dgnModel.GetLevelCache().GetLevelByName(levelName); if (layer == null) { MessageCenter.Instance.ShowInfoMessage($"获取自定义开项出错", $"图层不存在", false); return new Dictionary(); } var elements = dgnModel.GetElements().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的TypeOfSurrounding,Primary,Sub,Detail,Measurement,Unit,Formula来判断 //合并后的元素的Result为合并后的元素的Result之和 var mergedItems = new Dictionary(); 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 AnalyzeElements(IEnumerable elements) { List items = new List(); 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, }; } /// /// 通过属性名获取属性值 /// /// 元素 /// 属性分组 /// 属性名 /// 属性值,可根据情况进行转换数据类型 public static Dictionary GetPropertyValueByClass(Element elem, string classDefinitionName) { var dict = new Dictionary(); var instances = new CustomItemHost(elem, false).CustomItems; object value = default; foreach (var instance in instances) { if (instance.ClassDefinition.DisplayLabel == classDefinitionName && instance.ContainsValues) { foreach (var propValue in instance) { if (propValue.TryGetNativeValue(out value)) { dict.Add(propValue.Property.DisplayLabel, value); } } } } return dict; } /// /// 通过属性名获取属性值 /// /// 元素 /// 属性名 /// 属性值,可根据情况进行转换数据类型 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; } /// /// 获取元素的长度 /// /// 元素 /// 长度值,单位m 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; } /// /// 获取属性 /// /// public static List GetPropertiesByName(Element element, string propName) { if (null == element) { throw new ArgumentNullException(nameof(element), "所提供ElemId无效"); } List eCProperties = new List(); DgnECManager ecManager = DgnECManager.Manager; int count = 0; DgnECInstanceCollection instCol = ecManager.GetElementProperties(element, ECQueryProcessFlags.SearchAllClasses); foreach (IDgnECInstance inst in instCol) { count++; IEnumerator 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; } } /// /// 自定义开项的内容,从模型属性读取的数据 /// public class CustomOpenItem { /// /// 围岩等级 /// public string TypeOfSurrounding { get; set; } /// /// 计量单位 /// public string Unit { get; set; } /// /// 表格 /// public string Sheet { get; set; } /// /// 一级开项 /// public string Primary { get; set; } /// /// 二级开项 /// public string Sub { get; set; } /// /// 细项 /// public string Detail { get; set; } /// /// 支护类型 /// public string Proof { get; set; } /// /// 计量方式 /// public string Measurement { get; set; } /// /// 公式 /// public string Formula { get; set; } /// /// 结果值 /// public virtual double Result { get; set; } /// /// 开项元素个数 /// public double Count { get; set; } } public class ElementOpenItem : CustomOpenItem { public Element AssociateElement { get; set; } private readonly double uorMeter = Session.Instance.GetActiveDgnModel().GetModelInfo().UorPerMeter; //public ElementOpenItem(string measure, List elements) //{ // MeasurementMode = GetMeasurement(measure); // AssociateElements = elements; //} public override string ToString() { return $"{AssociateElement.ElementId},{AssociateElement.Description},{TypeOfSurrounding},{Primary},{Sub},{Detail},{Proof},{Measurement},{Unit},{Result}{Unit}"; } /// /// 信息 /// public StringBuilder Message { get; private set; } /// /// 平方米 /// /// 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); } /// /// 米 /// /// 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; } /// /// 立方米 /// /// 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); } private double GetValueByFormula() { if (!string.IsNullOrEmpty(Formula) || !string.IsNullOrWhiteSpace(Formula)) { try { var parameters = CustomOpenItemHelpers.GetPropertyValueByClass(AssociateElement, "计算公式参数"); return CustomOpenItemHelpers.EvaluateFormula(Formula, parameters); } 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; //} /// /// 计量方式 /// public MeasurementMode MeasurementMode => GetMeasurement(Measurement); /// /// 计算结果 /// public override double Result { get { double result = 0.0; switch (MeasurementMode) { case MeasurementMode.Count: result = 1; break; case MeasurementMode.Length: var length = GetLength(); if (Unit != "m" && Unit != "米") { result = length; } else if (Unit == "cm" || Unit == "厘米") { result = length * 100; } else if (Unit == "mm" || Unit == "毫米") { result = length * 1000; } else { result = length; } break; case MeasurementMode.Area: var area = GetArea(); if (Unit != "m²" && Unit != "m2" && Unit != "平方米") { result = area; } else if (Unit == "cm²" || Unit == "平方厘米" || Unit == "cm2") { result = area * 10000; } else if (Unit == "mm²" || Unit == "平方毫米" || Unit == "mm2") { result = area * 1000000; } else { result = area; } break; case MeasurementMode.Volume: var volume = GetVolume(); if (Unit != "m³" && Unit != "m3" && Unit != "立方米") { result = volume; } else if (Unit == "cm³" || Unit == "立方厘米" || Unit == "cm3") { result = volume * 1000000; } else if (Unit == "mm³" || Unit == "立方毫米" || Unit == "mm3") { result = volume * 1000000000; } else { result = volume; } break; case MeasurementMode.Formula: result = GetValueByFormula(); if (Unit == "个" || Unit == "套" || Unit == "根" || Unit == "孔") { result = Math.Round(result, 0, MidpointRounding.AwayFromZero); } else { result = Math.Round(result, 3, MidpointRounding.AwayFromZero); } break; case MeasurementMode.Unknow: break; } return result; } } } /// /// 计量方式 /// public enum MeasurementMode { [Description("未知")] Unknow, [Description("个数")] Count, [Description("长度")] Length, [Description("面积")] Area, [Description("体积")] Volume, [Description("公式")] Formula } }