Files
Shrlalgo.RvKits/Sai.RvKits/RvCommon/InstanceCreatorViewModel.cs
2024-09-22 11:05:41 +08:00

327 lines
13 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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;
// ReSharper disable ConditionIsAlwaysTrueOrFalse
namespace Sai.RvKits.RvCommon;
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]
[NotifyCanExecuteChangedFor(nameof(PlaceInstancesCommand))]
private bool canPlaceInstance = true;
private readonly Document document;
[ObservableProperty]
private double offset;
[ObservableProperty]
private Family selectedFamily;
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(PlaceInstancesCommand))]
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
{
reference = uiDocument.Selection.PickObject(ObjectType.PointOnElement, new DwgBlockSelection(), "请选择dwg块");
}
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.GetDwgPath();
// 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();
}
}