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.Selection;
|
|
|
|
|
|
using CommunityToolkit.Mvvm.ComponentModel;
|
|
|
|
|
|
using CommunityToolkit.Mvvm.Input;
|
|
|
|
|
|
using Nice3point.Revit.Toolkit.External.Handlers;
|
2026-02-21 16:31:24 +08:00
|
|
|
|
|
|
|
|
|
|
using ShrlAlgoToolkit.RevitAddins.Common.Extensions;
|
2026-02-22 20:03:42 +08:00
|
|
|
|
using ShrlAlgoToolkit.RevitAddins.RvCommon;
|
|
|
|
|
|
using ShrlAlgoToolkit;
|
|
|
|
|
|
using ShrlAlgoToolkit.RevitAddins;
|
2025-02-10 20:53:40 +08:00
|
|
|
|
|
2025-04-24 20:56:44 +08:00
|
|
|
|
|
2024-09-22 11:05:41 +08:00
|
|
|
|
// ReSharper disable ConditionIsAlwaysTrueOrFalse
|
|
|
|
|
|
|
2026-02-22 20:03:42 +08:00
|
|
|
|
namespace ShrlAlgoToolkit.RevitAddins.Modeling;
|
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;
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
2024-09-22 11:05:41 +08:00
|
|
|
|
~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]
|
2025-10-04 08:52:23 +08:00
|
|
|
|
public partial BitmapSource Image { get; set; }
|
2024-09-22 11:05:41 +08:00
|
|
|
|
|
|
|
|
|
|
[ObservableProperty]
|
2026-02-22 20:03:42 +08:00
|
|
|
|
[NotifyCanExecuteChangedFor(nameof(Modeling.InstanceCreatorViewModel.PlaceInstancesCommand))]
|
2025-10-04 08:52:23 +08:00
|
|
|
|
public partial bool CanPlaceInstance { get; set; } = true;
|
2024-09-22 11:05:41 +08:00
|
|
|
|
|
|
|
|
|
|
private readonly Document document;
|
|
|
|
|
|
|
|
|
|
|
|
[ObservableProperty]
|
2025-10-04 08:52:23 +08:00
|
|
|
|
public partial double Offset { get; set; }
|
2024-09-22 11:05:41 +08:00
|
|
|
|
|
|
|
|
|
|
[ObservableProperty]
|
2025-10-04 08:52:23 +08:00
|
|
|
|
public partial Family SelectedFamily { get; set; }
|
2024-09-22 11:05:41 +08:00
|
|
|
|
|
|
|
|
|
|
[ObservableProperty]
|
2026-02-22 20:03:42 +08:00
|
|
|
|
[NotifyCanExecuteChangedFor(nameof(Modeling.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
|
|
|
|
|
|
{
|
2025-07-11 09:20:23 +08:00
|
|
|
|
reference = uiDocument.Selection.PickObject(ObjectType.PointOnElement, new DwgElementSelection(), "请选择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;
|
2025-07-11 09:20:23 +08:00
|
|
|
|
var loc = ins.GetLocationPoint(dwgTransform, out var rotation);
|
2024-09-22 11:05:41 +08:00
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
|
{
|
2025-07-11 09:20:23 +08:00
|
|
|
|
var loc = ins.GetLocationPoint(dwgTransform, out var rotation);
|
|
|
|
|
|
|
2024-09-22 11:05:41 +08:00
|
|
|
|
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;
|
2025-07-11 09:20:23 +08:00
|
|
|
|
var loc = ins.GetLocationPoint(dwgTransform, out var rotation);
|
|
|
|
|
|
|
2024-09-22 11:05:41 +08:00
|
|
|
|
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)
|
|
|
|
|
|
{
|
2025-07-11 09:20:23 +08:00
|
|
|
|
var loc = ins.GetLocationPoint(dwgTransform, out var rotation);
|
2024-09-22 11:05:41 +08:00
|
|
|
|
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);
|
2024-10-27 00:19:48 +08:00
|
|
|
|
// 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
|
|
|
|
|
|
// );
|
|
|
|
|
|
//}
|
|
|
|
|
|
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();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|