277 lines
14 KiB
C#
277 lines
14 KiB
C#
using System.IO;
|
|
using System.Windows;
|
|
|
|
using Autodesk.Revit.DB;
|
|
using Autodesk.Revit.UI;
|
|
using Autodesk.Revit.UI.Selection;
|
|
|
|
using CommunityToolkit.Mvvm.ComponentModel;
|
|
using CommunityToolkit.Mvvm.Input;
|
|
|
|
using Nice3point.Revit.Toolkit.External.Handlers;
|
|
|
|
using ShrlAlgo.Toolkit.Core.Assist;
|
|
using ShrlAlgoToolkit.Core.Assist;
|
|
|
|
namespace ShrlAlgo.RvKits.RvCivil
|
|
{
|
|
public partial class CreateOpeningsViewModel : ObservableObject
|
|
{
|
|
[ObservableProperty] private bool addCasing;
|
|
|
|
[ObservableProperty] private double distance;
|
|
|
|
private readonly string openingsFamilyFolder = $"{Variables.FamilyFolder}Opening";
|
|
private readonly string casingsFamilyFolder = $"{Variables.FamilyFolder}Casing";
|
|
private readonly ActionEventHandler handler = new();
|
|
[ObservableProperty] private FileInfo selectedCasing;
|
|
[ObservableProperty] private List<FileInfo> casingFiles = [];
|
|
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<MEPCurve>().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<Connector>().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<Solid>()
|
|
.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;
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// 找到宿主的面
|
|
/// </summary>
|
|
/// <param name="wall"></param>
|
|
/// <returns></returns>
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 查找所有管线定位线与元素面的碰撞点
|
|
/// </summary>
|
|
/// <param name="elementToOpen"></param>
|
|
/// <param name="curve"></param>
|
|
/// <returns></returns>
|
|
private static List<XYZ> FindIntersects(Element elementToOpen, Curve curve)
|
|
{
|
|
var faces = elementToOpen.GetAllGeometryObjects<Face>();
|
|
var intersects = new List<XYZ>();
|
|
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;
|
|
}
|
|
}
|
|
} |