Files
SzmediTools/Szmedi.RvKits/MEPTools/MEPCurveSignViewModel.cs

259 lines
12 KiB
C#
Raw Permalink Normal View History

2025-09-16 16:06:41 +08:00
using System.Linq;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Electrical;
using Autodesk.Revit.DB.Mechanical;
using Autodesk.Revit.DB.Plumbing;
using Autodesk.Revit.UI;
using Nice3point.Revit.Toolkit.External.Handlers;
namespace Szmedi.RvKits.MEPTools
{
public partial class MEPCurveSignViewModel : ObservableValidator
{
private readonly ActionEventHandler handler;
public MEPCurveSignViewModel()
{
handler = new ActionEventHandler();
}
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(BatchSignsCommand))]
private string newSign = "生活给水管道";
[ObservableProperty]
[IsNumeric]
[NotifyDataErrorInfo]
[Minimum(0)]
[NotifyCanExecuteChangedFor(nameof(CreateSignsCommand))]
private double minSize = 50;
[ObservableProperty]
[IsNumeric]
[NotifyDataErrorInfo]
[Minimum(0)]
[NotifyCanExecuteChangedFor(nameof(CreateSignsCommand))]
private double minLength = 600;
[ObservableProperty]
private bool useArrow;
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(CreateSignsCommand))]
private bool containPipes;
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(CreateSignsCommand))]
private bool containDucts;
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(CreateSignsCommand))]
private bool containCableTrays;
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(CreateSignsCommand))]
private bool containConduits;
private bool CanCreateSigns =>
MinSize >= 0 &&
MinLength >= 0 &&
(ContainPipes || ContainDucts || ContainCableTrays || ContainConduits);
[RelayCommand(CanExecute = nameof(CanCreateSigns))]
private void CreateSigns()
{
handler.Raise(
uiapp =>
{
Document doc = uiapp.ActiveUIDocument.Document;
doc.Invoke(
_ =>
{
var family = doc.OfClass<Family>()
.Cast<Family>()
.FirstOrDefault(f => f.Name == "机电管线标识");
if (family == null)
{
var path = Path.Combine(GlobalVariables.DirAssembly, "FamilyLib", "2020", "机电管线标识.rfa");
doc.LoadFamily(path, out family);
}
var symbol = doc.GetElement(family.GetFamilySymbolIds().FirstOrDefault()) as FamilySymbol;
if (!symbol.IsActive)
{
symbol.Activate();
}
var mepCurves = doc.ActiveView
.OfCollector()
.OfClass(typeof(MEPCurve))
.Cast<MEPCurve>()
.Where(
c => (c is Duct && ContainDucts) ||
(c is CableTray && ContainCableTrays) ||
(c is Pipe && ContainPipes) ||
(c is Conduit && ContainConduits))
.ToList();
foreach (var mepCurve in mepCurves)
{
var conn = mepCurve.ConnectorManager.Connectors.OfType<Connector>().FirstOrDefault();
var shape = conn.Shape;
var locLine = mepCurve.GetLocCurve() as Line;
if (locLine.Length - MinLength / 304.8 < 10e-6)
{
continue;
}
switch (shape)
{
case ConnectorProfileType.Round:
if (mepCurve.Diameter - MinSize / 304.8 < 10e-6)
{
continue;
}
break;
default:
if (mepCurve.Width - MinSize / 304.8 < 10e-6)
{
continue;
}
break;
}
var centerPoint = locLine.Evaluate(0.5, true);
Line l = Line.CreateUnbound(centerPoint, XYZ.BasisZ);
if (locLine.Direction.CrossProduct(XYZ.BasisZ).IsAlmostEqualTo(XYZ.Zero))//立管
{
l = Line.CreateUnbound(centerPoint, XYZ.BasisX);
}
XYZ loc = null;
XYZ referenceVector = XYZ.Zero;
var options = new Options() { ComputeReferences = true, };
var geoElem = mepCurve.get_Geometry(options);
Face face = null;
foreach (var obj in geoElem)
{
if (obj is Solid solid)
{
var faces = solid.Faces;
if (faces == null || faces.Size == 0)
{
continue;
}
foreach (Face cface in faces)
{
var result = cface.Intersect(l, out var array);
if (result == SetComparisonResult.Overlap)
{
face = cface;
loc = array.get_Item(0).XYZPoint;
var uv = array.get_Item(0).UVPoint;
var faceNormal = face.ComputeNormal(uv);
if (faceNormal.IsAlmostEqualTo(XYZ.BasisZ))
{
break;
}
}
}
if (face != null && loc != null)
{
break;
}
}
}
if (loc == null)
{
continue;
}
var instance = doc.Create
.NewFamilyInstance(
face, loc, referenceVector, symbol);
doc.Regenerate();
string systemName = string.Empty;
switch (conn.Domain)
{
case Domain.DomainHvac:
systemName = mepCurve.get_Parameter(BuiltInParameter.RBS_DUCT_SYSTEM_TYPE_PARAM).AsValueString();
break;
case Domain.DomainPiping:
systemName = mepCurve.get_Parameter(BuiltInParameter.RBS_PIPING_SYSTEM_TYPE_PARAM).AsValueString();
break;
case Domain.DomainCableTrayConduit:
systemName = mepCurve.get_Parameter(BuiltInParameter.RBS_CTC_SERVICE_TYPE).AsValueString();
break;
default:
break;
}
if (string.IsNullOrEmpty(systemName))
{
systemName = "未定义管线";
}
var split = systemName.Split('_', '-');
if (split.Length > 1)//具有多字段
{
systemName = split.LastOrDefault();
}
systemName = systemName.Replace("系统", "管道");
instance.LookupParameter("机电管线标识").Set(systemName);
instance.LookupParameter("显示箭头").Set(UseArrow ? 1 : 0);
var refer = instance.HandOrientation;
var normal = refer.CrossProduct(locLine.Direction);
if (normal.IsAlmostEqualTo(XYZ.Zero))
{
continue;
}
var angle = refer.AngleTo(locLine.Direction);
ElementTransformUtils.RotateElement(
doc,
instance.Id,
Line.CreateUnbound(loc, normal),
angle);
}
}, "创建管线标识");
});
}
private bool CanBatchSigns =>
!string.IsNullOrEmpty(NewSign);
[RelayCommand(CanExecute = nameof(CanBatchSigns))]
private void BatchSigns()
{
handler.Raise(
uiapp =>
{
if (string.IsNullOrEmpty(NewSign))
{
return;
}
var uidoc = uiapp.ActiveUIDocument;
var doc = uidoc.Document;
var ids = uidoc.Selection.GetElementIds();
var signs = doc.ActiveView.OfCollector().OfClass(typeof(FamilyInstance))
.Cast<FamilyInstance>()
.Where(e => e.Name == "机电管线标识")
.ToList();
if (ids.Count == 0)
{
TaskDialog.Show("提示", "请选择机电管线");
return;
}
if (signs.Count == 0)
{
TaskDialog.Show("提示", "当前视图中没有机电管线标识的实例");
return;
}
doc.Invoke(
_ =>
{
foreach (var sign in signs)
{
if (sign.Host is MEPCurve host && ids.Contains(host.Id))
{
sign.GetParameters("机电管线标识").FirstOrDefault()?.Set(NewSign);
}
}
}, "批处理标识");
});
}
}
}