using System.Windows; using Autodesk.Revit.DB; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using Nice3point.Revit.Toolkit.External.Handlers; using ShrlAlgoToolkit.RevitAddins.Common.Assists; using ShrlAlgoToolkit.RevitAddins.Common.Controls; namespace ShrlAlgoToolkit.RevitAddins.RvCivil; public partial class ResolveCivilConnectViewModel : ObservableObject { private readonly ActionEventHandler modifyHandler = new(); public ResolveCivilConnectViewModel(UIDocument uidoc) { doc = uidoc.Document; this.uidoc = uidoc; } private readonly Document doc; private readonly UIDocument uidoc; /// /// 楼板-建筑墙 /// [ObservableProperty] public partial bool? FloorCutAWall { get; set; } = false; /// /// 板-结构墙 /// [ObservableProperty] public partial bool? FloorCutSWall { get; set; } = false; /// /// 梁-建筑墙 /// [ObservableProperty] public partial bool? FramingCutAWall { get; set; } = false; /// /// 梁-板 /// [ObservableProperty] public partial bool? FramingCutFloor { get; set; } = false; /// /// 梁-结构墙 /// [ObservableProperty] public partial bool? FramingCutSWall { get; set; } = false; /// /// 主梁-次梁 /// [ObservableProperty] public partial bool? MFramingCutSFraming { get; set; } = false; /// /// 结构柱子-建筑墙 /// [ObservableProperty] public partial bool? SColumnCutAWall { get; set; } = false; /// /// 结构柱-板 /// [ObservableProperty] public partial bool? SColumnCutFloor { get; set; } = false; /// /// 结构柱-梁 /// [ObservableProperty] public partial bool? SColumnCutFraming { get; set; } = false; /// /// 结构柱-结构墙 /// [ObservableProperty] public partial bool? SColumnCutSWall { get; set; } = false; /// /// 结构墙-建筑墙 /// [ObservableProperty] public partial bool? SWallCutAWall { get; set; } = false; [ObservableProperty] private bool? isWholeModel = false; public static Options SetOptions() { Options option = new() { ComputeReferences = true, DetailLevel = ViewDetailLevel.Fine }; return option; } /// /// /// /// /// /// /// 保留的集合 /// 剪切的集合 private void ConnectCivilComponents( List elementsToSkip, View3D view3D, string tsName, FilteredElementCollector collectorReserve, FilteredElementCollector collectorToCut ) { if (collectorReserve == null || collectorToCut == null) { return; } var ids = collectorToCut.WhereElementIsNotElementType().ToElementIds(); doc.Invoke( ts => { var options = ts.GetFailureHandlingOptions(); FailuresPreProcessor failuresProcessor = new(); options.SetFailuresPreprocessor(failuresProcessor); ts.SetFailureHandlingOptions(options); var reserveElements = collectorReserve.WhereElementIsNotElementType().ToList(); foreach (var element in reserveElements) { try { //var filter = new ElementIntersectsElementFilter(wall, false); //var instances = collector.WherePasses(filter); //instance.get_BoundingBox(view3D) //BoundingBoxIntersectsFilter filter=new BoundingBoxIntersectsFilter(new Outline()) var box = element.get_BoundingBox(view3D); Outline outline = new(box.Min, box.Max); BoundingBoxIntersectsFilter intersectsFilter = new(outline); BoundingBoxIsInsideFilter boxIsInsideFilter = new(outline); var filter = new LogicalOrFilter(intersectsFilter, boxIsInsideFilter); //ElementIntersectsElementFilter filter = new ElementIntersectsElementFilter(structuralColumn, false); //执行一次后会修改集合,需修改 var newCollector = new FilteredElementCollector(doc, ids); var intersectElements = newCollector.WherePasses(filter).ToList(); foreach (var intersectElem in intersectElements) { if (!JoinGeometryUtils.AreElementsJoined(doc, intersectElem, element)) { JoinGeometryUtils.JoinGeometry(doc, element, intersectElem); } if (!JoinGeometryUtils.IsCuttingElementInJoin(doc, element, intersectElem)) { JoinGeometryUtils.SwitchJoinOrder(doc, element, intersectElem); } } } catch (Exception ex) { //避免重复添加 if (!elementsToSkip.Exists(ele => ele.Element.Id == element.Id)) { elementsToSkip.Add(new MessageModel(element, ex.Message)); } } } }, tsName ); } private static List GetElementGeoList(Element elem) { List getElementGeoList = new(); var geometry = elem.get_Geometry(SetOptions()); foreach (var geomObj in geometry) { if (geomObj is GeometryInstance geomInstance) { var usesSymbolGeometry = elem is FamilyInstance instance && !instance.HasModifiedGeometry(); var instanceGeometry = usesSymbolGeometry ? geomInstance.GetSymbolGeometry() : geomInstance.GetInstanceGeometry(); foreach (var instObj in instanceGeometry) { getElementGeoList.AddRange(GetFaces(instObj)); } } getElementGeoList.AddRange(GetFaces(geomObj)); } return getElementGeoList; } private static List GetFaces(GeometryObject geoObject) { List geometryObjects = new(); if (geoObject is Solid instSolid) { if (instSolid.Faces.Size > 0) { geometryObjects.AddRange(instSolid.Faces.Cast()); } //else if (typeof(Face) == typeof(Edge) && instSolid.Edges.Size > 0) //{ // geometryObjects.AddRange(instSolid.Edges.Cast()); //} } return geometryObjects; } [RelayCommand] private void ModifyModel() { //if (obj is Windows view) //{ // view.DialogResult = true; //} var result = MessageBox.Show("连接处理", "如果模型构件数量过多,存在崩溃风险。\n\r是否现在保存并继续?", MessageBoxButton.YesNo, MessageBoxImage.Warning); if (result == MessageBoxResult.Yes) { doc.Save(new SaveOptions()); } if (result == MessageBoxResult.No) { return; } modifyHandler.Raise(_ => { List elementsToSkip = new(); //墙和柱空间位置,连接时,墙在柱间要打断处理,不能“一条线延伸”建筑结构均如此。墙的顶部到梁底或者板底,等等其他具有构件之间空间连接视具体情况而定。要保证既不影响模型完整准确性,又不会对后期量的统计造成误差。建筑和结构要协调连接处的处理方式,做到统一。 var view3D = doc.OfClass().Cast().FirstOrDefault(v => !v.IsTemplate); //构造收集器 var floors = new FilteredElementCollector(doc).OfClass(typeof(Floor)); var columnCollector = new FilteredElementCollector(doc).OfClass(typeof(FamilyInstance)).OfCategory(BuiltInCategory.OST_Columns); var structColumns = new FilteredElementCollector(doc) .OfClass(typeof(FamilyInstance)) .OfCategory(BuiltInCategory.OST_StructuralColumns); var beamsCollector = new FilteredElementCollector(doc).OfClass(typeof(FamilyInstance)).OfCategory(BuiltInCategory.OST_StructuralFraming); var elemIds = new FilteredElementCollector(doc) .OfClass(typeof(Wall)) .Where(wall => wall.get_Parameter(BuiltInParameter.WALL_STRUCTURAL_SIGNIFICANT).AsInteger() == 0) .Select(elem => elem.Id) .ToList(); var archiWalls = elemIds.Any() ? new FilteredElementCollector(doc, elemIds) : null; elemIds = new FilteredElementCollector(doc) .OfClass(typeof(Wall)) .Where(wall => wall.get_Parameter(BuiltInParameter.WALL_STRUCTURAL_SIGNIFICANT).AsInteger() == 1) .Select(elem => elem.Id) .ToList(); var structWalls = elemIds.Any() ? new FilteredElementCollector(doc, elemIds) : null; //ElementCategoryFilter structuralColumns = new ElementCategoryFilter(BuiltInCategory.OST_StructuralColumns); //ElementCategoryFilter columns = new ElementCategoryFilter(BuiltInCategory.OST_Columns); //ElementCategoryFilter beams = new ElementCategoryFilter(BuiltInCategory.OST_StructuralFraming); //List filters = new List //{ // structuralColumns, // columns, // beams //}; //LogicalOrFilter orFilter = new LogicalOrFilter(filters); try { if (IsWholeModel != true) { var elements = uidoc.Selection.PickElementsByRectangle(new FuncFilter(e => e is Wall or Floor or FamilyInstance)); elemIds = elements.Where(elem => elem is Floor).Select(f => f.Id).ToList(); floors = elemIds.Any() ? new FilteredElementCollector(doc, elemIds) : null; elemIds = elements .Where(elem => elem.Category.Id == Category.GetCategory(doc, BuiltInCategory.OST_StructuralColumns).Id) .Select(elem => elem.Id) .ToList(); structColumns = elemIds.Any() ? new FilteredElementCollector(doc, elemIds) : null; elemIds = elements .Where(elem => elem.Category.Id == Category.GetCategory(doc, BuiltInCategory.OST_Columns).Id) .Select(elem => elem.Id) .ToList(); columnCollector = elemIds.Any() ? new FilteredElementCollector(doc, elemIds) : null; elemIds = elements .Where(elem => elem.Category.Id == Category.GetCategory(doc, BuiltInCategory.OST_StructuralFraming).Id) .Select(elem => elem.Id) .ToList(); beamsCollector = elemIds.Any() ? new FilteredElementCollector(doc, elemIds) : null; elemIds = elements .Where( elem => elem.Category.Id == Category.GetCategory(doc, BuiltInCategory.OST_Walls).Id && elem.get_Parameter(BuiltInParameter.WALL_STRUCTURAL_SIGNIFICANT).AsInteger() == 0 ) .Select(elem => elem.Id) .ToList(); archiWalls = elemIds.Any() ? new FilteredElementCollector(doc, elemIds) : null; elemIds = elements .Where( elem => elem.Category.Id == Category.GetCategory(doc, BuiltInCategory.OST_Walls).Id && elem.get_Parameter(BuiltInParameter.WALL_STRUCTURAL_SIGNIFICANT).AsInteger() == 1 ) .Select(elem => elem.Id) .ToList(); structWalls = elemIds.Any() ? new FilteredElementCollector(doc, elemIds) : null; } } catch (Autodesk.Revit.Exceptions.OperationCanceledException) { } using (TransactionGroup tg = new(doc, "模型连接处理")) { tg.Start(); if (SColumnCutSWall == true) { ConnectCivilComponents(elementsToSkip, view3D, "结构柱剪切结构墙", structColumns, structWalls); } if (FloorCutAWall == true) { ConnectCivilComponents(elementsToSkip, view3D, "板剪切建筑墙", floors, archiWalls); } if (FramingCutFloor == true) { ConnectCivilComponents(elementsToSkip, view3D, "梁剪切板", beamsCollector, floors); } if (FramingCutSWall == true) { ConnectCivilComponents(elementsToSkip, view3D, "梁剪切结构墙", beamsCollector, structWalls); } if (SWallCutAWall == true) { ConnectCivilComponents(elementsToSkip, view3D, "结构墙剪切建筑墙", structWalls, archiWalls); } if (SColumnCutFloor == true) { ConnectCivilComponents(elementsToSkip, view3D, "结构柱剪切板", structColumns, floors); } if (SColumnCutFraming == true) { ConnectCivilComponents(elementsToSkip, view3D, "结构柱剪切梁", structColumns, beamsCollector); } if (SColumnCutAWall == true) { ConnectCivilComponents(elementsToSkip, view3D, "结构柱剪切建筑墙", structColumns, archiWalls); } if (FramingCutAWall == true) { ConnectCivilComponents(elementsToSkip, view3D, "梁剪切建筑墙", beamsCollector, archiWalls); } if (FloorCutSWall == true) { ConnectCivilComponents(elementsToSkip, view3D, "板剪切结构墙", floors, structWalls); } if (MFramingCutSFraming == true) { //ConnectCivilComponents(elementsToSkip, view3D, "主梁连接次梁", beamsCollector, beamsCollector); using Transaction trans = new(doc, "主梁连接次梁"); trans.Start(); var options = trans.GetFailureHandlingOptions(); FailuresPreProcessor failuresProcessor = new(); options.SetFailuresPreprocessor(failuresProcessor); trans.SetFailureHandlingOptions(options); var beams = beamsCollector.WhereElementIsNotElementType().ToList(); var ids = beamsCollector.WhereElementIsNotElementType().ToElementIds(); foreach (var beam in beams) { try { //ElementIntersectsElementFilter filter = new ElementIntersectsElementFilter(structuralColumn, false); var box = beam.get_BoundingBox(view3D); Outline outline = new(box.Min, box.Max); BoundingBoxIntersectsFilter intersectsFilter = new(outline); BoundingBoxIsInsideFilter boxIsInsideFilter = new(outline); var filter = new LogicalOrFilter(intersectsFilter, boxIsInsideFilter); //执行一次后会修改集合,需修改 var newCollector = new FilteredElementCollector(doc, ids); var intersectBeams = newCollector.WherePasses(filter); var firstBeam = beam as FamilyInstance; foreach (var intersectBeam in intersectBeams) { if (intersectBeam.Id == firstBeam.Id) { continue; } var secondBeam = intersectBeam as FamilyInstance; var face1 = GetElementGeoList(firstBeam) .Find(face => face.ComputeNormal(new UV()).IsAlmostEqualTo(firstBeam.HandOrientation)); var face2 = GetElementGeoList(intersectBeam) .Find(face => face.ComputeNormal(new UV()).IsAlmostEqualTo(secondBeam.HandOrientation)); FamilyInstance mainBeam; FamilyInstance subBeam; if (face1 == null || face2 == null) { continue; } if (face1.Area > face2.Area) { mainBeam = firstBeam; subBeam = secondBeam; } else { mainBeam = secondBeam; subBeam = firstBeam; } if (!JoinGeometryUtils.AreElementsJoined(doc, mainBeam, subBeam)) { JoinGeometryUtils.JoinGeometry(doc, mainBeam, subBeam); } if (!JoinGeometryUtils.IsCuttingElementInJoin(doc, mainBeam, subBeam)) { JoinGeometryUtils.SwitchJoinOrder(doc, mainBeam, subBeam); } //if (JoinGeometryUtils.AreElementsJoined(doc, mainBeam, subBeam)) //{ // //楼板被剪切了,第一个元素保持不变 // if (!JoinGeometryUtils.IsCuttingElementInJoin(doc, mainBeam, subBeam)) // { // JoinGeometryUtils.SwitchJoinOrder(doc, mainBeam, subBeam); // } //} //else //{ // // 第一个元素保持不变 // JoinGeometryUtils.SwitchJoinOrder(doc, beam, intersectBeam); //} } } catch (Exception ex) { elementsToSkip.Add(new MessageModel(beam, ex.Message)); } } trans.Commit(); } tg.Assimilate(); } if (elementsToSkip.Any()) { Common.Assists.WinDialogAssist.ShowOrActivate(uidoc, elementsToSkip, "未解决构件"); } else { MessageBox.Show("处理完成", "提示", MessageBoxButton.OK, MessageBoxImage.Information); } }); } }