Add selection-based clip box controls
This commit is contained in:
parent
18b530ef5f
commit
bbd72345c9
@ -14,6 +14,13 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class LogisticsControlViewModel : ViewModelBase
|
public class LogisticsControlViewModel : ViewModelBase
|
||||||
{
|
{
|
||||||
|
private enum ClipBoxFocusMode
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
Path,
|
||||||
|
Selection
|
||||||
|
}
|
||||||
|
|
||||||
#region 私有字段
|
#region 私有字段
|
||||||
|
|
||||||
private string _statusText;
|
private string _statusText;
|
||||||
@ -144,6 +151,9 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
|||||||
}
|
}
|
||||||
|
|
||||||
private bool _isClipBoxEnabled;
|
private bool _isClipBoxEnabled;
|
||||||
|
private bool _isSelectionClipBoxEnabled;
|
||||||
|
private bool _isUpdatingClipBoxState;
|
||||||
|
private ClipBoxFocusMode _clipBoxFocusMode = ClipBoxFocusMode.None;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 是否启用剖面盒(聚焦当前路径)
|
/// 是否启用剖面盒(聚焦当前路径)
|
||||||
@ -155,14 +165,45 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
|||||||
{
|
{
|
||||||
if (SetProperty(ref _isClipBoxEnabled, value))
|
if (SetProperty(ref _isClipBoxEnabled, value))
|
||||||
{
|
{
|
||||||
|
if (_isUpdatingClipBoxState)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (value)
|
if (value)
|
||||||
{
|
{
|
||||||
EnableClipBoxForCurrentRoute();
|
ActivatePathClipBox();
|
||||||
}
|
}
|
||||||
else
|
else if (_clipBoxFocusMode == ClipBoxFocusMode.Path)
|
||||||
{
|
{
|
||||||
SectionClipHelper.ClearClipBox();
|
ClearActiveClipBox();
|
||||||
LogManager.Info("[剖面盒] 已关闭");
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否启用剖面盒(聚焦当前选择对象)
|
||||||
|
/// </summary>
|
||||||
|
public bool IsSelectionClipBoxEnabled
|
||||||
|
{
|
||||||
|
get => _isSelectionClipBoxEnabled;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (SetProperty(ref _isSelectionClipBoxEnabled, value))
|
||||||
|
{
|
||||||
|
if (_isUpdatingClipBoxState)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value)
|
||||||
|
{
|
||||||
|
ActivateSelectionClipBox();
|
||||||
|
}
|
||||||
|
else if (_clipBoxFocusMode == ClipBoxFocusMode.Selection)
|
||||||
|
{
|
||||||
|
ClearActiveClipBox();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -238,7 +279,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
|||||||
// 用于剖面盒自动跟随路径切换
|
// 用于剖面盒自动跟随路径切换
|
||||||
_pathPlanningManager.CurrentRouteSwitched += (s, e) =>
|
_pathPlanningManager.CurrentRouteSwitched += (s, e) =>
|
||||||
{
|
{
|
||||||
if (IsClipBoxEnabled)
|
if (_clipBoxFocusMode == ClipBoxFocusMode.Path)
|
||||||
{
|
{
|
||||||
if (_pathPlanningManager.PathEditState == PathEditState.Creating)
|
if (_pathPlanningManager.PathEditState == PathEditState.Creating)
|
||||||
{
|
{
|
||||||
@ -252,6 +293,11 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (NavisApplication.ActiveDocument?.CurrentSelection != null)
|
||||||
|
{
|
||||||
|
NavisApplication.ActiveDocument.CurrentSelection.Changed += OnCurrentSelectionChanged;
|
||||||
|
}
|
||||||
|
|
||||||
// 初始化状态
|
// 初始化状态
|
||||||
StatusText = "插件已就绪";
|
StatusText = "插件已就绪";
|
||||||
|
|
||||||
@ -333,6 +379,63 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
|||||||
|
|
||||||
#region 剖面盒功能
|
#region 剖面盒功能
|
||||||
|
|
||||||
|
private void ActivatePathClipBox()
|
||||||
|
{
|
||||||
|
SetClipBoxState(ClipBoxFocusMode.Path);
|
||||||
|
EnableClipBoxForCurrentRoute();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ActivateSelectionClipBox()
|
||||||
|
{
|
||||||
|
SetClipBoxState(ClipBoxFocusMode.Selection);
|
||||||
|
EnableClipBoxForCurrentSelection();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ClearActiveClipBox()
|
||||||
|
{
|
||||||
|
SetClipBoxState(ClipBoxFocusMode.None);
|
||||||
|
SectionClipHelper.ClearClipBox();
|
||||||
|
LogManager.Info("[剖面盒] 已关闭");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetClipBoxState(ClipBoxFocusMode mode)
|
||||||
|
{
|
||||||
|
_clipBoxFocusMode = mode;
|
||||||
|
bool pathEnabled = mode == ClipBoxFocusMode.Path;
|
||||||
|
bool selectionEnabled = mode == ClipBoxFocusMode.Selection;
|
||||||
|
|
||||||
|
_isUpdatingClipBoxState = true;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (_isClipBoxEnabled != pathEnabled)
|
||||||
|
{
|
||||||
|
_isClipBoxEnabled = pathEnabled;
|
||||||
|
OnPropertyChanged(nameof(IsClipBoxEnabled));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_isSelectionClipBoxEnabled != selectionEnabled)
|
||||||
|
{
|
||||||
|
_isSelectionClipBoxEnabled = selectionEnabled;
|
||||||
|
OnPropertyChanged(nameof(IsSelectionClipBoxEnabled));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_isUpdatingClipBoxState = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnCurrentSelectionChanged(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
if (_clipBoxFocusMode != ClipBoxFocusMode.Selection)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LogManager.Info("[剖面盒] 选择已变化,重新聚焦到当前选择对象");
|
||||||
|
EnableClipBoxForCurrentSelection();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 启用剖面盒并聚焦到当前路径
|
/// 启用剖面盒并聚焦到当前路径
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -344,7 +447,8 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
|||||||
if (currentRoute?.Points == null || currentRoute.Points.Count == 0)
|
if (currentRoute?.Points == null || currentRoute.Points.Count == 0)
|
||||||
{
|
{
|
||||||
LogManager.Warning("[剖面盒] 当前没有路径,无法设置剖面盒");
|
LogManager.Warning("[剖面盒] 当前没有路径,无法设置剖面盒");
|
||||||
IsClipBoxEnabled = false;
|
SectionClipHelper.ClearClipBox();
|
||||||
|
SetClipBoxState(ClipBoxFocusMode.None);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -390,13 +494,59 @@ namespace NavisworksTransport.UI.WPF.ViewModels
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogManager.Warning("[剖面盒] 设置失败");
|
LogManager.Warning("[剖面盒] 设置失败");
|
||||||
IsClipBoxEnabled = false;
|
SectionClipHelper.ClearClipBox();
|
||||||
|
SetClipBoxState(ClipBoxFocusMode.None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
LogManager.Error($"[剖面盒] 启用失败: {ex.Message}");
|
LogManager.Error($"[剖面盒] 启用失败: {ex.Message}");
|
||||||
IsClipBoxEnabled = false;
|
SectionClipHelper.ClearClipBox();
|
||||||
|
SetClipBoxState(ClipBoxFocusMode.None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 启用剖面盒并聚焦到当前选择对象
|
||||||
|
/// </summary>
|
||||||
|
private void EnableClipBoxForCurrentSelection()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var document = NavisApplication.ActiveDocument;
|
||||||
|
var selectedItems = document?.CurrentSelection?.SelectedItems?.Cast<ModelItem>().Where(item => item != null).ToList();
|
||||||
|
if (selectedItems == null || selectedItems.Count == 0)
|
||||||
|
{
|
||||||
|
LogManager.Warning("[剖面盒] 当前没有选中的模型对象,无法设置剖面盒");
|
||||||
|
SectionClipHelper.ClearClipBox();
|
||||||
|
SetClipBoxState(ClipBoxFocusMode.None);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SectionClipHelper.ClearClipBox();
|
||||||
|
|
||||||
|
bool success = SectionClipHelper.SetClipBoxByModelItems(
|
||||||
|
selectedItems,
|
||||||
|
marginInMeters: 2.0,
|
||||||
|
heightMarginInMeters: 2.0);
|
||||||
|
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
ViewpointHelper.FocusOnModelItems(selectedItems, ViewpointHelper.ViewpointStrategy.ModelFocus);
|
||||||
|
LogManager.Info($"[剖面盒] 已按当前选择对象启用,选择数量: {selectedItems.Count}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogManager.Warning("[剖面盒] 按选择对象设置失败");
|
||||||
|
SectionClipHelper.ClearClipBox();
|
||||||
|
SetClipBoxState(ClipBoxFocusMode.None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogManager.Error($"[剖面盒] 按选择对象启用失败: {ex.Message}");
|
||||||
|
SectionClipHelper.ClearClipBox();
|
||||||
|
SetClipBoxState(ClipBoxFocusMode.None);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -147,17 +147,47 @@ NavisworksTransport 主控制面板 - 采用与其他视图一致的Navisworks 2
|
|||||||
Foreground="#FFCCCCCC"
|
Foreground="#FFCCCCCC"
|
||||||
FontSize="14"/>
|
FontSize="14"/>
|
||||||
|
|
||||||
<!-- 剖面盒开关 -->
|
<!-- 选择对象剖面盒开关 -->
|
||||||
|
<ToggleButton IsChecked="{Binding IsSelectionClipBoxEnabled}"
|
||||||
|
ToolTip="剖面盒(聚焦当前选择对象)"
|
||||||
|
Width="28" Height="24"
|
||||||
|
Margin="2,0">
|
||||||
|
<Viewbox Width="18" Height="18" Stretch="Uniform">
|
||||||
|
<Canvas Width="20" Height="20">
|
||||||
|
<Path Data="M 2,6 L 14,6 L 14,18 L 2,18 Z M 2,6 L 6,2 L 18,2 L 14,6 M 14,18 L 18,14 L 18,2 L 14,6"
|
||||||
|
Stroke="{Binding IsSelectionClipBoxEnabled, Converter={StaticResource BoolToBrushConverter}, ConverterParameter=Green}"
|
||||||
|
StrokeThickness="1.3"
|
||||||
|
Fill="Transparent"/>
|
||||||
|
<Rectangle Canvas.Left="6"
|
||||||
|
Canvas.Top="10"
|
||||||
|
Width="4"
|
||||||
|
Height="4"
|
||||||
|
Stroke="{Binding IsSelectionClipBoxEnabled, Converter={StaticResource BoolToBrushConverter}, ConverterParameter=Green}"
|
||||||
|
StrokeThickness="1.2"
|
||||||
|
Fill="Transparent"/>
|
||||||
|
</Canvas>
|
||||||
|
</Viewbox>
|
||||||
|
</ToggleButton>
|
||||||
|
|
||||||
|
<!-- 路径剖面盒开关 -->
|
||||||
<ToggleButton IsChecked="{Binding IsClipBoxEnabled}"
|
<ToggleButton IsChecked="{Binding IsClipBoxEnabled}"
|
||||||
ToolTip="剖面盒(聚焦当前路径)"
|
ToolTip="剖面盒(聚焦当前路径)"
|
||||||
Width="28" Height="24"
|
Width="28" Height="24"
|
||||||
Margin="2,0">
|
Margin="2,0">
|
||||||
|
<Viewbox Width="18" Height="18" Stretch="Uniform">
|
||||||
|
<Canvas Width="20" Height="20">
|
||||||
<Path Data="M 2,6 L 14,6 L 14,18 L 2,18 Z M 2,6 L 6,2 L 18,2 L 14,6 M 14,18 L 18,14 L 18,2 L 14,6"
|
<Path Data="M 2,6 L 14,6 L 14,18 L 2,18 Z M 2,6 L 6,2 L 18,2 L 14,6 M 14,18 L 18,14 L 18,2 L 14,6"
|
||||||
Stroke="{Binding IsClipBoxEnabled, Converter={StaticResource BoolToBrushConverter}, ConverterParameter=Red}"
|
Stroke="{Binding IsClipBoxEnabled, Converter={StaticResource BoolToBrushConverter}, ConverterParameter=Green}"
|
||||||
StrokeThickness="1.5"
|
StrokeThickness="1.3"
|
||||||
Fill="Transparent"
|
Fill="Transparent"/>
|
||||||
Stretch="Uniform"
|
<Polyline Points="5.5,13 7.2,11 8.1,12 10.5,10"
|
||||||
Margin="2"/>
|
Stroke="{Binding IsClipBoxEnabled, Converter={StaticResource BoolToBrushConverter}, ConverterParameter=Green}"
|
||||||
|
StrokeThickness="1.2"
|
||||||
|
StrokeLineJoin="Round"
|
||||||
|
StrokeStartLineCap="Round"
|
||||||
|
StrokeEndLineCap="Round"/>
|
||||||
|
</Canvas>
|
||||||
|
</Viewbox>
|
||||||
</ToggleButton>
|
</ToggleButton>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using Autodesk.Navisworks.Api;
|
using Autodesk.Navisworks.Api;
|
||||||
|
|
||||||
namespace NavisworksTransport.Utils
|
namespace NavisworksTransport.Utils
|
||||||
@ -131,6 +132,78 @@ namespace NavisworksTransport.Utils
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 根据模型项集合设置剖面盒
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="modelItems">模型项集合</param>
|
||||||
|
/// <param name="marginInMeters">水平边距(米)</param>
|
||||||
|
/// <param name="heightMarginInMeters">高度边距(米,上下各延伸)</param>
|
||||||
|
/// <returns>是否成功设置</returns>
|
||||||
|
public static bool SetClipBoxByModelItems(
|
||||||
|
IEnumerable<ModelItem> modelItems,
|
||||||
|
double marginInMeters = 2.0,
|
||||||
|
double heightMarginInMeters = 2.0)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (modelItems == null)
|
||||||
|
{
|
||||||
|
LogManager.Warning("[剖面盒] 模型项集合为空");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var validItems = modelItems.Where(item => item != null).ToList();
|
||||||
|
if (validItems.Count == 0)
|
||||||
|
{
|
||||||
|
LogManager.Warning("[剖面盒] 没有可用的模型项,无法设置剖面盒");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasBounds = false;
|
||||||
|
double minX = double.MaxValue, minY = double.MaxValue, minZ = double.MaxValue;
|
||||||
|
double maxX = double.MinValue, maxY = double.MinValue, maxZ = double.MinValue;
|
||||||
|
|
||||||
|
foreach (var item in validItems)
|
||||||
|
{
|
||||||
|
BoundingBox3D bounds = item.BoundingBox();
|
||||||
|
minX = Math.Min(minX, bounds.Min.X);
|
||||||
|
minY = Math.Min(minY, bounds.Min.Y);
|
||||||
|
minZ = Math.Min(minZ, bounds.Min.Z);
|
||||||
|
maxX = Math.Max(maxX, bounds.Max.X);
|
||||||
|
maxY = Math.Max(maxY, bounds.Max.Y);
|
||||||
|
maxZ = Math.Max(maxZ, bounds.Max.Z);
|
||||||
|
hasBounds = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasBounds)
|
||||||
|
{
|
||||||
|
LogManager.Warning("[剖面盒] 未能从模型项中计算有效包围盒");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
double metersToUnits = UnitsConverter.GetMetersToUnitsConversionFactor(Application.ActiveDocument.Units);
|
||||||
|
double margin = marginInMeters * metersToUnits;
|
||||||
|
double heightMargin = heightMarginInMeters * metersToUnits;
|
||||||
|
|
||||||
|
var selectionBounds = new BoundingBox3D(
|
||||||
|
new Point3D(minX, minY, minZ),
|
||||||
|
new Point3D(maxX, maxY, maxZ));
|
||||||
|
var clipBox = ExpandBoundingBox(selectionBounds, margin, heightMargin);
|
||||||
|
|
||||||
|
ApplyClipBox(clipBox);
|
||||||
|
|
||||||
|
LogManager.Info($"[剖面盒] 已按选择对象设置 - 对象数: {validItems.Count}, 水平边距: {marginInMeters}m, 高度边距: {heightMarginInMeters}m, " +
|
||||||
|
$"范围: X[{clipBox.Min.X:F2}, {clipBox.Max.X:F2}], Y[{clipBox.Min.Y:F2}, {clipBox.Max.Y:F2}], Z[{clipBox.Min.Z:F2}, {clipBox.Max.Z:F2}]");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogManager.Error($"[剖面盒] 按选择对象设置失败: {ex.Message}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 清除剖面盒(显示全部模型)
|
/// 清除剖面盒(显示全部模型)
|
||||||
/// 使用 JSON 字符串方式设置 Enabled = false
|
/// 使用 JSON 字符串方式设置 Enabled = false
|
||||||
|
|||||||
@ -689,6 +689,36 @@ namespace NavisworksTransport.Utils
|
|||||||
FocusOnModelItem(modelItem, profile.ViewAngleDegrees, profile.TargetViewRatio);
|
FocusOnModelItem(modelItem, profile.ViewAngleDegrees, profile.TargetViewRatio);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void FocusOnModelItems(IEnumerable<ModelItem> modelItems, ViewpointStrategy strategy)
|
||||||
|
{
|
||||||
|
if (modelItems == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(modelItems));
|
||||||
|
}
|
||||||
|
|
||||||
|
List<ModelItem> items = modelItems.Where(item => item != null).ToList();
|
||||||
|
if (items.Count == 0)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("至少需要一个模型元素", nameof(modelItems));
|
||||||
|
}
|
||||||
|
|
||||||
|
BoundingBox3D combinedBounds = items[0].BoundingBox();
|
||||||
|
for (int i = 1; i < items.Count; i++)
|
||||||
|
{
|
||||||
|
BoundingBox3D itemBounds = items[i].BoundingBox();
|
||||||
|
combinedBounds.Extend(itemBounds.Min);
|
||||||
|
combinedBounds.Extend(itemBounds.Max);
|
||||||
|
}
|
||||||
|
|
||||||
|
Point3D center = new Point3D(
|
||||||
|
(combinedBounds.Min.X + combinedBounds.Max.X) / 2.0,
|
||||||
|
(combinedBounds.Min.Y + combinedBounds.Max.Y) / 2.0,
|
||||||
|
(combinedBounds.Min.Z + combinedBounds.Max.Z) / 2.0);
|
||||||
|
double targetSize = GetMaxDimension(combinedBounds);
|
||||||
|
|
||||||
|
FocusOnPosition(center, targetSize, strategy);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 聚焦到多个模型元素(如碰撞中的两个对象)
|
/// 聚焦到多个模型元素(如碰撞中的两个对象)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user