Files
SzmediTools/Szmedi.RvKits/ModelManager/ResolveCivilConnectViewModel.cs
2025-09-16 16:06:41 +08:00

470 lines
21 KiB
C#

using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Nice3point.Revit.Toolkit.External.Handlers;
using System;
using System.Linq;
using System.Windows;
using OperationCanceledException = Autodesk.Revit.Exceptions.OperationCanceledException;
namespace Szmedi.RvKits.ModelManager
{
public partial class ResolveCivilConnectViewModel : ObservableObject
{
private readonly ActionEventHandler connectHandler;
public ResolveCivilConnectViewModel(UIDocument uidoc)
{
doc = uidoc.Document;
this.uidoc = uidoc;
connectHandler = new();
}
private readonly Document doc;
private readonly UIDocument uidoc;
[ObservableProperty]
private bool? activateFloorCutArchitecturalWall = false;
[ObservableProperty]
private bool? activateFloorCutStructuralWall = false;
[ObservableProperty]
private bool? activateFramingCutArchitecturalWall = false;
[ObservableProperty]
private bool? activateFramingCutFloor = false;
[ObservableProperty]
private bool? activateFramingCutStructuralWall = false;
[ObservableProperty]
private bool? activateMainFramingCutSubFraming = false;
[ObservableProperty]
private bool? activateStructuralColumnCutArchitecturalWall = false;
[ObservableProperty]
private bool? activateStructuralColumnCutFloor = false;
[ObservableProperty]
private bool? activateStructuralColumnCutFraming = false;
[ObservableProperty]
private bool? activateStructuralColumnCutStructuralWall = false;
[ObservableProperty]
private bool? activateStructuralWallCutArchitecturalWall = false;
[ObservableProperty]
private bool? isWholeModel = false;
public static Options SetOptions()
{
Options option = new() { ComputeReferences = true, DetailLevel = ViewDetailLevel.Fine };
return option;
}
private void ConnectCivilComponents(
List<MessageModel> 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);
LogicalOrFilter filter = new(intersectsFilter, boxIsInsideFilter);
//ElementIntersectsElementFilter filter = new ElementIntersectsElementFilter(structuralColumn, false);
//执行一次后会修改集合,需修改
FilteredElementCollector newCollector = new(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<Face> GetElementGeoList(Element elem)
{
List<Face> getElementGeoList = [];
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<Face> GetFaces(GeometryObject geoObject)
{
List<Face> geometryObjects = [];
if (geoObject is Solid instSolid)
{
if (instSolid.Faces.Size > 0)
{
geometryObjects.AddRange(instSolid.Faces.Cast<Face>());
}
//else if (typeof(Face) == typeof(Edge) && instSolid.Edges.Size > 0)
//{
// geometryObjects.AddRange(instSolid.Edges.Cast<Face>());
//}
}
return geometryObjects;
}
[RelayCommand]
private void ModifyModel()
{
//if (obj is Window visibilityWin)
//{
// visibilityWin.DialogResult = true;
//}
var result = MessageBox.Show(
"如果模型构件数量过多,处理时间会较长,且存在崩溃风险。\n\r是否现在保存并继续?",
"温馨提示",
MessageBoxButton.OKCancel,
MessageBoxImage.Warning
);
if (result == MessageBoxResult.OK)
{
if (!string.IsNullOrEmpty(doc.PathName))
{
doc.Save(new SaveOptions());
}
}
if (result == MessageBoxResult.Cancel)
{
return;
}
connectHandler.Raise(app =>
{
List<MessageModel> elementsToSkip = [];
//墙和柱空间位置,连接时,墙在柱间要打断处理,不能“一条线延伸”建筑结构均如此。墙的顶部到梁底或者板底,等等其他具有构件之间空间连接视具体情况而定。要保证既不影响模型完整准确性,又不会对后期量的统计造成误差。建筑和结构要协调连接处的处理方式,做到统一。
var view3D = doc.QueryElementsByType<View3D>()
.WhereElementIsNotElementType()
.Cast<View3D>()
.FirstOrDefault(v => !v.IsTemplate);
//构造收集器
var floorCollector = new FilteredElementCollector(doc).OfClass(typeof(Floor));
//建筑柱
var columnCollector = new FilteredElementCollector(doc)
.OfClass(typeof(FamilyInstance))
.OfCategory(BuiltInCategory.OST_Columns);
var structuralColumnsCollector = 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 architecturalWallCollector = 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 structuralWallCollector = elemIds.Any() ? new FilteredElementCollector(doc, elemIds) : null;
try
{
if (IsWholeModel != true)
{
var elements = uidoc.Selection.PickElementsByRectangle(
new TypesSelectionFilter(typeof(Wall), typeof(Floor), typeof(FamilyInstance))
);
elemIds = elements.Where(elem => elem is Floor).Select(f => f.Id).ToList();
floorCollector = 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();
structuralColumnsCollector = 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();
architecturalWallCollector = 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();
structuralWallCollector = elemIds.Any() ? new FilteredElementCollector(doc, elemIds) : null;
}
}
catch (OperationCanceledException)
{
return;
}
using (TransactionGroup tg = new(doc, "模型连接处理"))
{
tg.Start();
if (ActivateStructuralColumnCutStructuralWall == true)
{
ConnectCivilComponents(elementsToSkip, view3D, "结构柱剪切结构墙", structuralColumnsCollector, structuralWallCollector);
}
if (ActivateFloorCutArchitecturalWall == true)
{
ConnectCivilComponents(elementsToSkip, view3D, "板剪切建筑墙", floorCollector, architecturalWallCollector);
}
if (ActivateFramingCutFloor == true)
{
ConnectCivilComponents(elementsToSkip, view3D, "梁剪切板", beamsCollector, floorCollector);
}
if (ActivateFramingCutStructuralWall == true)
{
ConnectCivilComponents(elementsToSkip, view3D, "梁剪切结构墙", beamsCollector, structuralWallCollector);
}
if (ActivateStructuralWallCutArchitecturalWall == true)
{
ConnectCivilComponents(elementsToSkip, view3D, "结构墙剪切建筑墙", structuralWallCollector, architecturalWallCollector);
}
if (ActivateStructuralColumnCutFloor == true)
{
ConnectCivilComponents(elementsToSkip, view3D, "结构柱剪切板", structuralColumnsCollector, floorCollector);
}
if (ActivateStructuralColumnCutFraming == true)
{
ConnectCivilComponents(elementsToSkip, view3D, "结构柱剪切梁", structuralColumnsCollector, beamsCollector);
}
if (ActivateStructuralColumnCutArchitecturalWall == true)
{
ConnectCivilComponents(elementsToSkip, view3D, "结构柱剪切建筑墙", structuralColumnsCollector, architecturalWallCollector);
}
if (ActivateFramingCutArchitecturalWall == true)
{
ConnectCivilComponents(elementsToSkip, view3D, "梁剪切建筑墙", beamsCollector, architecturalWallCollector);
}
if (ActivateFloorCutStructuralWall == true)
{
ConnectCivilComponents(elementsToSkip, view3D, "板剪切结构墙", floorCollector, structuralWallCollector);
}
if (ActivateMainFramingCutSubFraming == 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);
LogicalOrFilter filter = new(intersectsFilter, boxIsInsideFilter);
//执行一次后会修改集合,需修改
FilteredElementCollector newCollector = new(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)
.FirstOrDefault(face => face.ComputeNormal(new UV()).IsAlmostEqualTo(firstBeam.HandOrientation));
var face2 = GetElementGeoList(intersectBeam)
.FirstOrDefault(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.Count > 0)
{
MessageWin errorResolveWin = new() { DataContext = new MessageViewModel(uidoc, elementsToSkip) };
_ = new System.Windows.Interop.WindowInteropHelper(errorResolveWin)
{
Owner = System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle
};
errorResolveWin.Show();
}
else
{
MessageBox.Show("处理完成", "提示");
}
});
}
}
}