2024-09-22 11:05:41 +08:00
|
|
|
|
using System.Collections.ObjectModel;
|
|
|
|
|
|
using System.Windows;
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
2024-09-22 11:05:41 +08:00
|
|
|
|
using Autodesk.Revit.DB;
|
|
|
|
|
|
using CommunityToolkit.Mvvm.ComponentModel;
|
|
|
|
|
|
using CommunityToolkit.Mvvm.Input;
|
2025-07-11 09:20:23 +08:00
|
|
|
|
|
2024-09-22 11:05:41 +08:00
|
|
|
|
using Nice3point.Revit.Toolkit.External.Handlers;
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-02-10 20:53:40 +08:00
|
|
|
|
|
2025-04-24 20:56:44 +08:00
|
|
|
|
namespace ShrlAlgoToolkit.RevitAddins.RvView;
|
2024-09-22 11:05:41 +08:00
|
|
|
|
|
|
|
|
|
|
public partial class SectionBoxControllerViewModel : ObservableObject
|
|
|
|
|
|
{
|
2024-12-22 10:26:12 +08:00
|
|
|
|
public SectionBoxControllerViewModel(UIApplication uiapp)
|
2024-09-22 11:05:41 +08:00
|
|
|
|
{
|
2024-12-22 10:26:12 +08:00
|
|
|
|
uiapp.ViewActivated -= Application_ViewActivated;
|
|
|
|
|
|
uiapp.ViewActivated += Application_ViewActivated;
|
2024-09-22 11:05:41 +08:00
|
|
|
|
|
2024-12-22 10:26:12 +08:00
|
|
|
|
if (uiapp.ActiveUIDocument.ActiveView is View3D view3d)
|
2024-09-22 11:05:41 +08:00
|
|
|
|
{
|
2024-12-22 10:26:12 +08:00
|
|
|
|
using var trans = new Transaction(uiapp.ActiveUIDocument.Document, "激活剖面框");
|
2024-09-22 11:05:41 +08:00
|
|
|
|
trans.Start();
|
|
|
|
|
|
if (!view3d.IsSectionBoxActive)
|
|
|
|
|
|
{
|
|
|
|
|
|
view3d.IsSectionBoxActive = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
//defaultSectionBox = view3D.GetSectionBox();
|
|
|
|
|
|
trans.Commit();
|
|
|
|
|
|
CanModify = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
CanModify = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
setSectionBoxHandler = new ActionEventHandler();
|
2024-12-22 10:26:12 +08:00
|
|
|
|
this.uiapp = uiapp;
|
2024-09-22 11:05:41 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void Application_ViewActivated(object sender, Autodesk.Revit.UI.Events.ViewActivatedEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
CanModify = e.CurrentActiveView is View3D view3d && view3d.IsSectionBoxActive;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[ObservableProperty]
|
2025-04-24 20:56:44 +08:00
|
|
|
|
[NotifyCanExecuteChangedFor(nameof(RevitAddins.RvView.SectionBoxControllerViewModel.RecordSectionBoxCommand), nameof(RevitAddins.RvView.SectionBoxControllerViewModel.UpdateSectionBoxCommand))]
|
2025-10-04 08:52:23 +08:00
|
|
|
|
public partial bool CanModify { get; set; }
|
|
|
|
|
|
|
2024-09-22 11:05:41 +08:00
|
|
|
|
[ObservableProperty]
|
2025-10-04 08:52:23 +08:00
|
|
|
|
public partial SectionBoxType SectionBoxType { get; set; }
|
|
|
|
|
|
|
2024-09-22 11:05:41 +08:00
|
|
|
|
[ObservableProperty]
|
2025-10-04 08:52:23 +08:00
|
|
|
|
public partial bool NeedExtend { get; set; }
|
|
|
|
|
|
|
2024-09-22 11:05:41 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 记录剖面框修改
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public ObservableCollection<SectionBox> BoundingBoxes { get; set; } = [];
|
|
|
|
|
|
|
|
|
|
|
|
private readonly ActionEventHandler setSectionBoxHandler;
|
2024-12-22 10:26:12 +08:00
|
|
|
|
private readonly UIApplication uiapp;
|
2024-09-22 11:05:41 +08:00
|
|
|
|
private int index = 1;
|
|
|
|
|
|
|
2025-04-24 20:56:44 +08:00
|
|
|
|
[RelayCommand(CanExecute = nameof(RevitAddins.RvView.SectionBoxControllerViewModel.CanModify))]
|
2024-09-22 11:05:41 +08:00
|
|
|
|
private void RecordSectionBox()
|
|
|
|
|
|
{
|
2024-12-22 10:26:12 +08:00
|
|
|
|
if (uiapp.ActiveUIDocument.Document.ActiveView is View3D { IsSectionBoxActive: true } view3D)
|
2024-09-22 11:05:41 +08:00
|
|
|
|
{
|
|
|
|
|
|
BoundingBoxes.Insert(0, new SectionBox($"剖面框 {index}", view3D.GetSectionBox()));
|
|
|
|
|
|
index++;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
[RelayCommand]
|
|
|
|
|
|
private void RemoveSectionBox(SectionBox sectionBox)
|
|
|
|
|
|
{
|
|
|
|
|
|
BoundingBoxes.Remove(sectionBox);
|
|
|
|
|
|
}
|
|
|
|
|
|
[RelayCommand]
|
|
|
|
|
|
private void ResetSectionBox()
|
|
|
|
|
|
{
|
2024-12-22 10:26:12 +08:00
|
|
|
|
setSectionBoxHandler.Raise(uiapp =>
|
2024-09-22 11:05:41 +08:00
|
|
|
|
{
|
2024-12-22 10:26:12 +08:00
|
|
|
|
var uidoc = uiapp.ActiveUIDocument;
|
2024-09-22 11:05:41 +08:00
|
|
|
|
switch (SectionBoxType)
|
|
|
|
|
|
{
|
|
|
|
|
|
case SectionBoxType.Element:
|
2024-12-22 10:26:12 +08:00
|
|
|
|
ResetSectionBoxByElement(uidoc);
|
2024-09-22 11:05:41 +08:00
|
|
|
|
break;
|
|
|
|
|
|
case SectionBoxType.Rectangle:
|
2024-12-22 10:26:12 +08:00
|
|
|
|
ResetSectionBoxByRectangle(uidoc);
|
2024-09-22 11:05:41 +08:00
|
|
|
|
break;
|
|
|
|
|
|
case SectionBoxType.ViewSection:
|
2024-12-22 10:26:12 +08:00
|
|
|
|
ResetSectionBoxByViewSection(uidoc);
|
2024-09-22 11:05:41 +08:00
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 重设元素剖面框
|
|
|
|
|
|
/// </summary>
|
2024-12-22 10:26:12 +08:00
|
|
|
|
private void ResetSectionBoxByElement(UIDocument uidoc)
|
2024-09-22 11:05:41 +08:00
|
|
|
|
{
|
|
|
|
|
|
var doc = uidoc.Document;
|
|
|
|
|
|
doc.Invoke(
|
|
|
|
|
|
ts =>
|
|
|
|
|
|
{
|
|
|
|
|
|
if (doc.ActiveView is not View3D view3D)
|
|
|
|
|
|
{
|
|
|
|
|
|
var viewFamilyType = doc.OfClass<ViewFamilyType>()
|
|
|
|
|
|
.Cast<ViewFamilyType>()
|
|
|
|
|
|
.FirstOrDefault(vft => vft.ViewFamily == ViewFamily.ThreeDimensional);
|
|
|
|
|
|
view3D = View3D.CreateIsometric(doc, viewFamilyType.Id);
|
|
|
|
|
|
view3D.DisplayStyle = DisplayStyle.ShadingWithEdges;
|
|
|
|
|
|
view3D.DetailLevel = ViewDetailLevel.Fine;
|
|
|
|
|
|
}
|
|
|
|
|
|
var elements = uidoc.GetSelectedElements();
|
|
|
|
|
|
if (elements.Count == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-07-11 09:20:23 +08:00
|
|
|
|
XYZ gmax = XYZ.Zero;
|
|
|
|
|
|
XYZ gmin = XYZ.Zero;
|
2024-09-22 11:05:41 +08:00
|
|
|
|
|
2025-07-11 09:20:23 +08:00
|
|
|
|
doc.InvokeSub(
|
|
|
|
|
|
sub =>
|
|
|
|
|
|
{
|
|
|
|
|
|
//var boundingBox = elements[0].get_BoundingBox(view3D);
|
|
|
|
|
|
//var maxX = boundingBox.Max.X;
|
|
|
|
|
|
//var maxY = boundingBox.Max.Y;
|
|
|
|
|
|
//var maxZ = boundingBox.Max.Z;
|
|
|
|
|
|
//var minX = boundingBox.Min.X;
|
|
|
|
|
|
//var minY = boundingBox.Min.Y;
|
|
|
|
|
|
//var minZ = boundingBox.Min.Z;
|
|
|
|
|
|
//foreach (var elem in elements)
|
|
|
|
|
|
//{
|
|
|
|
|
|
// var box = elem.get_BoundingBox(view3D);
|
|
|
|
|
|
// maxX = Math.Max(box.Max.X, maxX);
|
|
|
|
|
|
// maxY = Math.Max(box.Max.Y, maxY);
|
|
|
|
|
|
// maxZ = Math.Max(box.Max.Z, maxZ);
|
|
|
|
|
|
// minX = Math.Min(box.Min.X, minX);
|
|
|
|
|
|
// minY = Math.Min(box.Min.Y, minY);
|
|
|
|
|
|
// minZ = Math.Min(box.Min.Z, minZ);
|
|
|
|
|
|
//}
|
|
|
|
|
|
var elementIds = elements.Select(e => e.Id).ToList();
|
|
|
|
|
|
var g = doc.Create.NewGroup(elementIds);
|
|
|
|
|
|
var boundingBox = g.get_BoundingBox(null);
|
|
|
|
|
|
gmax = g.get_BoundingBox(null).Max;
|
|
|
|
|
|
gmin = g.get_BoundingBox(null).Min;
|
|
|
|
|
|
sub.RollBack();
|
|
|
|
|
|
if (!boundingBox.Enabled)
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show("当前三维剖面框不可用", "错误");
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
//var newbox = new BoundingBoxXYZ
|
|
|
|
|
|
//{
|
|
|
|
|
|
// Max = new XYZ(maxX, maxY, maxZ),
|
|
|
|
|
|
// Min = new XYZ(minX, minY, minZ)
|
|
|
|
|
|
//};
|
2024-09-22 11:05:41 +08:00
|
|
|
|
var newbox = new BoundingBoxXYZ
|
|
|
|
|
|
{
|
2025-07-11 09:20:23 +08:00
|
|
|
|
Max = gmax,
|
|
|
|
|
|
Min = gmin
|
2024-09-22 11:05:41 +08:00
|
|
|
|
};
|
|
|
|
|
|
//XYZ origin = new XYZ(0, 0, 0);
|
|
|
|
|
|
//XYZ axis = new XYZ(0, 0, 1);
|
|
|
|
|
|
//Transform rotate = Transform.CreateRotationAtPoint(axis, 2, origin);
|
|
|
|
|
|
//box.Transform = box.Transform.Multiply(rotate);
|
|
|
|
|
|
newbox = NeedExtend ? newbox.Extend() : newbox;
|
|
|
|
|
|
view3D?.SetSectionBox(newbox);
|
|
|
|
|
|
ts.Commit();
|
|
|
|
|
|
uidoc.ActiveView = view3D;
|
|
|
|
|
|
},
|
|
|
|
|
|
"重设(元素)剖面框");
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 重设框选剖面框
|
|
|
|
|
|
/// </summary>
|
2024-12-22 10:26:12 +08:00
|
|
|
|
private void ResetSectionBoxByRectangle(UIDocument uidoc)
|
2024-09-22 11:05:41 +08:00
|
|
|
|
{
|
|
|
|
|
|
var doc = uidoc.Document;
|
|
|
|
|
|
doc.Invoke(
|
|
|
|
|
|
ts =>
|
|
|
|
|
|
{
|
|
|
|
|
|
if (uidoc.ActiveView is not ViewPlan viewPlane)
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show("请在平面上框选范围", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
var box = uidoc.Selection.PickBox(Autodesk.Revit.UI.Selection.PickBoxStyle.Directional);
|
|
|
|
|
|
var max = box.Max;
|
|
|
|
|
|
var min = box.Min;
|
|
|
|
|
|
|
|
|
|
|
|
var currentLevel = viewPlane.GenLevel;
|
|
|
|
|
|
var level = doc.OfClass<Level>()
|
|
|
|
|
|
.Cast<Level>()
|
|
|
|
|
|
.OrderBy(l => l.Elevation)
|
|
|
|
|
|
.FirstOrDefault(l => l.Elevation > currentLevel.Elevation);
|
|
|
|
|
|
|
|
|
|
|
|
var boundMax = new XYZ(Math.Max(max.X, min.X), Math.Max(max.Y, min.Y), level.Elevation);
|
|
|
|
|
|
var boundMin = new XYZ(Math.Min(max.X, min.X), Math.Min(max.Y, min.Y), min.Z);
|
|
|
|
|
|
var bounding = new BoundingBoxXYZ() { Max = boundMax, Min = boundMin };
|
|
|
|
|
|
var viewFamilyType = doc.OfClass<ViewFamilyType>()
|
|
|
|
|
|
.Cast<ViewFamilyType>()
|
|
|
|
|
|
.FirstOrDefault(vft => vft.ViewFamily == ViewFamily.ThreeDimensional);
|
|
|
|
|
|
var view3D = View3D.CreateIsometric(doc, viewFamilyType.Id);
|
|
|
|
|
|
view3D.IsSectionBoxActive = true;
|
|
|
|
|
|
bounding = NeedExtend ? bounding : bounding.Extend();
|
|
|
|
|
|
|
|
|
|
|
|
view3D.SetSectionBox(bounding);
|
|
|
|
|
|
view3D.DisplayStyle = DisplayStyle.ShadingWithEdges;
|
|
|
|
|
|
view3D.DetailLevel = ViewDetailLevel.Fine;
|
|
|
|
|
|
ts.Commit();
|
|
|
|
|
|
uidoc.ActiveView = view3D;
|
|
|
|
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
"重设(框选)剖面框");
|
|
|
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 重设剖面视图范围的剖面框
|
|
|
|
|
|
/// </summary>
|
2024-12-22 10:26:12 +08:00
|
|
|
|
private void ResetSectionBoxByViewSection(UIDocument uidoc)
|
2024-09-22 11:05:41 +08:00
|
|
|
|
{
|
|
|
|
|
|
var reference = uidoc.Selection.PickObject(Autodesk.Revit.UI.Selection.ObjectType.Element, new FuncFilter(elem => elem.Category?.GetHashCode() == -2000278), "请选择剖面视图");
|
|
|
|
|
|
var doc = uidoc.Document;
|
|
|
|
|
|
var element = doc.GetElement(reference);
|
|
|
|
|
|
if (element != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
doc.Invoke(
|
|
|
|
|
|
ts =>
|
|
|
|
|
|
{
|
|
|
|
|
|
var viewFamilyType = doc.OfClass<ViewFamilyType>()
|
|
|
|
|
|
.Cast<ViewFamilyType>()
|
|
|
|
|
|
.FirstOrDefault(vft => vft.ViewFamily == ViewFamily.ThreeDimensional);
|
|
|
|
|
|
//新建的三维视图
|
|
|
|
|
|
var view3D = View3D.CreateIsometric(doc, viewFamilyType.Id);
|
|
|
|
|
|
if (doc.ActiveView is not ViewSection viewSection)
|
|
|
|
|
|
{
|
|
|
|
|
|
viewSection = doc.OfClass<View>().Cast<View>().FirstOrDefault(v => v.Name == element.Name && v.ViewType == ViewType.Section && !v.IsTemplate) as ViewSection;
|
|
|
|
|
|
}
|
|
|
|
|
|
view3D.IsSectionBoxActive = true;
|
|
|
|
|
|
doc.Regenerate();
|
|
|
|
|
|
//最新添加的即是当前复制视图的剖面框
|
|
|
|
|
|
//var cropBoxElement = view3D.OfCategory(BuiltInCategory.OST_SectionBox).Last();
|
|
|
|
|
|
//实际位置的BoundingBox
|
|
|
|
|
|
//var bounding = element.get_BoundingBox(viewSection);
|
|
|
|
|
|
//相对剖面的BoundingBox,准确的剖面框大小,具有transform
|
|
|
|
|
|
var boundingBox = viewSection.CropBox;
|
|
|
|
|
|
//var b = Transform.CreateRotationAtPoint(viewSection.RightDirection, Math.PI / 2, viewSection.Origin);
|
|
|
|
|
|
//重新构造一个变换,由于视图的变换r x v = u满足左手定则,与全局坐标系右手定则不一样,将其坐标轴修改为全局坐标系的一样的右手定则
|
|
|
|
|
|
var transform = Transform.Identity;
|
|
|
|
|
|
transform.BasisX = viewSection.RightDirection;
|
|
|
|
|
|
//Y轴取反
|
|
|
|
|
|
transform.BasisY = -viewSection.ViewDirection;
|
|
|
|
|
|
transform.BasisZ = viewSection.UpDirection;
|
|
|
|
|
|
transform.Origin = boundingBox.Transform.Origin;
|
|
|
|
|
|
//boundingBox.Max.Z固定等于0,因为ViewDirection朝外面向用户,Min的Z值始终小于0,即反向
|
|
|
|
|
|
var max = new XYZ(boundingBox.Max.X, -boundingBox.Min.Z, boundingBox.Max.Y);
|
|
|
|
|
|
var min = new XYZ(boundingBox.Min.X, -boundingBox.Max.Z, boundingBox.Min.Y);
|
|
|
|
|
|
boundingBox.Max = max;
|
|
|
|
|
|
boundingBox.Min = min;
|
|
|
|
|
|
boundingBox.Transform = transform;
|
|
|
|
|
|
|
|
|
|
|
|
boundingBox = NeedExtend ? boundingBox : boundingBox.Extend();
|
|
|
|
|
|
view3D.SetSectionBox(boundingBox);
|
|
|
|
|
|
//ElementTransformUtils.MoveElement(doc, cropBoxElement.Id, viewSection.Origin);
|
|
|
|
|
|
view3D.DisplayStyle = DisplayStyle.ShadingWithEdges;
|
|
|
|
|
|
view3D.DetailLevel = ViewDetailLevel.Fine;
|
|
|
|
|
|
|
|
|
|
|
|
ts.Commit();
|
|
|
|
|
|
uidoc.ActiveView = view3D;
|
|
|
|
|
|
},
|
|
|
|
|
|
"重设(剖面)剖面框");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-04-24 20:56:44 +08:00
|
|
|
|
[RelayCommand(CanExecute = nameof(RevitAddins.RvView.SectionBoxControllerViewModel.CanModify))]
|
2024-09-22 11:05:41 +08:00
|
|
|
|
private void UpdateSectionBox(object obj)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (obj is BoundingBoxXYZ boundingBoxXyz)
|
|
|
|
|
|
{
|
2024-12-22 10:26:12 +08:00
|
|
|
|
setSectionBoxHandler.Raise(uiapp =>
|
2024-09-22 11:05:41 +08:00
|
|
|
|
{
|
2024-12-22 10:26:12 +08:00
|
|
|
|
var uidoc = uiapp.ActiveUIDocument;
|
2024-09-22 11:05:41 +08:00
|
|
|
|
if (uidoc.ActiveView is View3D view3d)
|
|
|
|
|
|
{
|
|
|
|
|
|
uidoc.Document.Invoke(_ =>
|
|
|
|
|
|
{
|
|
|
|
|
|
view3d?.SetSectionBox(boundingBoxXyz);
|
|
|
|
|
|
|
|
|
|
|
|
}, "更新剖面框");
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public class SectionBox(string name, BoundingBoxXYZ bounding)
|
|
|
|
|
|
{
|
|
|
|
|
|
public string Name { get; set; } = name;
|
|
|
|
|
|
|
|
|
|
|
|
public BoundingBoxXYZ Bounding { get; set; } = bounding;
|
|
|
|
|
|
}
|
|
|
|
|
|
public enum SectionBoxType
|
|
|
|
|
|
{
|
|
|
|
|
|
Element,
|
|
|
|
|
|
Rectangle,
|
|
|
|
|
|
ViewSection,
|
|
|
|
|
|
}
|