修复rail路径的编辑状态问题

This commit is contained in:
tian 2026-03-30 22:13:16 +08:00
parent 440c41d1d9
commit 1d71d36e5f
4 changed files with 173 additions and 17 deletions

View File

@ -133,6 +133,50 @@
禁止再使用“本地坐标系”这种含糊说法。
### 4.1.2 坐标命名规则
以后凡是变量名、字段名、日志名里出现 `X/Y/Z`、正负轴、forward/up/side 等方向语义,必须在名字上直接带出所属坐标系,避免只看名字时无法判断语义层。
允许的前缀示例:
- `Host...`
- 宿主坐标系
- `Canonical...`
- 内部坐标系
- `Asset...`
- 资产坐标系
- `Local...`
- 仅当这里明确表示“对象自身局部轴”时才允许使用
正负轴命名示例:
- `LocalPositiveX`
- `LocalNegativeY`
- `HostPositiveZ`
- `CanonicalPositiveX`
- `AssetPositiveY`
方向/向量命名示例:
- `hostForward`
- `hostUp`
- `canonicalForward`
- `assetUp`
- `localXAxis`
- `localZAxis`
禁止继续使用这类脱离坐标系语义的名字:
- `PositiveX`
- `NegativeZ`
- `xAxis`
- `upAxis`
- `forwardAxis`
除非变量名里已经明确出现了所属坐标系前缀。
目标是做到:只看名字,就能知道这个方向、轴、向量到底属于宿主、内部、资产,还是对象自身局部轴。
### 4.1.1 Quaternion / Rotation3D 固定定义
这是项目级硬约束,不允许在任何修复中重新猜测、重新验证或临时改口:

View File

