Files
Shrlalgo.RvKits/ShrlAlgo.RvKits/RvCivil/CreateOpeningsViewModel.cs

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;
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;
}
}
}