using System.IO; using System.Windows; using Autodesk.Revit.DB; using Autodesk.Revit.UI.Selection; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using Nice3point.Revit.Toolkit.External.Handlers; using ShrlAlgoToolkit.RevitAddins.Common.Assists; namespace ShrlAlgoToolkit.RevitAddins.RvCivil { public partial class CreateOpeningsViewModel : ObservableObject { [ObservableProperty] public partial bool AddCasing { get; set; } [ObservableProperty] public partial double Distance { get; set; } private readonly string openingsFamilyFolder = $"{Variables.FamilyFolder}Opening"; private readonly string casingsFamilyFolder = $"{Variables.FamilyFolder}Casing"; private readonly ActionEventHandler handler = new(); [ObservableProperty] public partial FileInfo SelectedCasing { get; set; } [ObservableProperty] public partial List CasingFiles { get; set; } = []; public CreateOpeningsViewModel() { var files = Directory.GetFiles(casingsFamilyFolder); foreach (var file in files) { CasingFiles.Add(new FileInfo(file)); } } [RelayCommand] private void CreateOpenings() { try { handler.Raise( uiapp => { var uidoc = uiapp.ActiveUIDocument; var doc = uidoc.Document; var reference = uidoc.Selection.PickObject( ObjectType.Element, new FuncFilter(e => e is Floor or ExtrusionRoof or FootPrintRoof or Ceiling or Wall or FamilyInstance), "请选择需要开洞的图元" ); var elementToOpen = doc.GetElement(reference); var intersectsElement = new ElementIntersectsElementFilter(elementToOpen); var mepCurves = doc.OfCollector().WherePasses(intersectsElement).Where(e => e is MEPCurve).Cast().ToList(); if (doc.ActiveView.ViewType != ViewType.ThreeD) { MessageBox.Show("请选择三维视图", "提示"); } doc.InvokeGroup( _ => { foreach (var mepCurve in mepCurves) { doc.Invoke( _ => { //var level = new FilteredElementCollector(doc, doc.ActiveView.Id).OfCollector(BuiltInCategory.OST_Levels).OfClass(typeof(Level)).FirstElement(); doc.ActiveView.SketchPlane = SketchPlane.Create( doc, elementToOpen.LevelId); }, "设置工作平面"); var curve = mepCurve.GetCurve(); var conn = mepCurve.GetConnectors().OfType().FirstOrDefault(); double diameter = default; double width = default; double height = default; //double angle = default; Family openingFamily = null; var faceNormal = XYZ.Zero; faceNormal = conn.CoordinateSystem.BasisY; doc.Invoke( ts => { switch (conn.Shape) { case ConnectorProfileType.Oval: break; case ConnectorProfileType.Rectangular: openingFamily = AddCasing ? doc.GetOrLoadedFamily( $"{casingsFamilyFolder}\\矩形套管.rfa") : doc.GetOrLoadedFamily( $"{openingsFamilyFolder}\\矩形洞口.rfa"); width = conn.Width + (double)(Distance / 304.8); height = conn.Height + (double)(Distance / 304.8); break; case ConnectorProfileType.Round: openingFamily = doc.GetOrLoadedFamily( AddCasing ? $"{casingsFamilyFolder}\\圆形套管.rfa" : $"{openingsFamilyFolder}\\圆形洞口.rfa"); diameter = mepCurve.Diameter + (double)(Distance / 304.8); break; case ConnectorProfileType.Invalid: break; default: break; } //doc.ActiveView.SketchPlane = originSketch; if (openingFamily == null) { return Result.Failed; } var intersects = FindIntersects(elementToOpen, curve); if (intersects.Count != 2) { return Result.Failed; } var line = Line.CreateBound(intersects[0], intersects[1]) .ExtendLine(0.5, true); doc.ActiveView.ShowActiveWorkPlane(); if (faceNormal == XYZ.Zero) { return Result.Failed; } var plane = Plane.CreateByNormalAndOrigin( faceNormal, line.Evaluate(0.5, true)); doc.ActiveView.SketchPlane = SketchPlane.Create(doc, plane); var workPlane = new FilteredElementCollector( doc, doc.ActiveView.Id) .OfCategory(BuiltInCategory.OST_IOSSketchGrid) .FirstElement(); doc.Regenerate(); var op = new Options { IncludeNonVisibleObjects = true, View = doc.ActiveView, //DetailLevel = ViewDetailLevel.Fine, ComputeReferences = true }; var planeFace = workPlane .get_Geometry(op) .Where(obj => obj is Solid) .Cast() .Select(s => s.Faces.get_Item(0)) .FirstOrDefault(); var options = ts.GetFailureHandlingOptions(); options.SetFailuresPreprocessor(new FailuresPreProcessor()); ts.SetFailureHandlingOptions(options); if (planeFace == null) { return Result.Failed; } var symbolIds = openingFamily.GetFamilySymbolIds().FirstOrDefault(); var symbol = doc.GetElement(symbolIds) as FamilySymbol; if (symbol != null && !symbol.IsActive) { symbol.Activate(); } var newFamilyInstance = doc.Create .NewFamilyInstance(planeFace, line, symbol); if (diameter != 0.0) { newFamilyInstance.GetParameters("洞口直径").FirstOrDefault()?.Set( diameter); } else if (width != 0.0 && height != 0.0) { newFamilyInstance.GetParameters("洞口宽度").FirstOrDefault()?.Set(width); newFamilyInstance.GetParameters("洞口高度").FirstOrDefault()?.Set( height); } //ElementTransformUtils.RotateElement(doc, newFamilyInstance.ViewId, line, angle); doc.Regenerate(); InstanceVoidCutUtils.AddInstanceVoidCut( doc, elementToOpen, newFamilyInstance); doc.Delete(doc.ActiveView.SketchPlane.Id); return Result.Succeeded; }, "新建洞口"); } }, "开洞"); }); } catch (Autodesk.Revit.Exceptions.OperationCanceledException) { } catch (Exception e) { e.Message.ToLog(); throw; } } /// /// 找到宿主的面 /// /// /// private static Face FindCeilingAndFloorFace(Wall wall) { Options opt = new() { ComputeReferences = true, DetailLevel = ViewDetailLevel.Fine }; var geometryElement = wall.get_Geometry(opt); Face normalFace = null; foreach (var geometryObject in geometryElement) { var solid = geometryObject as Solid; if (solid != null && solid.Faces.Size > 0) { foreach (Face face in solid.Faces) { var planarFace = face as PlanarFace; if (planarFace != null) { if ( planarFace.FaceNormal.AngleTo(new XYZ(1, 1, 0)) == 0 || Math.Abs(planarFace.FaceNormal.AngleTo(new XYZ(1, 1, 0)) - Math.PI) < 0.0001 ) { normalFace = face; } } } } } return normalFace; } /// /// 查找所有管线定位线与元素面的碰撞点 /// /// /// /// private static List FindIntersects(Element elementToOpen, Curve curve) { var faces = elementToOpen.GetAllGeometryObjects(); var intersects = new List(); foreach (var face in faces) { //face = FindCeilingAndFloorFace(openingElement as Wall); var intersect = face.Intersect(curve, out var result); if (intersect == SetComparisonResult.Overlap) { //CurveArray curveArray = new CurveArray(); var x = result.get_Item(0); var intersection = x.XYZPoint; intersects.Add(intersection); //doc.Create.NewOpening(openingElement, curveArray, true); } } return intersects; } } }