diff --git a/src/UI/WPF/ViewModels/PathEditingViewModel.cs b/src/UI/WPF/ViewModels/PathEditingViewModel.cs
index 528bbf2..ca64002 100644
--- a/src/UI/WPF/ViewModels/PathEditingViewModel.cs
+++ b/src/UI/WPF/ViewModels/PathEditingViewModel.cs
@@ -12,6 +12,7 @@ using System.Text;
using System.Numerics;
using Microsoft.Win32;
using Autodesk.Navisworks.Api;
+using Autodesk.Navisworks.Api.Plugins;
using NavisApplication = Autodesk.Navisworks.Api.Application;
using NavisworksTransport.Core;
using NavisworksTransport.Core.Config;
@@ -1411,6 +1412,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
public ICommand CancelRailAssemblyWorkflowCommand { get; private set; }
public ICommand AnalyzeAssemblyTerminalFaceForCreateCommand { get; private set; }
public ICommand AnalyzeAssemblyTerminalFaceForEditCommand { get; private set; }
+ public ICommand QuickAnalyzeAssemblyEndFaceCommand { get; private set; }
public ICommand DecreaseSelectedRailNormalOffsetCommand { get; private set; }
public ICommand IncreaseSelectedRailNormalOffsetCommand { get; private set; }
@@ -1482,6 +1484,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
!IsSelectingAssemblyStartPoint &&
!IsSelectingAssemblyEndFacePoints &&
!_isSelectingAssemblyInstallationPoint;
+ public bool CanQuickAnalyzeAssemblyEndFace => CanAnalyzeAssemblyTerminalFaceForCreate;
public bool CanAnalyzeAssemblyTerminalFaceForEdit => HasAssemblyTerminalObject &&
IsRailRouteSelected &&
SelectedPathRoute != null &&
@@ -1691,6 +1694,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
private void NotifyRailAssemblyCommandStateChanged()
{
OnPropertyChanged(nameof(CanAnalyzeAssemblyTerminalFaceForCreate));
+ OnPropertyChanged(nameof(CanQuickAnalyzeAssemblyEndFace));
OnPropertyChanged(nameof(CanAnalyzeAssemblyTerminalFaceForEdit));
OnPropertyChanged(nameof(CanSelectAssemblyStartPointForCreate));
OnPropertyChanged(nameof(CanRepositionRailStartPoint));
@@ -2073,6 +2077,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
CancelRailAssemblyWorkflowCommand = new RelayCommand(() => ExecuteCancelRailAssemblyWorkflow(), () => CanCancelRailAssemblyWorkflow);
AnalyzeAssemblyTerminalFaceForCreateCommand = new RelayCommand(async () => await ExecuteAnalyzeAssemblyTerminalFaceAsync(RailAssemblyWorkflowMode.CreateNewRailPath), () => CanAnalyzeAssemblyTerminalFaceForCreate);
AnalyzeAssemblyTerminalFaceForEditCommand = new RelayCommand(async () => await ExecuteAnalyzeAssemblyTerminalFaceAsync(RailAssemblyWorkflowMode.EditSelectedRail), () => CanAnalyzeAssemblyTerminalFaceForEdit);
+ QuickAnalyzeAssemblyEndFaceCommand = new RelayCommand(() => BeginAssemblyEndFaceQuickPick(), () => CanQuickAnalyzeAssemblyEndFace);
DecreaseSelectedRailNormalOffsetCommand = new RelayCommand(() => AdjustSelectedRailNormalOffset(-RailNormalOffsetNudgeStepInMeters));
IncreaseSelectedRailNormalOffsetCommand = new RelayCommand(() => AdjustSelectedRailNormalOffset(RailNormalOffsetNudgeStepInMeters));
ApplyHoistingLayerHeightsCommand = new RelayCommand(async () => await ExecuteApplyHoistingLayerHeightsAsync(), () => CanApplyHoistingLayerHeights);
@@ -2477,6 +2482,105 @@ namespace NavisworksTransport.UI.WPF.ViewModels
LogManager.Info(logMessage);
}
+ private void BeginAssemblyEndFaceQuickPick()
+ {
+ CleanupAssemblyReferenceSelection();
+ CleanupAssemblyEndFaceSelection(clearVisuals: false);
+ CleanupAssemblyInstallationSelection();
+ ClearAssemblyEndFaceAnalysisVisuals();
+ ResetAssemblyEndFaceAnalysisState();
+ ClearAssemblyInstallationReferenceVisuals();
+ ResetAssemblyInstallationReferenceState();
+ _assemblyEndFaceSeedPoints.Clear();
+
+ _pathPlanningManager.DisableMouseHandling();
+ _isSelectingAssemblyEndFacePoints = true;
+ NotifyRailAssemblyCommandStateChanged();
+
+ // 激活取面工具
+ try
+ {
+ var assemblyPath = FaceInferToolPlugin.AssemblyPath;
+ NavisApplication.Plugins.AddPluginAssembly(assemblyPath);
+ var record = (ToolPluginRecord)NavisApplication.Plugins.FindPlugin("FaceInferTool.NavisworksTransport");
+ var loadedPlugin = record.LoadPlugin();
+ NavisApplication.MainDocument.Tool.Value = Tool.None;
+ NavisApplication.MainDocument.Tool.SetCustomToolPlugin(loadedPlugin);
+ }
+ catch (Exception ex)
+ {
+ LogManager.Error($"[直线装配] 激活取面工具失败: {ex.Message}", ex);
+ CleanupAssemblyEndFaceSelection(clearVisuals: true);
+ throw new InvalidOperationException("取面工具激活失败,请重试。");
+ }
+
+ FaceInferToolPlugin.FaceInferred += OnQuickEndFaceInferred;
+
+ UpdateMainStatus("请在终点箱体端面上点击一下,系统将自动分析端面中心。");
+ LogManager.Info("[直线装配] 已进入快速取端面模式");
+ }
+
+ private void OnQuickEndFaceInferred(object sender, FaceInferResult result)
+ {
+ FaceInferToolPlugin.FaceInferred -= OnQuickEndFaceInferred;
+
+ // 恢复选择工具
+ try { NavisApplication.MainDocument.Tool.Value = Tool.Select; } catch { }
+
+ if (!result.IsValid || result.ModelItem != _assemblyTerminalObject)
+ {
+ CleanupAssemblyEndFaceSelection(clearVisuals: false);
+ UpdateMainStatus("取面失败: 请确认点击的是终点箱体的端面。");
+ return;
+ }
+
+ try
+ {
+ var endFaceResult = AssemblyEndFaceAnalyzer.Analyze(
+ _assemblyTerminalObject,
+ result.HitPoint,
+ result.Normal);
+
+ if (!endFaceResult.IsReliable)
+ {
+ CleanupAssemblyEndFaceSelection(clearVisuals: false);
+ UpdateMainStatus($"端面分析失败: {endFaceResult.DiagnosticMessage}");
+ return;
+ }
+
+ Point3D centerPoint = AssemblyEndFaceAnalyzer.ToPoint3D(endFaceResult.Center);
+ Point3D sphereCenterPoint = new Point3D(
+ AssemblySphereCenterX, AssemblySphereCenterY, AssemblySphereCenterZ);
+ Vector3 orientedNormal = AssemblyEndFaceAnalyzer.OrientNormalTowardTarget(
+ endFaceResult.Normal,
+ new Vector3((float)centerPoint.X, (float)centerPoint.Y, (float)centerPoint.Z),
+ new Vector3((float)sphereCenterPoint.X, (float)sphereCenterPoint.Y, (float)sphereCenterPoint.Z));
+
+ _hasAssemblyEndFaceAnalysis = true;
+ _assemblyEndFaceCenterPoint = centerPoint;
+ _assemblyEndFaceNormal = orientedNormal;
+ RenderAssemblyEndFaceCenter(centerPoint);
+ RenderAssemblyEndFaceNormal(centerPoint, orientedNormal);
+ RefreshAssemblyTerminalObjectInfo();
+ RefreshAssemblyReferenceRodIfNeeded();
+ UpdateMainStatus($"端面分析完成:中心=({centerPoint.X:F2}, {centerPoint.Y:F2}, {centerPoint.Z:F2}),三角形={endFaceResult.CandidateTriangleCount}");
+ LogManager.Info(
+ $"[直线装配] 快速取端面完成: 中心=({centerPoint.X:F3}, {centerPoint.Y:F3}, {centerPoint.Z:F3}), " +
+ $"法向=({orientedNormal.X:F4}, {orientedNormal.Y:F4}, {orientedNormal.Z:F4}), " +
+ $"三角形={endFaceResult.CandidateTriangleCount}");
+ }
+ catch (Exception ex)
+ {
+ LogManager.Error($"[直线装配] 端面分析失败: {ex.Message}", ex);
+ UpdateMainStatus($"端面分析失败: {ex.Message}");
+ }
+ finally
+ {
+ _isSelectingAssemblyEndFacePoints = false;
+ NotifyRailAssemblyCommandStateChanged();
+ }
+ }
+
private void BeginAssemblyEndFaceSelection(RailAssemblyWorkflowMode workflowMode)
{
CleanupAssemblyReferenceSelection();
diff --git a/src/UI/WPF/Views/PathEditingView.xaml b/src/UI/WPF/Views/PathEditingView.xaml
index 9960293..8885761 100644
--- a/src/UI/WPF/Views/PathEditingView.xaml
+++ b/src/UI/WPF/Views/PathEditingView.xaml
@@ -538,6 +538,11 @@ NavisworksTransport 路径编辑页签视图 - 采用与动画控制和分层管
Command="{Binding AnalyzeAssemblyTerminalFaceForCreateCommand}"
Style="{StaticResource SecondaryButtonStyle}"
IsEnabled="{Binding CanAnalyzeAssemblyTerminalFaceForCreate}"/>
+