refactor: replace 3-click end face detection with single-click FaceInferTool

- Remove '找端面' button and all 3-click logic
- Keep single-click '取端面' button only
- Remove: AnalyzeCurrentAssemblyEndFace, BeginAssemblyEndFaceSelection,
  OnAssemblyEndFaceMouseClicked, ExecuteAnalyzeAssemblyTerminalFaceAsync
- Retain CleanupAssemblyEndFaceSelection (shared with quick pick)
This commit is contained in:
tian 2026-06-09 02:04:54 +08:00
parent 01195434b7
commit 0fe7179494
2 changed files with 5 additions and 165 deletions

View File

@ -1410,8 +1410,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels
public ICommand SelectAssemblyInstallationPointForEditCommand { get; private set; }
public ICommand ClearAssemblyReferenceRodCommand { get; private set; }
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; }
@ -1479,19 +1477,11 @@ namespace NavisworksTransport.UI.WPF.ViewModels
!_isSelectingAssemblyStartPoint &&
!_isSelectingAssemblyEndFacePoints &&
!_isSelectingAssemblyInstallationPoint;
public bool CanAnalyzeAssemblyTerminalFaceForCreate => HasAssemblyTerminalObject &&
_pathPlanningManager != null &&
!IsSelectingAssemblyStartPoint &&
!IsSelectingAssemblyEndFacePoints &&
!_isSelectingAssemblyInstallationPoint;
public bool CanQuickAnalyzeAssemblyEndFace => CanAnalyzeAssemblyTerminalFaceForCreate;
public bool CanAnalyzeAssemblyTerminalFaceForEdit => HasAssemblyTerminalObject &&
IsRailRouteSelected &&
SelectedPathRoute != null &&
_pathPlanningManager != null &&
!IsSelectingAssemblyStartPoint &&
!IsSelectingAssemblyEndFacePoints &&
!_isSelectingAssemblyInstallationPoint;
public bool CanQuickAnalyzeAssemblyEndFace => HasAssemblyTerminalObject &&
_pathPlanningManager != null &&
!IsSelectingAssemblyStartPoint &&
!IsSelectingAssemblyEndFacePoints &&
!_isSelectingAssemblyInstallationPoint;
public string CreateAssemblyInstallationPointButtonText => _hasAssemblyInstallationReference && !IsRailEditingWorkflowActive
? "重选安装点"
@ -1693,9 +1683,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
private void NotifyRailAssemblyCommandStateChanged()
{
OnPropertyChanged(nameof(CanAnalyzeAssemblyTerminalFaceForCreate));
OnPropertyChanged(nameof(CanQuickAnalyzeAssemblyEndFace));
OnPropertyChanged(nameof(CanAnalyzeAssemblyTerminalFaceForEdit));
OnPropertyChanged(nameof(CanSelectAssemblyStartPointForCreate));
OnPropertyChanged(nameof(CanRepositionRailStartPoint));
OnPropertyChanged(nameof(CanSelectAssemblyInstallationPointForCreate));
@ -2075,8 +2063,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels
SelectAssemblyInstallationPointForEditCommand = new RelayCommand(async () => await ExecuteSelectAssemblyInstallationPointAsync(RailAssemblyWorkflowMode.EditSelectedRail), () => CanSelectAssemblyInstallationPointForEdit);
ClearAssemblyReferenceRodCommand = new RelayCommand(() => ExecuteClearAssemblyReferenceRod());
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));
@ -2268,29 +2254,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels
}
}
private async Task ExecuteAnalyzeAssemblyTerminalFaceAsync(RailAssemblyWorkflowMode workflowMode)
{
await SafeExecuteAsync(() =>
{
if (_pathPlanningManager == null)
{
throw new InvalidOperationException("路径规划管理器未初始化,无法分析端面。");
}
if (_assemblyTerminalObject == null || !ModelItemAnalysisHelper.IsModelItemValid(_assemblyTerminalObject))
{
throw new InvalidOperationException("终点箱体未设置或已失效,请先捕获终点箱体。");
}
PrepareRailAssemblyWorkflowForMode(
workflowMode,
editActionDescription: "请先选中一条需要编辑安装点的 Rail 路径。",
syncMountModeFromRoute: true);
BeginAssemblyEndFaceSelection(workflowMode);
}, "分析终端端面");
}
private async Task ExecuteSelectAssemblyInstallationPointAsync(RailAssemblyWorkflowMode workflowMode)
{
await SafeExecuteAsync(() =>
@ -2345,47 +2308,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels
}
}
private async void OnAssemblyEndFaceMouseClicked(object sender, PickItemResult pickResult)
{
try
{
if (!_isSelectingAssemblyEndFacePoints || pickResult == null)
{
return;
}
await SafeExecuteAsync(() =>
{
if (!IsPickOnAssemblyTerminalObject(pickResult))
{
UpdateMainStatus("请点击当前终点箱体的同一个端面,不要点到其他对象。");
return;
}
_assemblyEndFaceSeedPoints.Add(pickResult.Point);
RenderAssemblyEndFaceSeedPoints();
int pickedCount = _assemblyEndFaceSeedPoints.Count;
LogManager.Info($"[直线装配] 已记录端面种子点 {pickedCount}: ({pickResult.Point.X:F3}, {pickResult.Point.Y:F3}, {pickResult.Point.Z:F3})");
if (pickedCount < 3)
{
UpdateMainStatus($"已记录端面点 {pickedCount}/3,请继续在同一端面平面上点击。");
return;
}
AnalyzeCurrentAssemblyEndFace();
CleanupAssemblyEndFaceSelection(clearVisuals: false);
}, "处理端面三点拾取");
}
catch (Exception ex)
{
LogManager.Error($"[直线装配] 端面三点分析失败: {ex.Message}", ex);
UpdateMainStatus($"端面三点分析失败: {ex.Message}");
CleanupAssemblyEndFaceSelection(clearVisuals: false);
}
}
private async void OnAssemblyInstallationMouseClicked(object sender, PickItemResult pickResult)
{
try
@ -2594,34 +2516,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels
}
}
private void BeginAssemblyEndFaceSelection(RailAssemblyWorkflowMode workflowMode)
{
CleanupAssemblyReferenceSelection();
CleanupAssemblyEndFaceSelection(clearVisuals: false);
CleanupAssemblyInstallationSelection();
ClearAssemblyEndFaceAnalysisVisuals();
ResetAssemblyEndFaceAnalysisState();
ClearAssemblyInstallationReferenceVisuals();
ResetAssemblyInstallationReferenceState();
_assemblyEndFaceSeedPoints.Clear();
_pathPlanningManager.DisableMouseHandling();
_isSelectingAssemblyEndFacePoints = true;
NotifyRailAssemblyCommandStateChanged();
PathClickToolPlugin.MouseClicked -= OnAssemblyEndFaceMouseClicked;
PathClickToolPlugin.MouseClicked += OnAssemblyEndFaceMouseClicked;
if (!ForceReinitializeToolPlugin(subscribeToEvents: false))
{
CleanupAssemblyEndFaceSelection(clearVisuals: false);
throw new InvalidOperationException("ToolPlugin 初始化失败,请重试。");
}
UpdateMainStatus("请在同一个端面平面上连续点击 3 个点,系统将分析端面中心。");
LogManager.Info($"[直线装配] 已进入端面三点分析模式,模式={GetRailAssemblyWorkflowLabel(workflowMode)}");
}
private void BeginAssemblyInstallationSelection()
{
CleanupAssemblyReferenceSelection();
@ -3646,7 +3540,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels
{
try
{
PathClickToolPlugin.MouseClicked -= OnAssemblyEndFaceMouseClicked;
_isSelectingAssemblyEndFacePoints = false;
_pathPlanningManager?.EnableMouseHandling();
_pathPlanningManager?.StopClickTool();
@ -3679,55 +3572,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels
return pickResult.ModelItem.AncestorsAndSelf.Any(ancestor => ModelItemAnalysisHelper.ModelItemEquals(ancestor, _assemblyTerminalObject));
}
private void AnalyzeCurrentAssemblyEndFace()
{
if (_assemblyEndFaceSeedPoints.Count != 3)
{
throw new InvalidOperationException("端面分析需要恰好 3 个种子点。");
}
var triangles = GeometryHelper.ExtractTriangles(new[] { _assemblyTerminalObject })
.Select(triangle => new AnalysisTriangle3(
new Vector3((float)triangle.Point1.X, (float)triangle.Point1.Y, (float)triangle.Point1.Z),
new Vector3((float)triangle.Point2.X, (float)triangle.Point2.Y, (float)triangle.Point2.Z),
new Vector3((float)triangle.Point3.X, (float)triangle.Point3.Y, (float)triangle.Point3.Z)))
.ToList();
EndFaceAnalysisResult result = AssemblyEndFaceAnalyzer.Analyze(
triangles,
new Vector3((float)_assemblyEndFaceSeedPoints[0].X, (float)_assemblyEndFaceSeedPoints[0].Y, (float)_assemblyEndFaceSeedPoints[0].Z),
new Vector3((float)_assemblyEndFaceSeedPoints[1].X, (float)_assemblyEndFaceSeedPoints[1].Y, (float)_assemblyEndFaceSeedPoints[1].Z),
new Vector3((float)_assemblyEndFaceSeedPoints[2].X, (float)_assemblyEndFaceSeedPoints[2].Y, (float)_assemblyEndFaceSeedPoints[2].Z));
if (!result.IsReliable)
{
throw new InvalidOperationException(result.DiagnosticMessage);
}
Point3D centerPoint = AssemblyEndFaceAnalyzer.ToPoint3D(result.Center);
Point3D sphereCenterPoint = new Point3D(
AssemblySphereCenterX,
AssemblySphereCenterY,
AssemblySphereCenterZ);
Vector3 orientedNormal = AssemblyEndFaceAnalyzer.OrientNormalTowardTarget(
result.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;
RenderAssemblyEndFaceSeedPoints();
RenderAssemblyEndFaceCenter(centerPoint);
RenderAssemblyEndFaceNormal(centerPoint, orientedNormal);
RefreshAssemblyTerminalObjectInfo();
RefreshAssemblyReferenceRodIfNeeded();
UpdateMainStatus($"端面分析完成:中心=({centerPoint.X:F2}, {centerPoint.Y:F2}, {centerPoint.Z:F2}),候选三角形={result.CandidateTriangleCount}");
LogManager.Info(
$"[直线装配] 端面分析完成: 中心=({centerPoint.X:F3}, {centerPoint.Y:F3}, {centerPoint.Z:F3}), " +
$"法向=({orientedNormal.X:F4}, {orientedNormal.Y:F4}, {orientedNormal.Z:F4}), " +
$"三角形={result.CandidateTriangleCount}, 顶点={result.CandidateVertexCount}, 偏差={result.MaxPlaneDeviation:F6}");
}
private async Task ExecuteNewPathAsync()
{
await SafeExecuteAsync(() =>

View File

@ -534,10 +534,6 @@ NavisworksTransport 路径编辑页签视图 - 采用与动画控制和分层管
<Button Content="捕获箱体"
Command="{Binding CaptureAssemblyTerminalObjectForCreateCommand}"
Style="{StaticResource SecondaryButtonStyle}"/>
<Button Content="找端面"
Command="{Binding AnalyzeAssemblyTerminalFaceForCreateCommand}"
Style="{StaticResource SecondaryButtonStyle}"
IsEnabled="{Binding CanAnalyzeAssemblyTerminalFaceForCreate}"/>
<Button Content="取端面"
Command="{Binding QuickAnalyzeAssemblyEndFaceCommand}"
Style="{StaticResource SecondaryButtonStyle}"