Files
Shrlalgo.RvKits/ShrlAlgoToolkit.RevitAddins/RvCommon/InstanceCreatorViewModel.cs

328 lines
13 KiB
C#
Raw Normal View History

2024-09-22 11:05:41 +08:00
using System.Windows;
using System.Windows.Media.Imaging;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Structure;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Nice3point.Revit.Toolkit.External.Handlers;
2025-04-24 20:56:44 +08:00
2024-09-22 11:05:41 +08:00
// ReSharper disable ConditionIsAlwaysTrueOrFalse
2025-04-24 20:56:44 +08:00
namespace ShrlAlgoToolkit.RevitAddins.RvCommon;
2024-09-22 11:05:41 +08:00
public partial class InstanceCreatorViewModel : ObservableObject
{
public InstanceCreatorViewModel(UIDocument uiDocument)
{
this.uiDocument = uiDocument;
document = uiDocument.Document;
uiDocument.Application.Application.FamilyLoadedIntoDocument += Application_FamilyLoadedIntoDocument;
GetAvailableFamilies();
}
private readonly UIDocument uiDocument;
~InstanceCreatorViewModel()
{
uiDocument.Application.Application.FamilyLoadedIntoDocument -= Application_FamilyLoadedIntoDocument;
}
private void GetAvailableFamilies()
{
#if REVIT2018 || REVIT2020
//过滤掉栏杆族
var collector = document
.OfClass<Family>()
.Cast<Family>()
.Where(
f =>
f.IsEditable
&& !f.IsInPlace
&& f.GetFamilySymbolIds().Any()
&& f.FamilyCategory.Id.IntegerValue is not (-2000127 or -2009013 or -2005301 or -2009060)
&& f.FamilyPlacementType
is FamilyPlacementType.OneLevelBased
or FamilyPlacementType.TwoLevelsBased
or FamilyPlacementType.WorkPlaneBased
or FamilyPlacementType.OneLevelBasedHosted
)
.OrderBy(f => f.Name)
.ToList();
#elif REVIT2025
//过滤掉栏杆族
var collector = document
.OfClass<Family>()
.Cast<Family>()
.Where(
f =>
f.IsEditable
&& !f.IsInPlace
&& f.GetFamilySymbolIds().Any()
&& f.FamilyCategory.Id.Value is not (-2000127 or -2009013 or -2005301 or -2009060)
&& f.FamilyPlacementType
is FamilyPlacementType.OneLevelBased
or FamilyPlacementType.TwoLevelsBased
or FamilyPlacementType.WorkPlaneBased
or FamilyPlacementType.OneLevelBasedHosted
)
.OrderBy(f => f.Name)
.ToList();
#endif
Families = collector;
}
private void Application_FamilyLoadedIntoDocument(object sender, Autodesk.Revit.DB.Events.FamilyLoadedIntoDocumentEventArgs e)
{
GetAvailableFamilies();
}
private readonly ActionEventHandler handler = new();
[ObservableProperty]
private BitmapSource image;
[ObservableProperty]
2025-04-24 20:56:44 +08:00
[NotifyCanExecuteChangedFor(nameof(RevitAddins.RvCommon.InstanceCreatorViewModel.PlaceInstancesCommand))]
2024-09-22 11:05:41 +08:00
private bool canPlaceInstance = true;
private readonly Document document;
[ObservableProperty]
private double offset;
[ObservableProperty]
private Family selectedFamily;
[ObservableProperty]
2025-04-24 20:56:44 +08:00
[NotifyCanExecuteChangedFor(nameof(RevitAddins.RvCommon.InstanceCreatorViewModel.PlaceInstancesCommand))]
2024-09-22 11:05:41 +08:00
private FamilySymbol selectedFamilySymbol;
[ObservableProperty]
private List<Family> families;
[ObservableProperty]
private List<FamilySymbol> familySymbols;
private bool CanPlace()
{
return SelectedFamilySymbol != null && CanPlaceInstance;
}
[RelayCommand(CanExecute = nameof(CanPlace))]
private void PlaceInstances()
{
CanPlaceInstance = false;
handler.Raise(_ =>
{
var family = SelectedFamily;
var symbol = SelectedFamilySymbol;
var d = Offset / 304.8;
Reference reference;
try
{
2024-10-08 16:21:39 +08:00
reference = uiDocument.Selection.PickObject(ObjectType.PointOnElement, new DwgBlockSelection(), "请选择dwg链接的块参照");
2024-09-22 11:05:41 +08:00
}
catch (Autodesk.Revit.Exceptions.OperationCanceledException)
{
CanPlaceInstance = true;
return;
}
//图层ID
//Document.HideDwgLayer(referenceFunc, out ElementId columnGraphicStyleId, out GeometryElement columnGeoElem);
var dwg = document.GetElement(reference) as ImportInstance;
var geoInstances = dwg.GetBlocksByRef(reference);
var dwgTransform = dwg!.GetTotalTransform();
if (geoInstances == null || !geoInstances.Any())
{
MessageBox.Show("选中块为子块或选中块的嵌套层级过深请使用Tab来选择整体快", "识别失败", MessageBoxButton.OK, MessageBoxImage.Error);
CanPlaceInstance = true;
return;
}
document.Invoke(
_ =>
{
if (!symbol.IsActive)
{
symbol.Activate();
}
switch (family.FamilyPlacementType)
{
case FamilyPlacementType.OneLevelBased:
foreach (var ins in geoInstances)
{
var level = document.ActiveView.GenLevel;
GetPose(dwgTransform, ins, out var loc, out var rotation);
var familyInstance = document.Create.NewFamilyInstance(loc, symbol, level, StructuralType.NonStructural);
document.Regenerate();
ElementTransformUtils.RotateElement(document, familyInstance.Id, Line.CreateUnbound(loc, XYZ.BasisZ), rotation);
document.Regenerate();
var translation = XYZ.BasisZ * d;
ElementTransformUtils.MoveElement(document, familyInstance.Id, translation);
}
break;
case FamilyPlacementType.OneLevelBasedHosted:
#if REVIT2018 || REVIT2020
if (family.FamilyCategory.Id.IntegerValue is -2000023 or -2000014)
#elif REVIT2025
if (family.FamilyCategory.Id.Value is -2000023 or -2000014)
#endif
{
var level = document.ActiveView.GenLevel;
foreach (var ins in geoInstances)
{
GetPose(dwgTransform, ins, out var loc, out var rotation);
var minPoint = loc - new XYZ(0.4, 0.4, -level.Elevation);
var maxPoint = loc + new XYZ(0.4, 0.4, level.Elevation + 1);
var outline = new Outline(minPoint, maxPoint);
var intersectsFilter = new BoundingBoxIntersectsFilter(outline);
var intersect = document.OfClass<Wall>().WherePasses(intersectsFilter).FirstElement() as Wall;
var point = loc + (XYZ.BasisZ * level.Elevation);
document.Create.NewFamilyInstance(point, symbol, intersect, level, StructuralType.NonStructural);
}
}
break;
case FamilyPlacementType.TwoLevelsBased:
foreach (var ins in geoInstances)
{
var level = document.ActiveView.GenLevel;
GetPose(dwgTransform, ins, out var loc, out var rotation);
var familyInstance = document.Create.NewFamilyInstance(loc, symbol, level, StructuralType.NonStructural);
document.Regenerate();
ElementTransformUtils.RotateElement(document, familyInstance.Id, Line.CreateUnbound(loc, XYZ.BasisZ), rotation);
document.Regenerate();
var translation = XYZ.BasisZ * d;
ElementTransformUtils.MoveElement(document, familyInstance.Id, translation);
}
break;
case FamilyPlacementType.WorkPlaneBased:
foreach (var ins in geoInstances)
{
GetPose(dwgTransform, ins, out var loc, out var rotation);
var familyInstance = document.Create.NewFamilyInstance(
loc,
symbol,
document.ActiveView.SketchPlane,
StructuralType.NonStructural
);
document.Regenerate();
ElementTransformUtils.RotateElement(document, familyInstance.Id, Line.CreateUnbound(loc, XYZ.BasisZ), rotation);
document.Regenerate();
var translation = XYZ.BasisZ * d;
ElementTransformUtils.MoveElement(document, familyInstance.Id, translation);
}
break;
}
CanPlaceInstance = true;
},
"实例布置"
);
});
}
//private static Dictionary<XYZ, string> WriteCode(UIApplication uiapp)
//{
// var application = uiapp.Application;
// var uiDocument = uiapp.ActiveUIDocument;
// var doc = uiDocument.Document;
// Reference textRefer;
// try
// {
// //图层ID
// textRefer = uiDocument.Selection.PickObject(
// ObjectType.PointOnElement,
// new FuncFilter(e => e is ImportInstance import && import.IsLinked && doc.GetElement(e.GetTypeId()) is CADLinkType),
// "请选择“链接非导入”的Cad文字图层"
// );
// }
// catch (Autodesk.Revit.Exceptions.OperationCanceledException)
// {
// return null;
// }
// var dwg = doc.GetElement(textRefer) as ImportInstance;
// var textLayerName = dwg.GetLayerName(textRefer);
// var path = dwg.GetFilePath();
2024-09-22 11:05:41 +08:00
// var dwgTransform = dwg.GetTotalTransform();
// using ACadSharp.IO.DwgReader reader = new(path);
// var cadDocument = reader.Read();
// return cadDocument.Entities
// .OfType<ACadSharp.Entities.TextEntity>()
// .Where(e => e.Layer.Name == textLayerName)
// .ToDictionary(
// v =>
// {
// var loc = dwgTransform.OfPoint(new XYZ(v.InsertPoint.X, v.InsertPoint.Y, v.InsertPoint.Z));
// return new XYZ(loc.X, loc.Y, 0);
// },
// e => e.Value
// );
//}
/// <summary>
/// 获取更加准确的位置
/// </summary>
/// <param name="dwgTransform"></param>
/// <param name="ins"></param>
/// <param name="loc"></param>
/// <param name="rotation"></param>
private static void GetPose(Transform dwgTransform, GeometryInstance ins, out XYZ loc, out double rotation)
{
var blockLocation = ins.Transform.Origin;
if (ins.Transform.Origin.GetLength() is > 1000 or 0) //块原点距离实际几何重心过远时
{
//存在标注的情况时,以多段线最准确
var b = ins.GetInstanceGeometry().Any(i => i is PolyLine);
foreach (var geometryObject in ins.GetInstanceGeometry())
{
if (b)
{
if (geometryObject is PolyLine pl)
{
blockLocation = (pl.GetOutline().MaximumPoint + pl.GetOutline().MinimumPoint) / 2;
break;
}
}
else
{
if (geometryObject is Line l)
{
blockLocation = l.Evaluate(0.5, true);
break;
}
if (geometryObject is Arc arc)
{
blockLocation = arc.Center;
break;
}
}
}
}
loc = dwgTransform.OfPoint(blockLocation);
loc = new XYZ(loc.X, loc.Y, 0);
rotation = Math.Abs(ins.Transform.BasisX.AngleOnPlaneTo(XYZ.BasisX, XYZ.BasisZ) - (2 * Math.PI));
}
partial void OnSelectedFamilyChanged(Family value)
{
var doc = value.Document;
FamilySymbols = value.GetFamilySymbolIds().Select(id => doc.GetElement(id)).OfType<FamilySymbol>().ToList();
}
partial void OnSelectedFamilySymbolChanged(FamilySymbol value)
{
Image = value.GetPreviewImage(new System.Drawing.Size(128, 128)).ToBitmapSource();
}
}