2024-09-22 11:05:41 +08:00
|
|
|
|
using System.Collections.ObjectModel;
|
2026-02-21 16:31:24 +08:00
|
|
|
|
using System.IO;
|
|
|
|
|
|
using System.Windows;
|
2024-09-22 11:05:41 +08:00
|
|
|
|
using System.Windows.Data;
|
2026-02-21 16:31:24 +08:00
|
|
|
|
|
2024-09-22 11:05:41 +08:00
|
|
|
|
using Autodesk.Revit.DB;
|
|
|
|
|
|
using Autodesk.Revit.DB.Architecture;
|
|
|
|
|
|
using Autodesk.Revit.DB.Electrical;
|
|
|
|
|
|
using Autodesk.Revit.DB.Mechanical;
|
|
|
|
|
|
using Autodesk.Revit.DB.Plumbing;
|
2026-02-21 16:31:24 +08:00
|
|
|
|
|
2024-09-22 11:05:41 +08:00
|
|
|
|
using CommunityToolkit.Mvvm.ComponentModel;
|
|
|
|
|
|
using CommunityToolkit.Mvvm.Input;
|
2026-02-21 16:31:24 +08:00
|
|
|
|
|
2024-09-22 11:05:41 +08:00
|
|
|
|
using Microsoft.Win32;
|
2026-02-21 16:31:24 +08:00
|
|
|
|
|
|
|
|
|
|
using MiniExcelLibs;
|
|
|
|
|
|
using MiniExcelLibs.OpenXml;
|
|
|
|
|
|
|
2024-09-22 11:05:41 +08:00
|
|
|
|
using Nice3point.Revit.Toolkit.External.Handlers;
|
2026-02-21 16:31:24 +08:00
|
|
|
|
|
2026-02-22 20:03:42 +08:00
|
|
|
|
using ShrlAlgoToolkit.RevitAddins.Common.Controls;
|
2024-09-22 11:05:41 +08:00
|
|
|
|
|
2025-04-24 20:56:44 +08:00
|
|
|
|
namespace ShrlAlgoToolkit.RevitAddins.ModelManager;
|
2024-09-22 11:05:41 +08:00
|
|
|
|
|
2026-02-12 21:29:00 +08:00
|
|
|
|
[UsedImplicitly]
|
2024-09-22 11:05:41 +08:00
|
|
|
|
public partial class ModelCheckViewModel : ObservableObject
|
|
|
|
|
|
{
|
2026-02-22 20:03:42 +08:00
|
|
|
|
private readonly Standardizer.CorrectReferLevelExecutes correctReferLevelExecutes;
|
2024-09-22 11:05:41 +08:00
|
|
|
|
|
|
|
|
|
|
private readonly ActionEventHandler modifyModel = new();
|
2025-02-10 20:53:40 +08:00
|
|
|
|
private readonly ActionEventHandler showElementsSectionBox = new();
|
2024-09-22 11:05:41 +08:00
|
|
|
|
private readonly UIApplication uiapp;
|
|
|
|
|
|
|
|
|
|
|
|
public ModelCheckViewModel(UIApplication uiapp)
|
|
|
|
|
|
{
|
|
|
|
|
|
Items = [];
|
|
|
|
|
|
var cv = CollectionViewSource.GetDefaultView(Items);
|
|
|
|
|
|
cv.GroupDescriptions.Add(new PropertyGroupDescription("ErrorMessage"));
|
2026-02-22 20:03:42 +08:00
|
|
|
|
correctReferLevelExecutes = new Standardizer.CorrectReferLevelExecutes(uiapp);
|
2024-09-22 11:05:41 +08:00
|
|
|
|
this.uiapp = uiapp;
|
|
|
|
|
|
FindBasePoint();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-02-10 20:53:40 +08:00
|
|
|
|
private bool CanExport()
|
|
|
|
|
|
{
|
|
|
|
|
|
return Items.Any();
|
|
|
|
|
|
}
|
|
|
|
|
|
private static bool CanShowElement(object obj)
|
|
|
|
|
|
{
|
|
|
|
|
|
return obj is MessageModel { IsInstance: true };
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-09-22 11:05:41 +08:00
|
|
|
|
[RelayCommand]
|
|
|
|
|
|
private /*async Task*/ void CheckModel(/*CancellationToken token*/)
|
|
|
|
|
|
{
|
|
|
|
|
|
//if (Items.Any())
|
|
|
|
|
|
//{
|
|
|
|
|
|
// Items = [];
|
|
|
|
|
|
//}
|
|
|
|
|
|
Items.Clear();
|
|
|
|
|
|
var uidoc = uiapp.ActiveUIDocument;
|
|
|
|
|
|
var doc = uidoc.Document;
|
|
|
|
|
|
//await Task.Delay(TimeSpan.FromSeconds(2), token);
|
|
|
|
|
|
//if (doc.ActiveView is not View3D view3d)
|
|
|
|
|
|
//{
|
|
|
|
|
|
// view3d = doc.OfClass<View3D>().FirstOrDefault(e => FilteredElementCollector.IsViewValidForElementIteration(doc, e.Id)) as View3D;
|
|
|
|
|
|
//}
|
2024-12-22 10:26:12 +08:00
|
|
|
|
var elements = doc.OfParentModelElements();
|
2026-02-12 21:29:00 +08:00
|
|
|
|
var typeInstancesGroups = elements.GroupBy(e => e.GetTypeId()).ToList();
|
2024-09-22 11:05:41 +08:00
|
|
|
|
if (IsCheckLevel)
|
|
|
|
|
|
{
|
|
|
|
|
|
var levels = doc.OfClass<Level>().OfType<Level>().OrderBy(l => l.Elevation);
|
2026-02-22 20:03:42 +08:00
|
|
|
|
var levelOutlines = Standardizer.CorrectReferLevelExecutes.GetRegions(levels);
|
2024-09-22 11:05:41 +08:00
|
|
|
|
foreach (var keyPair in levelOutlines)
|
|
|
|
|
|
{
|
|
|
|
|
|
//得到在标高范围内的元素
|
|
|
|
|
|
BoundingBoxIsInsideFilter insideFilter = new(keyPair.Value);
|
|
|
|
|
|
var level = keyPair.Key;
|
|
|
|
|
|
var insideCollector = new FilteredElementCollector(doc)
|
|
|
|
|
|
.WherePasses(insideFilter)
|
|
|
|
|
|
.Where(elem => elem.get_BoundingBox(doc.ActiveView) != null)
|
|
|
|
|
|
.ToList();
|
|
|
|
|
|
foreach (var elem in insideCollector)
|
|
|
|
|
|
{
|
|
|
|
|
|
var isCorrect = false;
|
|
|
|
|
|
var hasReferenceLevel = false;
|
|
|
|
|
|
foreach (Parameter param in elem.Parameters)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (param.Definition.Name.Contains("标高") || param.Definition.Name.Contains("Level"))
|
|
|
|
|
|
{
|
|
|
|
|
|
hasReferenceLevel = param.StorageType == StorageType.ElementId;
|
|
|
|
|
|
if (hasReferenceLevel)
|
|
|
|
|
|
{
|
|
|
|
|
|
var value = param.AsElementId();
|
|
|
|
|
|
isCorrect = value == ElementId.InvalidElementId || param.AsElementId() == level.Id; //扶手等对象有宿主Host时为空
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (hasReferenceLevel && !isCorrect)
|
|
|
|
|
|
{
|
|
|
|
|
|
Items.Add(new MessageModel(elem, "参照标高有误"));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (IsCheckName)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var item in typeInstancesGroups)
|
|
|
|
|
|
{
|
|
|
|
|
|
var id = item.Key;
|
|
|
|
|
|
var type = doc.GetElement(id);
|
|
|
|
|
|
var array = type.Name.Split('-');
|
2026-02-22 20:03:42 +08:00
|
|
|
|
if (array.Length < 3)
|
2024-09-22 11:05:41 +08:00
|
|
|
|
{
|
|
|
|
|
|
var errorItem = new MessageModel(type, "类型名称不符合三段式");
|
|
|
|
|
|
Items.Add(errorItem);
|
|
|
|
|
|
}
|
2026-02-22 20:03:42 +08:00
|
|
|
|
|
2024-09-22 11:05:41 +08:00
|
|
|
|
}
|
2026-02-22 20:03:42 +08:00
|
|
|
|
|
2024-09-22 11:05:41 +08:00
|
|
|
|
}
|
|
|
|
|
|
if (IsCheckProps)
|
|
|
|
|
|
{
|
2026-02-22 20:03:42 +08:00
|
|
|
|
|
2024-09-22 11:05:41 +08:00
|
|
|
|
}
|
|
|
|
|
|
if (IsCheckSlope)
|
|
|
|
|
|
{
|
|
|
|
|
|
var mepCurves = doc.OfClass<MEPCurve>().Where(e => e is not InsulationLiningBase and not FlexDuct and not FlexPipe);
|
|
|
|
|
|
foreach (var mepCurve in mepCurves)
|
|
|
|
|
|
{
|
|
|
|
|
|
var isError = false;
|
|
|
|
|
|
if (mepCurve is Pipe)
|
|
|
|
|
|
{
|
|
|
|
|
|
var param = mepCurve.get_Parameter(BuiltInParameter.RBS_PIPE_SLOPE);
|
|
|
|
|
|
isError = param.HasValue && ((param.AsDouble() < 0.25 && param.AsDouble() > 10E-6) || param.AsDouble() > Math.PI); //坡度过大或过小时,90度时AsDouble为0
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (mepCurve is Duct)
|
|
|
|
|
|
{
|
|
|
|
|
|
var param = mepCurve.get_Parameter(BuiltInParameter.RBS_DUCT_SLOPE);
|
|
|
|
|
|
isError = param.HasValue && ((param.AsDouble() < 0.25 && param.AsDouble() > 10E-6) || param.AsDouble() > Math.PI); //坡度过大或过小时,90度时AsDouble为0
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (mepCurve is Conduit or CableTray)
|
|
|
|
|
|
{
|
|
|
|
|
|
var p1 = mepCurve.get_Parameter(BuiltInParameter.RBS_START_OFFSET_PARAM).AsDouble();
|
|
|
|
|
|
var p2 = mepCurve.get_Parameter(BuiltInParameter.RBS_END_OFFSET_PARAM).AsDouble();
|
|
|
|
|
|
var l = mepCurve.get_Parameter(BuiltInParameter.CURVE_ELEM_LENGTH).AsDouble();
|
|
|
|
|
|
var sin = Math.Abs(p1 - p2) / l;
|
|
|
|
|
|
var radian = Math.Asin(sin);
|
|
|
|
|
|
var slope = Math.Tan(radian);
|
|
|
|
|
|
isError = slope is (> 10E-6 and < 0.25) || (slope > Math.PI && Math.Abs(radian - Math.PI / 2) > 10E-6);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (isError)
|
|
|
|
|
|
{
|
|
|
|
|
|
var errorItem = new MessageModel(mepCurve, "管线坡度有误差");
|
|
|
|
|
|
Items.Add(errorItem);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (IsCheckLength)
|
|
|
|
|
|
{
|
|
|
|
|
|
var mepCurves = doc.OfClass<MEPCurve>().Where(e => e is not InsulationLiningBase);
|
|
|
|
|
|
foreach (var mepCurve in mepCurves)
|
|
|
|
|
|
{
|
|
|
|
|
|
var length = mepCurve.get_Parameter(BuiltInParameter.CURVE_ELEM_LENGTH).AsDouble();
|
|
|
|
|
|
var connectors = mepCurve.GetConnectors(true);
|
|
|
|
|
|
if (length < 500 / 304.8 && connectors.Size == 2)
|
|
|
|
|
|
{
|
|
|
|
|
|
var errorItem = new MessageModel(mepCurve, "管道孤立或长度有误");
|
|
|
|
|
|
Items.Add(errorItem);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (IsCheckEqual)
|
|
|
|
|
|
{
|
|
|
|
|
|
var mepCurves = doc.OfClass<MEPCurve>().Where(e => e is not InsulationLiningBase).ToList();
|
|
|
|
|
|
foreach (var c1 in mepCurves)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var c2 in mepCurves)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (c1.Id != c2.Id)
|
|
|
|
|
|
{
|
2024-12-22 10:26:12 +08:00
|
|
|
|
var result = c1.GetCurve().Intersect(c2.GetCurve());
|
2024-09-22 11:05:41 +08:00
|
|
|
|
if (result == SetComparisonResult.Equal)
|
|
|
|
|
|
{
|
|
|
|
|
|
var errorItem = new MessageModel(c1, "管线存在重叠");
|
|
|
|
|
|
Items.Add(errorItem);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (IsCheckSymbolGeometry)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var grouping in typeInstancesGroups)
|
|
|
|
|
|
{
|
|
|
|
|
|
var symbolId = grouping.Key;
|
|
|
|
|
|
|
|
|
|
|
|
if (doc.GetElement(symbolId) is not FamilySymbol symbol)
|
|
|
|
|
|
{
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
symbol.get_Geometry(new Options());
|
|
|
|
|
|
Options option = new() { ComputeReferences = true, DetailLevel = ViewDetailLevel.Fine };
|
|
|
|
|
|
var geometryElement = symbol.get_Geometry(option);
|
|
|
|
|
|
if (geometryElement == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
var count = 0;
|
|
|
|
|
|
foreach (var geomObj in geometryElement)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (geomObj is GeometryInstance geomInstance)
|
|
|
|
|
|
{
|
|
|
|
|
|
#if REVIT2018 || REVIT2020
|
|
|
|
|
|
if (geomInstance.Symbol is CADLinkType)
|
|
|
|
|
|
{
|
|
|
|
|
|
var errorItem = new MessageModel(symbol, "构件类型包含dwg模型");
|
|
|
|
|
|
Items.Add(errorItem);
|
|
|
|
|
|
}
|
|
|
|
|
|
#elif REVIT2025
|
|
|
|
|
|
if (doc.GetElement(geomInstance.GetSymbolGeometryId().SymbolId) is CADLinkType)
|
|
|
|
|
|
{
|
|
|
|
|
|
var errorItem = new MessageModel(symbol, "构件类型包含dwg模型");
|
|
|
|
|
|
Items.Add(errorItem);
|
|
|
|
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
if (geomObj is Solid)
|
|
|
|
|
|
{
|
|
|
|
|
|
count++;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (count > 50)
|
|
|
|
|
|
{
|
|
|
|
|
|
var errorItem = new MessageModel(symbol, "构件类型几何需考虑简化(超过50个实体)");
|
|
|
|
|
|
Items.Add(errorItem);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
ErrorCount = Items.Count;
|
|
|
|
|
|
ExportToExcelCommand.NotifyCanExecuteChanged();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[RelayCommand(CanExecute = nameof(CanExport))]
|
|
|
|
|
|
private void ExportToExcel()
|
|
|
|
|
|
{
|
|
|
|
|
|
var fileName = uiapp.ActiveUIDocument.Document.Title;
|
|
|
|
|
|
var dialog = new SaveFileDialog()
|
|
|
|
|
|
{
|
|
|
|
|
|
Title = "导出结果",
|
|
|
|
|
|
AddExtension = true,
|
|
|
|
|
|
DefaultExt = ".xlsx",
|
|
|
|
|
|
InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory),
|
|
|
|
|
|
Filter = "Excel表格(*.xlsx)|*.xlsx",
|
|
|
|
|
|
OverwritePrompt = true,
|
|
|
|
|
|
FileName = $"{fileName.Substring(0, fileName.Length - 4)}_检查结果"
|
|
|
|
|
|
};
|
|
|
|
|
|
if (dialog.ShowDialog() != true)
|
|
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//ExcelPackage.LicenseContext = OfficeOpenXml.LicenseContext.NonCommercial;
|
|
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
2026-02-21 16:31:24 +08:00
|
|
|
|
var config = new OpenXmlConfiguration()
|
|
|
|
|
|
{
|
|
|
|
|
|
TableStyles = TableStyles.Default,
|
|
|
|
|
|
AutoFilter = true,
|
|
|
|
|
|
};
|
|
|
|
|
|
Dictionary<string, MessageModel[]> sheets = Items.GroupBy(e => e.ErrorMessage).ToDictionary(g => g.Key, g => g.ToArray());
|
|
|
|
|
|
MiniExcel.SaveAs(dialog.FileName, sheets);
|
2024-09-22 11:05:41 +08:00
|
|
|
|
|
2026-02-21 16:31:24 +08:00
|
|
|
|
//EPPlusHelper.WriteExcel(
|
|
|
|
|
|
// dialog.FileName,
|
|
|
|
|
|
// m =>
|
|
|
|
|
|
// {
|
|
|
|
|
|
// IEnumerable<IGrouping<string, MessageModel>> groups = Items.GroupBy(e => e.ErrorMessage);
|
|
|
|
|
|
// foreach (var group in groups)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// var sheet = m.Workbook.Worksheets.Add(group.Key);
|
|
|
|
|
|
// for (var i = -1; i < group.Count(); i++)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// if (i == -1)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// sheet.Cells[1, 1].Value = "元素ID";
|
|
|
|
|
|
// sheet.Cells[1, 2].Value = "族类别";
|
|
|
|
|
|
// sheet.Cells[1, 3].Value = "类型或实例名称";
|
|
|
|
|
|
// sheet.Cells[1, 4].Value = "参照标高";
|
|
|
|
|
|
// sheet.Cells[1, 5].Value = "系统";
|
|
|
|
|
|
// sheet.Cells[1, 6].Value = "主体";
|
|
|
|
|
|
// sheet.Cells[1, 7].Value = "房间";
|
|
|
|
|
|
// }
|
|
|
|
|
|
// else
|
|
|
|
|
|
// {
|
|
|
|
|
|
// var elem = group.ElementAt(i).Element;
|
|
|
|
|
|
|
|
|
|
|
|
// var type = elem.GetType();
|
|
|
|
|
|
// var host = type.GetProperty("Host");
|
|
|
|
|
|
// var level = type.GetProperty("ReferenceLevel");
|
|
|
|
|
|
// var mepSystem = type.GetProperty("MEPSystem");
|
|
|
|
|
|
// var room = type.GetProperty("Room");
|
|
|
|
|
|
// sheet.Cells[i + 2, 1].Value = elem.Id.ToString();
|
|
|
|
|
|
// sheet.Cells[i + 2, 2].Value = elem.Category.Name;
|
|
|
|
|
|
// sheet.Cells[i + 2, 3].Value = elem.Name;
|
|
|
|
|
|
|
|
|
|
|
|
// if (level != null)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// sheet.Cells[i + 2, 4].Value = (level.GetValue(elem, null) as Level)?.Name;
|
|
|
|
|
|
// }
|
|
|
|
|
|
// if (mepSystem != null)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// sheet.Cells[i + 2, 5].Value = (mepSystem.GetValue(elem, null) as MEPSystem)?.Name;
|
|
|
|
|
|
// }
|
|
|
|
|
|
// if (host != null)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// sheet.Cells[i + 2, 6].Value = (host.GetValue(elem, null) as Element)?.Name;
|
|
|
|
|
|
// }
|
|
|
|
|
|
// if (room != null)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// sheet.Cells[i + 2, 7].Value = (room.GetValue(room, null) as Room)?.Name;
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|
|
|
|
|
|
// EPPlusHelper.SetTitle(sheet, 1, 1, 1, 7);
|
|
|
|
|
|
// EPPlusHelper.SetStyle(sheet, 2, 1, group.Count() + 1, 7);
|
|
|
|
|
|
|
|
|
|
|
|
// var range = sheet.Cells[1, 1, group.Count() + 1, 7];
|
|
|
|
|
|
// range.AutoFitColumns();
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|
|
|
|
|
|
//);
|
|
|
|
|
|
ExportErrorMessageToExcel(dialog.FileName);
|
|
|
|
|
|
Common.Assists.WinDialogAssist.OpenFolderAndSelectFile(dialog.FileName);
|
2024-09-22 11:05:41 +08:00
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
2026-02-21 16:31:24 +08:00
|
|
|
|
Common.Assists.LogAssist.ToLog(ex.Message);
|
2024-09-22 11:05:41 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-02-21 16:31:24 +08:00
|
|
|
|
private void ExportErrorMessageToExcel(string filePath)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 1. 准备大字典,用于存放所有 Sheet 数据
|
|
|
|
|
|
var allSheetsData = new Dictionary<string, object>();
|
|
|
|
|
|
|
|
|
|
|
|
// 2. 分组逻辑保持不变
|
|
|
|
|
|
IEnumerable<IGrouping<string, MessageModel>> groups = Items.GroupBy(e => e.ErrorMessage);
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var group in groups)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 3. 构造当前 Sheet 的行数据列表
|
|
|
|
|
|
var sheetRows = new List<Dictionary<string, object>>();
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var item in group)
|
|
|
|
|
|
{
|
|
|
|
|
|
var elem = item.Element;
|
|
|
|
|
|
if (elem == null) continue;
|
|
|
|
|
|
|
|
|
|
|
|
var type = elem.GetType();
|
|
|
|
|
|
|
|
|
|
|
|
// 创建一行数据
|
|
|
|
|
|
var row = new Dictionary<string, object>();
|
|
|
|
|
|
|
|
|
|
|
|
// 直接赋值固定属性
|
|
|
|
|
|
row["元素ID"] = elem.Id.ToString();
|
|
|
|
|
|
row["族类别"] = elem.Category?.Name ?? "";
|
|
|
|
|
|
row["类型或实例名称"] = elem.Name;
|
|
|
|
|
|
|
|
|
|
|
|
// 使用反射获取动态属性(保留你原有的逻辑)
|
|
|
|
|
|
var levelProp = type.GetProperty("ReferenceLevel");
|
|
|
|
|
|
var mepProp = type.GetProperty("MEPSystem");
|
|
|
|
|
|
var hostProp = type.GetProperty("Host");
|
|
|
|
|
|
var roomProp = type.GetProperty("Room");
|
2024-09-22 11:05:41 +08:00
|
|
|
|
|
2026-02-21 16:31:24 +08:00
|
|
|
|
row["参照标高"] = levelProp != null ? (levelProp.GetValue(elem, null) as Level)?.Name : "";
|
|
|
|
|
|
row["系统"] = mepProp != null ? (mepProp.GetValue(elem, null) as MEPSystem)?.Name : "";
|
|
|
|
|
|
row["主体"] = hostProp != null ? (hostProp.GetValue(elem, null) as Element)?.Name : "";
|
|
|
|
|
|
|
|
|
|
|
|
// 注意:原代码中 room.GetValue(room, null) 应该是 roomProp.GetValue(elem, null) 的笔误
|
|
|
|
|
|
row["房间"] = roomProp != null ? (roomProp.GetValue(elem, null) as Room)?.Name : "";
|
|
|
|
|
|
|
|
|
|
|
|
sheetRows.Add(row);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 4. 处理 Sheet 名称(Excel 限制 31 个字符且不能有特殊字符)
|
|
|
|
|
|
string sheetName = group.Key ?? "未命名";
|
|
|
|
|
|
char[] invalidChars = { '\\', '/', '?', '*', '[', ']', ':' };
|
|
|
|
|
|
foreach (var c in invalidChars) sheetName = sheetName.Replace(c, '_');
|
|
|
|
|
|
if (sheetName.Length > 31) sheetName = sheetName.Substring(0, 31);
|
|
|
|
|
|
|
|
|
|
|
|
// 防止同名 Sheet 冲突
|
|
|
|
|
|
if (allSheetsData.ContainsKey(sheetName))
|
|
|
|
|
|
sheetName = sheetName.Substring(0, Math.Min(sheetName.Length, 25)) + "_" + Guid.NewGuid().ToString().Substring(0, 4);
|
|
|
|
|
|
|
|
|
|
|
|
allSheetsData.Add(sheetName, sheetRows);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 5. 保存文件
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
// MiniExcel 默认会将 Dictionary 的 Key 作为表头并加粗
|
|
|
|
|
|
MiniExcel.SaveAs(filePath, allSheetsData, overwriteFile: true);
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (IOException)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 提示文件被占用
|
|
|
|
|
|
MessageBox.Show("请先关闭已打开的 Excel 文件后再尝试保存。");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-02-10 20:53:40 +08:00
|
|
|
|
private void FindBasePoint()
|
|
|
|
|
|
{
|
|
|
|
|
|
var basePoints = uiapp.ActiveUIDocument.Document.OfClass<BasePoint>().OfType<BasePoint>();
|
|
|
|
|
|
foreach (var item in basePoints)
|
|
|
|
|
|
{
|
|
|
|
|
|
//南北
|
|
|
|
|
|
var ns = Math.Round(
|
|
|
|
|
|
item.get_Parameter(BuiltInParameter.BASEPOINT_NORTHSOUTH_PARAM).AsDouble() * 0.3048,
|
|
|
|
|
|
4,
|
|
|
|
|
|
MidpointRounding.AwayFromZero
|
|
|
|
|
|
);
|
|
|
|
|
|
//东西
|
|
|
|
|
|
var ew = Math.Round(item.get_Parameter(BuiltInParameter.BASEPOINT_EASTWEST_PARAM).AsDouble() * 0.3048, 4, MidpointRounding.AwayFromZero);
|
|
|
|
|
|
//高程
|
|
|
|
|
|
var elev = Math.Round(
|
|
|
|
|
|
item.get_Parameter(BuiltInParameter.BASEPOINT_ELEVATION_PARAM).AsDouble() * 0.3048,
|
|
|
|
|
|
4,
|
|
|
|
|
|
MidpointRounding.AwayFromZero
|
|
|
|
|
|
);
|
|
|
|
|
|
if (item.IsShared)//测量点
|
|
|
|
|
|
{
|
|
|
|
|
|
SharedBasePoint = $"南北:{ns}m;东西:{ew}m;高程:{elev}m";
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (item.Category.GetHashCode() == -2001271)//项目基点
|
|
|
|
|
|
{
|
|
|
|
|
|
//正北角度
|
|
|
|
|
|
var angle = item.get_Parameter(BuiltInParameter.BASEPOINT_ANGLETON_PARAM).AsValueString();
|
|
|
|
|
|
ProjectBasePoint = $"南北:{ns}m;东西:{ew}m;高程:{elev}m;角度:{angle}";
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-09-22 11:05:41 +08:00
|
|
|
|
[RelayCommand]
|
|
|
|
|
|
private void ModifyModel()
|
|
|
|
|
|
{
|
|
|
|
|
|
var errorItems = new List<MessageModel>();
|
|
|
|
|
|
modifyModel.Raise(_ =>
|
|
|
|
|
|
{
|
|
|
|
|
|
var uidoc = uiapp.ActiveUIDocument;
|
|
|
|
|
|
var doc = uidoc.Document;
|
|
|
|
|
|
doc.Invoke(
|
|
|
|
|
|
_ =>
|
|
|
|
|
|
{
|
|
|
|
|
|
#region 参照标高
|
|
|
|
|
|
var errorItems1 = correctReferLevelExecutes.SetWalls();
|
|
|
|
|
|
errorItems.AddRange(errorItems1);
|
|
|
|
|
|
var errorItems2 = correctReferLevelExecutes.SetInstances();
|
|
|
|
|
|
errorItems.AddRange(errorItems2);
|
|
|
|
|
|
var errorItems3 = correctReferLevelExecutes.SetMEPCurves();
|
|
|
|
|
|
errorItems.AddRange(errorItems3);
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
#region 立管坡度修正
|
|
|
|
|
|
foreach (var error in Items)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (error.ErrorMessage != "管线坡度有误差")
|
|
|
|
|
|
{
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var elem = error.Element;
|
|
|
|
|
|
if (elem is MEPCurve mep)
|
|
|
|
|
|
{
|
|
|
|
|
|
var loc = mep.Location as LocationCurve;
|
|
|
|
|
|
var line = loc!.Curve as Line;
|
|
|
|
|
|
var endPoint = line!.GetEndPoint(0);
|
|
|
|
|
|
var endPoint1 = line.GetEndPoint(1);
|
|
|
|
|
|
Line unboundLine;
|
|
|
|
|
|
Line l;
|
|
|
|
|
|
var xoy1 = endPoint.Flatten();
|
|
|
|
|
|
var xoy2 = endPoint1.Flatten();
|
|
|
|
|
|
var tan = Math.Abs(endPoint.Z - endPoint1.Z) / xoy1.DistanceTo(xoy2);
|
|
|
|
|
|
var dir = -XYZ.BasisZ;
|
|
|
|
|
|
|
|
|
|
|
|
if (endPoint.Z > endPoint1.Z) //以高点作为基准,修改低点
|
|
|
|
|
|
{
|
|
|
|
|
|
if (tan > 1)
|
|
|
|
|
|
{
|
|
|
|
|
|
unboundLine = Line.CreateUnbound(endPoint, dir);
|
|
|
|
|
|
var startPoint = unboundLine.Project(endPoint1).XYZPoint;
|
|
|
|
|
|
l = Line.CreateBound(endPoint, startPoint);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
dir = xoy2 - xoy1;
|
|
|
|
|
|
unboundLine = Line.CreateUnbound(endPoint, dir);
|
|
|
|
|
|
var startPoint = unboundLine.Project(endPoint1).XYZPoint;
|
|
|
|
|
|
l = Line.CreateBound(endPoint, startPoint);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
if (tan > 1)
|
|
|
|
|
|
{
|
|
|
|
|
|
unboundLine = Line.CreateUnbound(endPoint1, dir);
|
|
|
|
|
|
var startPoint = unboundLine.Project(endPoint).XYZPoint;
|
|
|
|
|
|
l = Line.CreateBound(startPoint, endPoint1);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
dir = xoy2 - xoy1;
|
|
|
|
|
|
unboundLine = Line.CreateUnbound(endPoint1, dir);
|
|
|
|
|
|
var startPoint = unboundLine.Project(endPoint).XYZPoint;
|
|
|
|
|
|
l = Line.CreateBound(startPoint, endPoint1);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
loc.Curve = l;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
},
|
|
|
|
|
|
"模型调整"
|
|
|
|
|
|
);
|
|
|
|
|
|
if (errorItems.Count == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2026-02-21 16:31:24 +08:00
|
|
|
|
Common.Assists.WinDialogAssist.ShowOrActivate<MessageWin, MessageViewModel>(uiapp.ActiveUIDocument, errorItems, "未解决错误");
|
2024-09-22 11:05:41 +08:00
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[RelayCommand(CanExecute = nameof(CanShowElement))]
|
|
|
|
|
|
private void ShowElement(object obj)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (obj is MessageModel model)
|
|
|
|
|
|
{
|
|
|
|
|
|
var uidoc = uiapp.ActiveUIDocument;
|
|
|
|
|
|
var doc = uidoc.Document;
|
|
|
|
|
|
//if (UiDocument.ActiveView.IsTemporaryHideIsolateActive())
|
|
|
|
|
|
//{
|
|
|
|
|
|
// UiDocument.ActiveView.temporary
|
|
|
|
|
|
//}
|
|
|
|
|
|
if (model.Element.IsValidObject)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (model.Element.IsHidden(uidoc.ActiveView))
|
|
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
List<ElementId> ids = [model.Element.Id];
|
2024-10-27 00:19:48 +08:00
|
|
|
|
//UiDocument.ActiveView.IsolateElementTemporary(model.ElementToMove.ViewId);
|
2024-09-22 11:05:41 +08:00
|
|
|
|
showElementsSectionBox.Raise(_ =>
|
|
|
|
|
|
{
|
|
|
|
|
|
if (uidoc.ActiveView is not View3D view3d)
|
|
|
|
|
|
{
|
|
|
|
|
|
view3d =
|
|
|
|
|
|
doc.OfClass<View3D>().FirstOrDefault(e => FilteredElementCollector.IsViewValidForElementIteration(doc, e.Id)) as View3D;
|
|
|
|
|
|
}
|
|
|
|
|
|
uidoc.ActiveView = view3d;
|
|
|
|
|
|
|
|
|
|
|
|
doc.Invoke(_ =>
|
|
|
|
|
|
{
|
|
|
|
|
|
if (UseSectionBox)
|
|
|
|
|
|
{
|
|
|
|
|
|
doc.InvokeSub(_ => view3d.SectionBoxElements(ids));
|
|
|
|
|
|
}
|
|
|
|
|
|
view3d.ZoomElements(uidoc, ids);
|
|
|
|
|
|
uidoc.Selection.SetElementIds(ids);
|
|
|
|
|
|
});
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
Items.Remove(model);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-22 20:03:42 +08:00
|
|
|
|
[ObservableProperty]
|
|
|
|
|
|
public partial string Properties { get; set; }
|
|
|
|
|
|
|
2024-09-22 11:05:41 +08:00
|
|
|
|
[ObservableProperty]
|
2025-02-10 20:53:40 +08:00
|
|
|
|
public partial int ErrorCount { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
[ObservableProperty]
|
|
|
|
|
|
public partial bool IsCheckEqual { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
[ObservableProperty]
|
|
|
|
|
|
public partial bool IsCheckLength { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
[ObservableProperty]
|
|
|
|
|
|
public partial bool IsCheckLevel { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
[ObservableProperty]
|
|
|
|
|
|
public partial bool IsCheckName { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
[ObservableProperty]
|
|
|
|
|
|
public partial bool IsCheckProps { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
[ObservableProperty]
|
|
|
|
|
|
public partial bool IsCheckSlope { get; set; }
|
|
|
|
|
|
[ObservableProperty]
|
|
|
|
|
|
public partial bool IsCheckSymbolGeometry { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
[ObservableProperty]
|
|
|
|
|
|
public partial ObservableCollection<MessageModel> Items { get; set; }
|
|
|
|
|
|
[ObservableProperty]
|
|
|
|
|
|
public partial int MyProperty { get; set; }
|
2024-09-22 11:05:41 +08:00
|
|
|
|
|
|
|
|
|
|
public string ProjectBasePoint { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
public string SharedBasePoint { get; set; }
|
2025-02-10 20:53:40 +08:00
|
|
|
|
|
|
|
|
|
|
[ObservableProperty]
|
|
|
|
|
|
public partial bool UseSectionBox { get; set; }
|
2024-09-22 11:05:41 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public enum ModelCheckType
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 命名
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
Name,
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 坡度问题
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
Slope,
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 参照标高
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
ReferenceLevel,
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 属性检查
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
Property,
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 管线重叠
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
Equal,
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 管线过短,或孤立管线
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
Length
|
|
|
|
|
|
}
|