@ -11,7 +11,6 @@ using System.IO;
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;
@ -21,7 +20,6 @@ using NavisworksTransport.UI.WPF.Models;
using NavisworksTransport.Utils;
using NavisworksTransport.Utils.CoordinateSystem;
using NavisworksTransport.Utils.GeometryAnalysis;
using NavisworksTransport;
namespace NavisworksTransport.UI.WPF.ViewModels
{
@ -145,6 +143,8 @@ namespace NavisworksTransport.UI.WPF.ViewModels
private bool _isEditingSelectedRailStartPoint;
private bool _isSelectingAssemblyEndFacePoints;
private bool _isSelectingAssemblyInstallationPoint;
private bool _isEditingSelectedRailInstallationPoint;
private bool _isEditingSelectedRail;
private bool _hasAssemblyEndFaceAnalysis;
private bool _hasAssemblyInstallationReference;
private ModelItem _assemblyTerminalObject;
@ -218,6 +218,10 @@ namespace NavisworksTransport.UI.WPF.ViewModels
ClearAssemblyReferenceLineVisuals();
ClearAssemblyInstallationReferenceVisuals();
// 重置 Rail 编辑状态
_isEditingSelectedRail = false;
OnPropertyChanged(nameof(AssemblyInstallationPointButtonText));
// 🔧 修复同步PathPlanningManager的CurrentRoute
if (_pathPlanningManager != null && value != null)
{
@ -1066,6 +1070,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
public ICommand ExportPathCommand { get; private set; }
public ICommand SaveAsPathCommand { get; private set; }
public ICommand CaptureAssemblyTerminalObjectCommand { get; private set; }
public ICommand ReCaptureAssemblyTerminalObjectCommand { get; private set; }
public ICommand GenerateAssemblyReferenceRodCommand { get; private set; }
public ICommand SelectAssemblyStartPointCommand { get; private set; }
public ICommand RepositionRailStartPointCommand { get; private set; }
@ -1291,6 +1296,12 @@ namespace NavisworksTransport.UI.WPF.ViewModels
private bool HasSelectedRailInstallationReference()
{
// 只有在点击"重选箱体"进入编辑状态后才显示"重选安装点"
if (!_isEditingSelectedRail)
{
return false;
}
var coreRoute = GetSelectedCoreRoute();
return coreRoute != null &&
coreRoute.PathType == PathType.Rail &&
@ -1376,11 +1387,30 @@ namespace NavisworksTransport.UI.WPF.ViewModels
return;
}
var coreRoute = GetSelectedCoreRoute();
if (!TryBuildRailRouteReferenceLine(coreRoute, out AssemblyReferenceLine referenceLine))
AssemblyReferenceLine referenceLine;
if (_isEditingSelectedRail)
{
ClearAssemblyReferenceLineVisuals();
return;
// 编辑状态:使用默认杆长度构建参考线,方便选择更远的起点
try
{
referenceLine = BuildAssemblyReferenceLine();
}
catch
{
ClearAssemblyReferenceLineVisuals();
return;
}
}
else
{
// 非编辑状态:使用路径实际长度
var coreRoute = GetSelectedCoreRoute();
if (!TryBuildRailRouteReferenceLine(coreRoute, out referenceLine))
{
ClearAssemblyReferenceLineVisuals();
return;
}
}
AssemblyReferencePathManager.Instance.CreateOrUpdateReferenceRod(
@ -1422,11 +1452,31 @@ namespace NavisworksTransport.UI.WPF.ViewModels
throw new InvalidOperationException("当前 Rail 路径没有可更新的终点。");
}
// 获取当前起点索引
int startPointIndex = GetRailRouteStartPointIndex(route);
if (startPointIndex < 0)
{
throw new InvalidOperationException("当前 Rail 路径没有可更新的起点。");
}
// 计算原路径长度(起点到终点的距离)
Point3D currentStartPoint = route.Points[startPointIndex].Position;
Point3D currentEndPoint = route.Points[installationPointIndex].Position;
double pathLength = GeometryHelper.CalculatePointDistance(currentStartPoint, currentEndPoint);
// 更新终点(安装点)
if (!_pathPlanningManager.UpdatePathPointWithConstraints(route, installationPointIndex, _assemblyInstallationAnchorPoint))
{
throw new InvalidOperationException("更新 Rail 路径安装点失败。");
}
// 根据新终点和原路径长度重新计算起点位置
Point3D newStartPoint = CalculateRailStartPointFromEndPoint(_assemblyInstallationAnchorPoint, pathLength);
if (!_pathPlanningManager.UpdatePathPointWithConstraints(route, startPointIndex, newStartPoint))
{
throw new InvalidOperationException("更新 Rail 路径起点失败。");
}
route.RailPreferredNormal = new Point3D(
_assemblyInstallationPlaneNormal.X,
_assemblyInstallationPlaneNormal.Y,
@ -1449,7 +1499,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
RefreshSelectedRailReferenceLineVisuals();
}
LogManager.Info($"[Rail构型] {route.Name}: {logMessage}");
LogManager.Info($"[Rail构型] {route.Name}: {logMessage},起点已同步更新为 ({newStartPoint.X:F3}, {newStartPoint.Y:F3}, {newStartPoint.Z:F3})");
}
private void RefreshSelectedRailInstallationReferenceVisuals()
@ -1622,6 +1672,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
ExportPathCommand = new RelayCommand(async () => await ExecuteExportPathAsync(), () => CanExecuteExportPath);
SaveAsPathCommand = new RelayCommand(async () => await ExecuteSaveAsPathAsync(), () => CanExecuteSaveAsPath);
CaptureAssemblyTerminalObjectCommand = new RelayCommand(async () => await ExecuteCaptureAssemblyTerminalObjectAsync());
ReCaptureAssemblyTerminalObjectCommand = new RelayCommand(async () => await ExecuteReCaptureAssemblyTerminalObjectAsync());
GenerateAssemblyReferenceRodCommand = new RelayCommand(async () => await ExecuteGenerateAssemblyReferenceRodAsync(), () => CanGenerateAssemblyReferenceRod);
SelectAssemblyStartPointCommand = new RelayCommand(async () => await ExecuteSelectAssemblyStartPointAsync(), () => CanSelectAssemblyStartPoint);
RepositionRailStartPointCommand = new RelayCommand(async () => await ExecuteRepositionRailStartPointAsync(), () => CanRepositionRailStartPoint);
@ -1656,6 +1707,9 @@ namespace NavisworksTransport.UI.WPF.ViewModels
throw new InvalidOperationException("当前选择对象无效,请重新选择终点箱体");
}
// 注意:不在这里设置 _isEditingSelectedRail
// 新建路径时保持 false只有点击"重选箱体"时才设置为 true
_assemblyTerminalObject = selectedItem;
_assemblyStartPoint = Point3D.Origin;
HasAssemblyTerminalObject = true;
@ -1672,12 +1726,24 @@ namespace NavisworksTransport.UI.WPF.ViewModels
OnPropertyChanged(nameof(CanRepositionRailStartPoint));
OnPropertyChanged(nameof(CanSelectAssemblyInstallationPoint));
OnPropertyChanged(nameof(CanAnalyzeAssemblyTerminalFace));
RefreshSelectedRailReferenceLineVisuals($"已捕获终点箱体: {AssemblyTerminalObjectName}");
OnPropertyChanged(nameof(AssemblyInstallationPointButtonText));
// 新建路径时隐藏其他路径的辅助线
ClearAssemblyReferenceLineVisuals();
UpdateMainStatus($"已捕获终点箱体: {AssemblyTerminalObjectName}");
LogManager.Info($"[直线装配] 已捕获终点箱体: {AssemblyTerminalObjectName}");
}, "捕获终点箱体");
}
private async Task ExecuteReCaptureAssemblyTerminalObjectAsync()
{
// 先进入编辑状态,再执行捕获
_isEditingSelectedRail = true;
OnPropertyChanged(nameof(AssemblyInstallationPointButtonText));
await ExecuteCaptureAssemblyTerminalObjectAsync();
}
private void ClearNonGridPathVisualizations(string context)
{
if (PathPointRenderPlugin.Instance == null)
@ -1915,6 +1981,11 @@ namespace NavisworksTransport.UI.WPF.ViewModels
_pathPlanningManager.DisableMouseHandling();
_isSelectingAssemblyInstallationPoint = true;
// 判断是编辑现有路径还是创建新路径
var selectedRailRoute = GetSelectedCoreRoute();
_isEditingSelectedRailInstallationPoint = selectedRailRoute != null && selectedRailRoute.PathType == PathType.Rail;
OnPropertyChanged(nameof(CanAnalyzeAssemblyTerminalFace));
OnPropertyChanged(nameof(CanSelectAssemblyStartPoint));
OnPropertyChanged(nameof(CanRepositionRailStartPoint));
@ -2048,12 +2119,22 @@ namespace NavisworksTransport.UI.WPF.ViewModels
BuildAndRenderAssemblyInstallationReference(
_assemblyInstallationSeedPoints[0],
_assemblyInstallationSeedPoints[1]);
var selectedRailRoute = GetSelectedCoreRoute();
if (selectedRailRoute != null && selectedRailRoute.PathType == PathType.Rail)
if (_isEditingSelectedRailInstallationPoint)
{
PersistAssemblyInstallationReferenceToRailRoute(
selectedRailRoute,
"已重选安装点并同步更新 Rail 路径安装参数");
// 编辑现有路径:更新安装点并同步起点
var selectedRailRoute = GetSelectedCoreRoute();
if (selectedRailRoute != null && selectedRailRoute.PathType == PathType.Rail)
{
PersistAssemblyInstallationReferenceToRailRoute(
selectedRailRoute,
"已重选安装点并同步更新 Rail 路径安装参数");
}
}
else
{
// 创建新路径:生成参考线,等待用户选择起点
LogManager.Info("[直线装配] 安装点已确定,请继续选择起点以生成新路径");
}
CleanupAssemblyInstallationSelection();
}, "处理安装点拾取");
@ -2224,6 +2305,36 @@ namespace NavisworksTransport.UI.WPF.ViewModels
return adapter.FromCanonicalPoint(canonicalAnchorPoint);
}
/// <summary>
/// 根据 Rail 路径终点和路径长度计算起点位置。
/// 起点位于从终点沿光轴方向(远离球心方向)延伸路径长度的位置。
/// </summary>
private Point3D CalculateRailStartPointFromEndPoint(Point3D endPoint, double pathLength)
{
HostCoordinateAdapter adapter = CoordinateSystemManager.Instance.CreateHostAdapter();
ProjectReferenceFrame projectFrame = CreateAssemblyProjectReferenceFrame(adapter);
Point3D opticalAxisReferencePoint = GetAssemblyOpticalAxisReferencePoint();
Point3D canonicalEndPoint = adapter.ToCanonicalPoint(endPoint);
Point3D canonicalOpticalAxisRef = adapter.ToCanonicalPoint(opticalAxisReferencePoint);
// 计算从球心到光轴参考点的方向(作为参考线方向)
Vector3D direction = new Vector3D(
canonicalOpticalAxisRef.X - projectFrame.SphereCenterInCanonical.X,
canonicalOpticalAxisRef.Y - projectFrame.SphereCenterInCanonical.Y,
canonicalOpticalAxisRef.Z - projectFrame.SphereCenterInCanonical.Z);
direction = direction.Normalize();
// 起点 = 终点 + 方向 * 路径长度
Point3D canonicalStartPoint = new Point3D(
canonicalEndPoint.X + direction.X * pathLength,
canonicalEndPoint.Y + direction.Y * pathLength,
canonicalEndPoint.Z + direction.Z * pathLength);
return adapter.FromCanonicalPoint(canonicalStartPoint);
}
private void UpdateAssemblyInstallationAnchorFromVerticalOffset()
{
if (!_hasAssemblyInstallationReference ||
@ -2997,6 +3108,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels
{
PathClickToolPlugin.MouseClicked -= OnAssemblyInstallationMouseClicked;
_isSelectingAssemblyInstallationPoint = false;
_isEditingSelectedRailInstallationPoint = false;
_pathPlanningManager?.EnableMouseHandling();
_pathPlanningManager?.StopClickTool();
ClearAssemblyInstallationReferenceVisuals();

View File

@ -560,10 +560,10 @@ NavisworksTransport 路径编辑页签视图 - 采用与动画控制和分层管
Orientation="Horizontal"
VerticalAlignment="Center"
ItemHeight="28">
<Button Content="捕获箱体"
<Button Content="重选箱体"
Padding="10,2"
Margin="0,0,10,0"
Command="{Binding CaptureAssemblyTerminalObjectCommand}"
Command="{Binding ReCaptureAssemblyTerminalObjectCommand}"
Style="{StaticResource SecondaryButtonStyle}"/>
<TextBox Width="150"
Margin="0,0,10,0"

View File

@ -1052,7 +1052,7 @@ namespace NavisworksTransport.Utils
return;
}
LogManager.Info(
LogManager.Debug(
$"{prefix} GeometryType={geometry.GetType().FullName}, " +
$"FragmentCount={geometry.FragmentCount}, " +
$"BoundsCenter=({geometry.BoundingBox.Center.X:F3},{geometry.BoundingBox.Center.Y:F3},{geometry.BoundingBox.Center.Z:F3})");
@ -1080,7 +1080,7 @@ namespace NavisworksTransport.Utils
{
var linear = transform.Linear;
var components = transform.Factor();
LogManager.Info(
LogManager.Debug(
$"{prefix}: " +
$"X=({linear.Get(0, 0):F4},{linear.Get(1, 0):F4},{linear.Get(2, 0):F4}), " +
$"Y=({linear.Get(0, 1):F4},{linear.Get(1, 1):F4},{linear.Get(2, 1):F4}), " +