From 2e0b26e032e6b305751df82af4c104c6620c0bd4 Mon Sep 17 00:00:00 2001 From: tian <11429339@qq.com> Date: Wed, 1 Apr 2026 10:47:34 +0800 Subject: [PATCH] Refine rail assembly workflow and viewpoint strategies --- AGENTS.md | 50 ++ NavisworksTransport.UnitTests.csproj | 2 + TransportPlugin.csproj | 1 + .../RailAssemblyWorkflowContextTests.cs | 118 +++ .../CoordinateSystem/ViewpointHelperTests.cs | 80 ++ doc/working/current-engineering-state.md | 91 +- .../ViewModels/AnimationControlViewModel.cs | 4 +- .../WPF/ViewModels/ModelSettingsViewModel.cs | 4 +- src/UI/WPF/ViewModels/PathEditingViewModel.cs | 788 +++++++++++------- .../ViewModels/RailAssemblyWorkflowContext.cs | 154 ++++ src/UI/WPF/Views/PathEditingView.xaml | 4 - src/Utils/CollisionSceneHelper.cs | 2 +- src/Utils/ViewpointHelper.cs | 276 ++++++ 13 files changed, 1243 insertions(+), 331 deletions(-) create mode 100644 UnitTests/CoordinateSystem/RailAssemblyWorkflowContextTests.cs create mode 100644 UnitTests/CoordinateSystem/ViewpointHelperTests.cs create mode 100644 src/UI/WPF/ViewModels/RailAssemblyWorkflowContext.cs diff --git a/AGENTS.md b/AGENTS.md index 0bc6113..8851250 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -177,6 +177,56 @@ 目标是做到:只看名字,就能知道这个方向、轴、向量到底属于宿主、内部、资产,还是对象自身局部轴。 +### 4.1.3 对象局部轴业务映射 + +以后关于 `Local...`、前进轴、up 轴、side 轴,统一优先使用这个说法: + +- **对象局部轴业务映射** + - 它不是第四套全局坐标系 + - 也不是几何天然自带的“真理” + - 它表示:在当前业务链路里,我们准备把对象自身哪根局部轴解释成: + - `forward` + - `up` + - `side` + +这个概念的边界必须非常明确: + +- 它是**业务解释层** + - 不是宿主坐标系 + - 不是内部 `Canonical Space` + - 不是插件资源资产坐标系 +- 它不能脱离上下文单独存在 + - `up` 往往要结合宿主 `up` 语义来解释 + - `forward` 往往取决于: + - fragment 代表姿态解释 + - 资源默认轴约定 + - 用户选择 + - 当前路径类型 + +为什么必须保留这层概念: + +- 路径姿态求解必须回答: + - 对象哪根局部轴去对齐路径 `forward` + - 对象哪根局部轴去对齐目标 `up` +- 如果没有这层映射,下面这些都无法稳定定义: + - `Ground / Hoisting / Rail` 起点姿态 + - 逐帧姿态 + - `Rail` 角度修正 + - 通行空间尺寸投影 + - 终点原始姿态保持 + - `Rail` 平移模式的终点原位搬运 + +当前项目里的硬约束: + +- 不要把“对象局部轴业务映射”写成“对象自身天然就有 forward/up 定义” +- 对真实物体: + - 不能简单把 `ModelItem.Transform` 当成可靠的局部轴真值 + - 应优先通过 fragment 代表姿态 + `Fragment默认Up` 去解释 +- 对虚拟物体: + - 对象局部轴业务映射通常来自明确的资产轴约定 +- 如果只是讨论对象自身局部轴语义,允许继续使用 `Local...` 命名 + - 但文档、日志、设计讨论里优先说“对象局部轴业务映射” + ### 4.1.1 Quaternion / Rotation3D 固定定义 这是项目级硬约束,不允许在任何修复中重新猜测、重新验证或临时改口: diff --git a/NavisworksTransport.UnitTests.csproj b/NavisworksTransport.UnitTests.csproj index 4fefe8e..f26da39 100644 --- a/NavisworksTransport.UnitTests.csproj +++ b/NavisworksTransport.UnitTests.csproj @@ -76,6 +76,8 @@ + + diff --git a/TransportPlugin.csproj b/TransportPlugin.csproj index bc517ad..3cd6540 100644 --- a/TransportPlugin.csproj +++ b/TransportPlugin.csproj @@ -284,6 +284,7 @@ + diff --git a/UnitTests/CoordinateSystem/RailAssemblyWorkflowContextTests.cs b/UnitTests/CoordinateSystem/RailAssemblyWorkflowContextTests.cs new file mode 100644 index 0000000..aeb2308 --- /dev/null +++ b/UnitTests/CoordinateSystem/RailAssemblyWorkflowContextTests.cs @@ -0,0 +1,118 @@ +using Autodesk.Navisworks.Api; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using NavisworksTransport.UI.WPF.ViewModels; +using System.Numerics; + +namespace NavisworksTransport.UnitTests.CoordinateSystem +{ + [TestClass] + public class RailAssemblyWorkflowContextTests + { + [TestMethod] + public void ResetEndFaceAnalysis_ClearsAnalysisStateAndSeedPoints() + { + var context = CreateContext(); + context.HasEndFaceAnalysis = true; + context.EndFaceCenterPoint = new Point3D(1.0, 2.0, 3.0); + context.EndFaceNormal = new Vector3(1f, 0f, 0f); + context.EndFaceSeedPoints.Add(new Point3D(4.0, 5.0, 6.0)); + + context.ResetEndFaceAnalysis(); + + Assert.IsFalse(context.HasEndFaceAnalysis); + Assert.IsNull(context.EndFaceCenterPoint); + Assert.AreEqual(default(Vector3), context.EndFaceNormal); + Assert.AreEqual(0, context.EndFaceSeedPoints.Count); + } + + [TestMethod] + public void ResetInstallationReference_RestoresDefaultOffsetAndClearsReferenceState() + { + var context = CreateContext(); + context.HasInstallationReference = true; + context.InstallationPickPoint = new Point3D(1.0, 2.0, 3.0); + context.InstallationBaseAnchorPoint = new Point3D(4.0, 5.0, 6.0); + context.InstallationAnchorPoint = new Point3D(7.0, 8.0, 9.0); + context.InstallationPlaneNormal = new Vector3(0f, 1f, 0f); + context.InstallationPlaneSpanDirection = new Vector3(1f, 0f, 0f); + context.InstallationOffsetDistanceInMeters = 2.5; + context.InstallationReferenceRouteId = "route-1"; + context.InstallationSeedPoints.Add(new Point3D(9.0, 8.0, 7.0)); + context.AnchorVerticalOffsetInMeters = 3.5; + + context.ResetInstallationReference(); + + Assert.IsFalse(context.HasInstallationReference); + Assert.IsNull(context.InstallationPickPoint); + Assert.IsNull(context.InstallationBaseAnchorPoint); + Assert.IsNull(context.InstallationAnchorPoint); + Assert.AreEqual(default(Vector3), context.InstallationPlaneNormal); + Assert.AreEqual(default(Vector3), context.InstallationPlaneSpanDirection); + Assert.AreEqual(0.0, context.InstallationOffsetDistanceInMeters, 1e-9); + Assert.IsNull(context.InstallationReferenceRouteId); + Assert.AreEqual(0, context.InstallationSeedPoints.Count); + Assert.AreEqual(0.25, context.AnchorVerticalOffsetInMeters, 1e-9); + } + + [TestMethod] + public void ResetSession_ClearsTransientStateButPreservesConfiguration() + { + var context = CreateContext(); + context.WorkflowMode = RailAssemblyWorkflowMode.EditSelectedRail; + context.TerminalObjectName = "箱体A"; + context.TerminalObjectInfo = "info"; + context.ReferenceRodLengthInMeters = 12.0; + context.ReferenceRodDiameterInMeters = 0.4; + context.SphereCenterX = 10.0; + context.SphereCenterY = 11.0; + context.SphereCenterZ = 12.0; + context.MountMode = RailMountMode.OverRail; + context.HasTerminalObject = true; + context.IsSelectingStartPoint = true; + context.IsSelectingEndFacePoints = true; + context.IsSelectingInstallationPoint = true; + context.StartPoint = new Point3D(1.0, 2.0, 3.0); + context.StartPointText = "(1,2,3)"; + context.HasEndFaceAnalysis = true; + context.EndFaceCenterPoint = new Point3D(4.0, 5.0, 6.0); + context.HasInstallationReference = true; + context.InstallationReferenceRouteId = "route-2"; + context.AnchorVerticalOffsetInMeters = 1.5; + context.EndFaceSeedPoints.Add(new Point3D(1.0, 0.0, 0.0)); + context.InstallationSeedPoints.Add(new Point3D(0.0, 1.0, 0.0)); + + context.ResetSession(); + + Assert.AreEqual(RailAssemblyWorkflowMode.None, context.WorkflowMode); + Assert.IsFalse(context.HasTerminalObject); + Assert.IsFalse(context.IsSelectingStartPoint); + Assert.IsFalse(context.IsSelectingEndFacePoints); + Assert.IsFalse(context.IsSelectingInstallationPoint); + Assert.IsNull(context.TerminalObject); + Assert.IsNotNull(context.StartPoint); + Assert.AreEqual("未选择", context.TerminalObjectName); + Assert.AreEqual("请选择终点处已安装箱体", context.TerminalObjectInfo); + Assert.AreEqual("未选择", context.StartPointText); + Assert.IsFalse(context.HasEndFaceAnalysis); + Assert.IsFalse(context.HasInstallationReference); + Assert.AreEqual(0.25, context.AnchorVerticalOffsetInMeters, 1e-9); + Assert.AreEqual(12.0, context.ReferenceRodLengthInMeters, 1e-9); + Assert.AreEqual(0.4, context.ReferenceRodDiameterInMeters, 1e-9); + Assert.AreEqual(10.0, context.SphereCenterX, 1e-9); + Assert.AreEqual(11.0, context.SphereCenterY, 1e-9); + Assert.AreEqual(12.0, context.SphereCenterZ, 1e-9); + Assert.AreEqual(RailMountMode.OverRail, context.MountMode); + } + + private static RailAssemblyWorkflowContext CreateContext() + { + return new RailAssemblyWorkflowContext( + defaultReferenceRodLengthInMeters: 20.0, + defaultReferenceRodDiameterInMeters: 0.3, + defaultAnchorVerticalOffsetInMeters: 0.25, + defaultSphereCenterX: 0.0, + defaultSphereCenterY: 0.0, + defaultSphereCenterZ: 0.0); + } + } +} diff --git a/UnitTests/CoordinateSystem/ViewpointHelperTests.cs b/UnitTests/CoordinateSystem/ViewpointHelperTests.cs new file mode 100644 index 0000000..6858379 --- /dev/null +++ b/UnitTests/CoordinateSystem/ViewpointHelperTests.cs @@ -0,0 +1,80 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using NavisworksTransport.Utils; +using System.Numerics; + +namespace NavisworksTransport.UnitTests.CoordinateSystem +{ + [TestClass] + public class ViewpointHelperTests + { + [TestMethod] + public void ResolvePathViewpointProfile_ShouldReturnExpectedDefaults() + { + var ground = ViewpointHelper.ResolvePathViewpointProfile(ViewpointHelper.ViewpointStrategy.PathGroundSelection); + var hoisting = ViewpointHelper.ResolvePathViewpointProfile(ViewpointHelper.ViewpointStrategy.PathHoistingSelection); + var rail = ViewpointHelper.ResolvePathViewpointProfile(ViewpointHelper.ViewpointStrategy.PathRailSelection); + + Assert.AreEqual(1.0, ground.DistanceScale, 1e-9); + Assert.AreEqual(12.0, ground.MinDistanceMeters, 1e-9); + + Assert.AreEqual(1.2, hoisting.DistanceScale, 1e-9); + Assert.AreEqual(8.0, hoisting.MinDistanceMeters, 1e-9); + Assert.AreEqual(22.0, hoisting.ElevationDegrees, 1e-9); + + Assert.AreEqual(0.9, rail.DistanceScale, 1e-9); + Assert.AreEqual(6.0, rail.MinDistanceMeters, 1e-9); + Assert.AreEqual(12.0, rail.ElevationDegrees, 1e-9); + } + + [TestMethod] + public void ResolveCameraOffsetDirection_Hoisting_ShouldLookFromBehindAndAbove() + { + Vector3 hostUp = Vector3.UnitZ; + Vector3 forward = Vector3.UnitX; + + Vector3 offset = ViewpointHelper.ResolveCameraOffsetDirection(PathType.Hoisting, hostUp, forward); + + Assert.IsTrue(offset.X < -0.8f); + Assert.IsTrue(offset.Z > 0.3f); + } + + [TestMethod] + public void ResolveCameraOffsetDirection_Rail_ShouldLookFromSideAndSlightlyAbove() + { + Vector3 hostUp = Vector3.UnitZ; + Vector3 forward = Vector3.UnitX; + + Vector3 offset = ViewpointHelper.ResolveCameraOffsetDirection(PathType.Rail, hostUp, forward); + + Assert.AreEqual(0.0f, offset.X, 1e-5f); + Assert.IsTrue(offset.Y > 0.9f); + Assert.IsTrue(offset.Z > 0.15f); + } + + [TestMethod] + public void ResolveHorizontalPathForward_ShouldFallbackWhenPathIsVertical() + { + Vector3 hostUp = Vector3.UnitZ; + Vector3 rawVertical = Vector3.UnitZ; + Vector3 fallback = Vector3.UnitY; + + Vector3 resolved = ViewpointHelper.ResolveHorizontalPathForward(rawVertical, hostUp, fallback); + + Assert.AreEqual(0.0f, resolved.Z, 1e-5f); + Assert.AreEqual(1.0f, resolved.Y, 1e-5f); + } + + [TestMethod] + public void ResolveFocusViewpointProfile_ShouldCentralizeNamedFocusStrategies() + { + var modelFocus = ViewpointHelper.ResolveFocusViewpointProfile(ViewpointHelper.ViewpointStrategy.ModelFocus); + var collision = ViewpointHelper.ResolveFocusViewpointProfile(ViewpointHelper.ViewpointStrategy.CollisionCloseUp); + + Assert.AreEqual(60.0, modelFocus.ViewAngleDegrees, 1e-9); + Assert.AreEqual(0.25, modelFocus.TargetViewRatio, 1e-9); + + Assert.AreEqual(60.0, collision.ViewAngleDegrees, 1e-9); + Assert.AreEqual(0.25, collision.TargetViewRatio, 1e-9); + } + } +} diff --git a/doc/working/current-engineering-state.md b/doc/working/current-engineering-state.md index 44e23ff..7869750 100644 --- a/doc/working/current-engineering-state.md +++ b/doc/working/current-engineering-state.md @@ -1,12 +1,18 @@ # 当前工程状态 -更新时间:2026-03-25 +更新时间:2026-04-01 ## 1. 当前稳定状态 - `Rail` 路径主链路已稳定: - `ZUp` 模型下,轨上/轨下路径的真实物体与虚拟物体起点、动画、终点贴合正确。 - `YUp` 模型下,终端安装仿真、`Rail` 姿态、真实物体与虚拟物体通行空间、起点与动画主链路已基本跑通。 + - `Rail` “调整角度”窗口中的“平移”模式当前已重新收稳: + - 以终点箱体当前原始位姿为真值; + - 记录终点原位相对路径终点参考点的固定残差; + - 把这份残差整体搬运到路径起点; + - 动画全程保持终点原始姿态; + - 动画结束时应精确回到终点箱体原位。 - 地面路径在 `YUp` 模型下: - 虚拟物体起点姿态、动画姿态、转弯姿态已恢复正常。 - 真实物体地面路径当前已恢复到可用状态: @@ -20,16 +26,24 @@ - 对象级前进轴统一按 `PositiveX` 解释; - 不再因为路径初始方向更偏 `Z` 就把对象前进轴自动切换成 `PositiveZ`。 - 当前已禁止地面/吊装路径偷偷退回旧 `yaw` 链路。 +- 吊装路径真实物体的角度调整链路已重新稳定: + - 起点“调整角度”后,预览、生成动画、播放前重置都复用同一份真实起点基姿态; + - 清除并重新选择物体时,旧角度修正必须被清空,不能继承上一次调整状态。 - 碰撞检测/恢复主链路已稳定: - `ClashDetective` 三维恢复不能再先 `ResetPermanentTransform`。 - 碰撞恢复、自动报告、自动截图已重新对齐到动画主链路。 - 虚拟物体资源问题已确认并修复: - 旧 `unit_cube.nwc` 局部几何中心不在原点,会导致虚拟物体中心偏差。 - 新 `unit_cube.nwc` 已替换为几何中心在原点的版本。 - - 旋转适配入口当前稳定分流: - - 虚拟物体继续走 `HostCoordinateAdapter` 的 `Legacy` 入口; - - 真实物体走 `Direct` 入口; - - 两者不能再强行共用同一条旋转转换链。 +- 旋转适配入口当前稳定分流: + - 虚拟物体继续走 `HostCoordinateAdapter` 的 `Legacy` 入口; + - 真实物体走 `Direct` 入口; + - 两者不能再强行共用同一条旋转转换链。 +- `Rail` 终端安装仿真创建/编辑区当前已完成第一轮工作流拆分: + - 新建 Rail 与编辑选中 Rail 不再共用同一套按钮命令入口; + - 新建区和编辑区有独立的 `找端面 / 选安装点 / 取起点` 可用条件; + - 两个区域都已有明确的“取消装配”退出入口; + - 上方“路径编辑 -> 结束”在 Rail 装配工作流活跃时,也必须能真正退出 Rail 装配流程。 ## 2. 当前坐标系架构 @@ -212,6 +226,19 @@ 2. 再验证修正后 `forward` 是否仍沿 rail 切向 3. 最后再看 Navisworks 应用层是否正确按三步增量姿态落位 +### 4.7.1 Rail 平移模式 + +- `Rail` 的“平移”不是重新按轨上/轨下求一套新的安装姿态。 +- 当前稳定语义: + - 终点箱体当前原始位姿是唯一真值; + - 先计算终点箱体相对“路径终点参考点”的固定残差; + - 再把这份残差搬运到路径起点; + - 动画全程保持这套终点原始姿态和固定残差。 +- 当前规则: + - 不能把“平移模式”误实现成重新按 `RailMountMode` 解目标 pose; + - 不能锁到“参考姿态”而丢掉终点箱体当前真实几何姿态; + - 终点保位误差如果异常,优先检查“残差是相对终点参考点采样,还是误相对起点参考点采样”。 + ### 4.8 Rail 真实物体必须复用统一姿态解释层 - `Rail` 不应再单独退回默认 `PositiveX / PositiveY` 轴约定。 @@ -243,6 +270,40 @@ - `AnimationControlViewModel.UpdatePassageSpaceVisualization()` 中,真实物体的 `Rail` 和 `Hoisting` 必须分开消费 - `Rail` 真实物体不能再复用 `Hoisting` 的法向/分段参数语义 +### 4.10 Rail 终端安装仿真工作流 + +- 当前真实问题已经确认: + - “创建 Rail 路径”区和“Rail 参数”编辑区之前共用同一套装配状态、命令入口和按钮可用条件; + - 导致新建流程会误吃编辑态校验,或在切换路径后残留旧的装配状态。 +- 当前第一轮稳定修复: + - 新建 Rail 与编辑 Rail 已拆成独立命令入口; + - “找端面”在新建 Rail 时不再要求先选中一条现有 Rail 路径; + - 新建区的“选安装点”不再受 `IsRailRouteSelected` 编辑态条件限制; + - 安装点拾取完成后,拾取点、安装点、安装参考面、中心线必须保留可视化,不能在收尾时被一并清掉; + - “隐藏辅助线”必须同时清理: + - 参考杆与锚点 + - 球心到光轴参考点基准线 + - 端面分析可视化 + - 安装点、安装中心线、安装参考面 + - 新建区和编辑区都必须有明确的“取消装配”; + - “路径编辑 -> 结束”在 Rail 装配流程活跃时,也必须能触发同一条取消/清理链路; + - 切换路径时必须自动清空旧的 Rail 装配上下文,不能把旧状态带到下一条路径。 +- 当前仍要记住: + - 这块只是“第一轮工作流拆分”,还不是彻底的数据结构重构; + - 如果后续继续扩 Rail 终端安装仿真,优先方向应是把“创建态上下文”和“编辑态上下文”进一步拆成独立 context,而不是继续在 ViewModel 顶层堆共享字段和布尔分支。 + +### 4.11 吊装路径角度调整 + +- 当前真实根因已经确认: + - 吊装真实物体在“起点调整角度后生成动画”时,如果基姿态缓存不跟着角度修正一起重建,就会出现: + - 动画里没有沿用调整后的角度; + - 甚至被错误立起或只抬高一点的异常现象。 +- 当前稳定规则: + - 吊装路径必须缓存“真实起点基姿态 + 起始 yaw”; + - 起点预览、动画生成、播放前重置,都要复用同一份基线; + - 只要角度修正变化,就必须清掉旧缓存并重新 `MoveObjectToPathStart()`; + - 清除物体或重新选择物体时,角度修正状态必须归零,不允许继承上一轮对象的角度状态。 + ## 5. 当前保留的日志策略 - 保留: @@ -257,8 +318,16 @@ - 已降级或删除: - 大量重复逐帧宿主姿态轴日志 - 虚拟物体 `Transform` 即时读回日志(容易误导) + - `Hoisting` 真实物体起点姿态与平面前进轴的刷屏 `Info` 日志,已降为 `Debug` -## 6. 当前 Navisworks 变换 API 结论 +## 6. 最近关键提交 + +- `c3b103c` `Add explicit exit for rail assembly workflow` +- `c974469` `Separate rail creation and edit assembly flows` +- `d4c49fc` `Stabilize hoisting pose adjustment flow` +- `cb56737` `Preserve terminal pose when translating rail objects to path start` + +## 7. 当前 Navisworks 变换 API 结论 - `ModelItem.Transform` - 只表示原始设计文件变换; @@ -279,13 +348,13 @@ - 清掉的是永久增量层; - 不会修改原始设计文件变换。 -## 6. 当前还值得继续观察的点 +## 8. 当前还值得继续观察的点 - 空轨路径里仍有一个旧 warning: - `[空轨] 双轨几何中心线提取失败,退回 OBB 主轴中线` - 这与当前 `YUp` 地面路径问题无关,但后续可以单独处理。 -## 7. 下一步建议 +## 9. 下一步建议 - 继续按“先框架、先测试、后接业务”的方式推进。 - 新问题优先: @@ -293,8 +362,12 @@ 2. 若日志不足,先补日志 3. 再补针对性的回归测试 4. 最后再改业务代码 +- `Rail` 终端安装仿真的下一轮优化优先级: + 1. 把创建态/编辑态从 ViewModel 顶层共享字段继续拆成独立 context + 2. 为“取消装配 / 切换路径 / 中途退出后重新开始”补单元测试或更轻量的状态回归验证 + 3. 再考虑是否需要把创建区与编辑区在 UI 上做更明确的视觉分隔 -## 8. 当前阶段的工作边界 +## 10. 当前阶段的工作边界 - 不要回到“直接补旧 `yaw` 链路”的方式。 - 不要再增加隐藏错误的 fallback。 diff --git a/src/UI/WPF/ViewModels/AnimationControlViewModel.cs b/src/UI/WPF/ViewModels/AnimationControlViewModel.cs index 7dfc8b4..4689bb8 100644 --- a/src/UI/WPF/ViewModels/AnimationControlViewModel.cs +++ b/src/UI/WPF/ViewModels/AnimationControlViewModel.cs @@ -2458,7 +2458,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels ModelHighlightHelper.HighlightItems(ManualTargetsHighlightCategory, items); // 聚焦到对象(斜上方45度视角) - ViewpointHelper.FocusOnModelItem(target.ModelItem, viewAngleDegrees: 60.0, targetViewRatio: 0.25); + ViewpointHelper.FocusOnModelItem(target.ModelItem, ViewpointHelper.ViewpointStrategy.ModelFocus); UpdateMainStatus($"已聚焦到: {target.DisplayName}"); LogManager.Info($"聚焦到手工指定对象: {target.DisplayName}"); @@ -2484,7 +2484,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels ModelHighlightHelper.HighlightItems(ExcludedObjectsHighlightCategory, items); // 聚焦到对象(斜上方45度视角) - ViewpointHelper.FocusOnModelItem(excludedObject.ModelItem, viewAngleDegrees: 60.0, targetViewRatio: 0.25); + ViewpointHelper.FocusOnModelItem(excludedObject.ModelItem, ViewpointHelper.ViewpointStrategy.ModelFocus); UpdateMainStatus($"已聚焦到排除对象: {excludedObject.DisplayName}"); LogManager.Info($"聚焦到排除对象: {excludedObject.DisplayName}"); diff --git a/src/UI/WPF/ViewModels/ModelSettingsViewModel.cs b/src/UI/WPF/ViewModels/ModelSettingsViewModel.cs index 1e0093e..7eb10bd 100644 --- a/src/UI/WPF/ViewModels/ModelSettingsViewModel.cs +++ b/src/UI/WPF/ViewModels/ModelSettingsViewModel.cs @@ -1597,7 +1597,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels try { // 聚焦到模型(斜上方60度视角) - ViewpointHelper.FocusOnModelItem(logisticsModel.NavisworksItem, viewAngleDegrees: 60.0, targetViewRatio: 0.25); + ViewpointHelper.FocusOnModelItem(logisticsModel.NavisworksItem, ViewpointHelper.ViewpointStrategy.ModelFocus); UpdateMainStatus($"已聚焦到物流模型: {logisticsModel.Name}"); LogManager.Info($"聚焦到物流模型: {logisticsModel.Name}, 类别: {logisticsModel.Category}"); @@ -1684,4 +1684,4 @@ namespace NavisworksTransport.UI.WPF.ViewModels #endregion } -} \ No newline at end of file +} diff --git a/src/UI/WPF/ViewModels/PathEditingViewModel.cs b/src/UI/WPF/ViewModels/PathEditingViewModel.cs index 2db19f5..5370876 100644 --- a/src/UI/WPF/ViewModels/PathEditingViewModel.cs +++ b/src/UI/WPF/ViewModels/PathEditingViewModel.cs @@ -71,13 +71,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels /// public class PathEditingViewModel : ViewModelBase, IDisposable { - private enum RailAssemblyWorkflowMode - { - None, - CreateNewRailPath, - EditSelectedRail - } - #region 私有字段 private PathPlanningManager _pathPlanningManager; @@ -135,38 +128,13 @@ namespace NavisworksTransport.UI.WPF.ViewModels private const double DefaultAssemblySphereCenterX = 0.0; private const double DefaultAssemblySphereCenterY = 0.0; private const double DefaultAssemblySphereCenterZ = 0.0; - private string _assemblyTerminalObjectName = "未选择"; - private string _assemblyTerminalObjectInfo = "请选择终点处已安装箱体"; - private double _assemblyReferenceRodLengthInMeters = DefaultAssemblyReferenceRodLengthInMeters; - private double _assemblyReferenceRodDiameterInMeters = DefaultAssemblyReferenceRodDiameterInMeters; - private double _assemblyAnchorVerticalOffsetInMeters = DefaultAssemblyAnchorVerticalOffsetInMeters; - private double _assemblySphereCenterX = DefaultAssemblySphereCenterX; - private double _assemblySphereCenterY = DefaultAssemblySphereCenterY; - private double _assemblySphereCenterZ = DefaultAssemblySphereCenterZ; - private string _assemblyStartPointText = "未选择"; - private RailMountMode _assemblyMountMode = RailMountMode.UnderRail; - private bool _hasAssemblyTerminalObject; - private bool _isSelectingAssemblyStartPoint; - private bool _isEditingSelectedRailStartPoint; - private bool _isSelectingAssemblyEndFacePoints; - private bool _isSelectingAssemblyInstallationPoint; - private bool _isEditingSelectedRailInstallationPoint; - private RailAssemblyWorkflowMode _railAssemblyWorkflowMode = RailAssemblyWorkflowMode.None; - private bool _hasAssemblyEndFaceAnalysis; - private bool _hasAssemblyInstallationReference; - private ModelItem _assemblyTerminalObject; - private Point3D _assemblyStartPoint; - private Point3D _assemblyEndFaceCenterPoint; - private Vector3 _assemblyEndFaceNormal; - private Point3D _assemblyInstallationPickPoint; - private Point3D _assemblyInstallationBaseAnchorPoint; - private Point3D _assemblyInstallationAnchorPoint; - private Vector3 _assemblyInstallationPlaneNormal; - private Vector3 _assemblyInstallationPlaneSpanDirection; - private double _assemblyInstallationOffsetDistanceInMeters; - private string _assemblyInstallationReferenceRouteId; - private readonly List _assemblyInstallationSeedPoints = new List(); - private readonly List _assemblyEndFaceSeedPoints = new List(); + private readonly RailAssemblyWorkflowContext _railAssemblyContext = new RailAssemblyWorkflowContext( + DefaultAssemblyReferenceRodLengthInMeters, + DefaultAssemblyReferenceRodDiameterInMeters, + DefaultAssemblyAnchorVerticalOffsetInMeters, + DefaultAssemblySphereCenterX, + DefaultAssemblySphereCenterY, + DefaultAssemblySphereCenterZ); private const string AssemblyAnchorMarkerPathId = "assembly_anchor_marker"; private const string AssemblyCenterGuideLinePathId = "assembly_center_guide_line"; private const string AssemblyReferenceLinePathId = "assembly_reference_line"; @@ -181,6 +149,178 @@ namespace NavisworksTransport.UI.WPF.ViewModels private const double AssemblyInstallationPlanePaddingInMeters = 0.5; private const double AssemblyInstallationLineLengthScale = 1.2; + private string _assemblyTerminalObjectName + { + get => _railAssemblyContext.TerminalObjectName; + set => _railAssemblyContext.TerminalObjectName = value; + } + + private string _assemblyTerminalObjectInfo + { + get => _railAssemblyContext.TerminalObjectInfo; + set => _railAssemblyContext.TerminalObjectInfo = value; + } + + private double _assemblyReferenceRodLengthInMeters + { + get => _railAssemblyContext.ReferenceRodLengthInMeters; + set => _railAssemblyContext.ReferenceRodLengthInMeters = value; + } + + private double _assemblyReferenceRodDiameterInMeters + { + get => _railAssemblyContext.ReferenceRodDiameterInMeters; + set => _railAssemblyContext.ReferenceRodDiameterInMeters = value; + } + + private double _assemblyAnchorVerticalOffsetInMeters + { + get => _railAssemblyContext.AnchorVerticalOffsetInMeters; + set => _railAssemblyContext.AnchorVerticalOffsetInMeters = value; + } + + private double _assemblySphereCenterX + { + get => _railAssemblyContext.SphereCenterX; + set => _railAssemblyContext.SphereCenterX = value; + } + + private double _assemblySphereCenterY + { + get => _railAssemblyContext.SphereCenterY; + set => _railAssemblyContext.SphereCenterY = value; + } + + private double _assemblySphereCenterZ + { + get => _railAssemblyContext.SphereCenterZ; + set => _railAssemblyContext.SphereCenterZ = value; + } + + private string _assemblyStartPointText + { + get => _railAssemblyContext.StartPointText; + set => _railAssemblyContext.StartPointText = value; + } + + private RailMountMode _assemblyMountMode + { + get => _railAssemblyContext.MountMode; + set => _railAssemblyContext.MountMode = value; + } + + private bool _hasAssemblyTerminalObject + { + get => _railAssemblyContext.HasTerminalObject; + set => _railAssemblyContext.HasTerminalObject = value; + } + + private bool _isSelectingAssemblyStartPoint + { + get => _railAssemblyContext.IsSelectingStartPoint; + set => _railAssemblyContext.IsSelectingStartPoint = value; + } + + private bool _isSelectingAssemblyEndFacePoints + { + get => _railAssemblyContext.IsSelectingEndFacePoints; + set => _railAssemblyContext.IsSelectingEndFacePoints = value; + } + + private bool _isSelectingAssemblyInstallationPoint + { + get => _railAssemblyContext.IsSelectingInstallationPoint; + set => _railAssemblyContext.IsSelectingInstallationPoint = value; + } + + private RailAssemblyWorkflowMode _railAssemblyWorkflowMode + { + get => _railAssemblyContext.WorkflowMode; + set => _railAssemblyContext.WorkflowMode = value; + } + + private bool _hasAssemblyEndFaceAnalysis + { + get => _railAssemblyContext.HasEndFaceAnalysis; + set => _railAssemblyContext.HasEndFaceAnalysis = value; + } + + private bool _hasAssemblyInstallationReference + { + get => _railAssemblyContext.HasInstallationReference; + set => _railAssemblyContext.HasInstallationReference = value; + } + + private ModelItem _assemblyTerminalObject + { + get => _railAssemblyContext.TerminalObject; + set => _railAssemblyContext.TerminalObject = value; + } + + private Point3D _assemblyStartPoint + { + get => _railAssemblyContext.StartPoint; + set => _railAssemblyContext.StartPoint = value; + } + + private Point3D _assemblyEndFaceCenterPoint + { + get => _railAssemblyContext.EndFaceCenterPoint; + set => _railAssemblyContext.EndFaceCenterPoint = value; + } + + private Vector3 _assemblyEndFaceNormal + { + get => _railAssemblyContext.EndFaceNormal; + set => _railAssemblyContext.EndFaceNormal = value; + } + + private Point3D _assemblyInstallationPickPoint + { + get => _railAssemblyContext.InstallationPickPoint; + set => _railAssemblyContext.InstallationPickPoint = value; + } + + private Point3D _assemblyInstallationBaseAnchorPoint + { + get => _railAssemblyContext.InstallationBaseAnchorPoint; + set => _railAssemblyContext.InstallationBaseAnchorPoint = value; + } + + private Point3D _assemblyInstallationAnchorPoint + { + get => _railAssemblyContext.InstallationAnchorPoint; + set => _railAssemblyContext.InstallationAnchorPoint = value; + } + + private Vector3 _assemblyInstallationPlaneNormal + { + get => _railAssemblyContext.InstallationPlaneNormal; + set => _railAssemblyContext.InstallationPlaneNormal = value; + } + + private Vector3 _assemblyInstallationPlaneSpanDirection + { + get => _railAssemblyContext.InstallationPlaneSpanDirection; + set => _railAssemblyContext.InstallationPlaneSpanDirection = value; + } + + private double _assemblyInstallationOffsetDistanceInMeters + { + get => _railAssemblyContext.InstallationOffsetDistanceInMeters; + set => _railAssemblyContext.InstallationOffsetDistanceInMeters = value; + } + + private string _assemblyInstallationReferenceRouteId + { + get => _railAssemblyContext.InstallationReferenceRouteId; + set => _railAssemblyContext.InstallationReferenceRouteId = value; + } + + private List _assemblyInstallationSeedPoints => _railAssemblyContext.InstallationSeedPoints; + + private List _assemblyEndFaceSeedPoints => _railAssemblyContext.EndFaceSeedPoints; + // 自动路径起点和终点的路径对象引用(用于正确的ID管理) private PathRoute _autoPathStartPointRoute = null; private PathRoute _autoPathEndPointRoute = null; @@ -250,8 +390,8 @@ namespace NavisworksTransport.UI.WPF.ViewModels { try { - ViewpointHelper.AdjustViewpointToPathCenter(coreRoute); - LogManager.Info($"UI路径切换:已自动调整视角到路径中心: {value.Name}"); + ViewpointHelper.AdjustViewpointForPath(coreRoute); + LogManager.Info($"UI路径切换:已自动调整视角: {value.Name}, 类型={coreRoute.PathType}"); } catch (Exception ex) { @@ -417,13 +557,31 @@ namespace NavisworksTransport.UI.WPF.ViewModels public string AssemblyTerminalObjectName { get => _assemblyTerminalObjectName; - set => SetProperty(ref _assemblyTerminalObjectName, value); + set + { + if (string.Equals(_assemblyTerminalObjectName, value, StringComparison.Ordinal)) + { + return; + } + + _assemblyTerminalObjectName = value; + OnPropertyChanged(nameof(AssemblyTerminalObjectName)); + } } public string AssemblyTerminalObjectInfo { get => _assemblyTerminalObjectInfo; - set => SetProperty(ref _assemblyTerminalObjectInfo, value); + set + { + if (string.Equals(_assemblyTerminalObjectInfo, value, StringComparison.Ordinal)) + { + return; + } + + _assemblyTerminalObjectInfo = value; + OnPropertyChanged(nameof(AssemblyTerminalObjectInfo)); + } } public double AssemblyReferenceRodLengthInMeters @@ -431,10 +589,13 @@ namespace NavisworksTransport.UI.WPF.ViewModels get => _assemblyReferenceRodLengthInMeters; set { - if (SetProperty(ref _assemblyReferenceRodLengthInMeters, value)) + if (Math.Abs(_assemblyReferenceRodLengthInMeters - value) < 1e-9) { - OnPropertyChanged(nameof(CanGenerateAssemblyReferenceRod)); + return; } + + _assemblyReferenceRodLengthInMeters = value; + OnPropertyChanged(nameof(AssemblyReferenceRodLengthInMeters)); } } @@ -443,10 +604,13 @@ namespace NavisworksTransport.UI.WPF.ViewModels get => _assemblyReferenceRodDiameterInMeters; set { - if (SetProperty(ref _assemblyReferenceRodDiameterInMeters, value)) + if (Math.Abs(_assemblyReferenceRodDiameterInMeters - value) < 1e-9) { - OnPropertyChanged(nameof(CanGenerateAssemblyReferenceRod)); + return; } + + _assemblyReferenceRodDiameterInMeters = value; + OnPropertyChanged(nameof(AssemblyReferenceRodDiameterInMeters)); } } @@ -455,7 +619,15 @@ namespace NavisworksTransport.UI.WPF.ViewModels get => _assemblyAnchorVerticalOffsetInMeters; set { - if (SetProperty(ref _assemblyAnchorVerticalOffsetInMeters, value) && HasAssemblyTerminalObject) + if (Math.Abs(_assemblyAnchorVerticalOffsetInMeters - value) < 1e-9) + { + return; + } + + _assemblyAnchorVerticalOffsetInMeters = value; + OnPropertyChanged(nameof(AssemblyAnchorVerticalOffsetInMeters)); + + if (HasAssemblyTerminalObject) { var coreRoute = GetSelectedCoreRoute(); if (_hasAssemblyInstallationReference) @@ -475,7 +647,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels } else { - RenderAssemblyAnchorMarker(); RefreshAssemblyReferenceRodIfNeeded(); } } @@ -487,7 +658,15 @@ namespace NavisworksTransport.UI.WPF.ViewModels get => _assemblySphereCenterX; set { - if (SetProperty(ref _assemblySphereCenterX, value) && HasAssemblyTerminalObject) + if (Math.Abs(_assemblySphereCenterX - value) < 1e-9) + { + return; + } + + _assemblySphereCenterX = value; + OnPropertyChanged(nameof(AssemblySphereCenterX)); + + if (HasAssemblyTerminalObject) { RefreshAssemblyTerminalObjectInfo(); RefreshAssemblyReferenceRodIfNeeded(); @@ -500,7 +679,15 @@ namespace NavisworksTransport.UI.WPF.ViewModels get => _assemblySphereCenterY; set { - if (SetProperty(ref _assemblySphereCenterY, value) && HasAssemblyTerminalObject) + if (Math.Abs(_assemblySphereCenterY - value) < 1e-9) + { + return; + } + + _assemblySphereCenterY = value; + OnPropertyChanged(nameof(AssemblySphereCenterY)); + + if (HasAssemblyTerminalObject) { RefreshAssemblyTerminalObjectInfo(); RefreshAssemblyReferenceRodIfNeeded(); @@ -513,7 +700,15 @@ namespace NavisworksTransport.UI.WPF.ViewModels get => _assemblySphereCenterZ; set { - if (SetProperty(ref _assemblySphereCenterZ, value) && HasAssemblyTerminalObject) + if (Math.Abs(_assemblySphereCenterZ - value) < 1e-9) + { + return; + } + + _assemblySphereCenterZ = value; + OnPropertyChanged(nameof(AssemblySphereCenterZ)); + + if (HasAssemblyTerminalObject) { RefreshAssemblyTerminalObjectInfo(); RefreshAssemblyReferenceRodIfNeeded(); @@ -524,13 +719,31 @@ namespace NavisworksTransport.UI.WPF.ViewModels public bool HasAssemblyTerminalObject { get => _hasAssemblyTerminalObject; - set => SetProperty(ref _hasAssemblyTerminalObject, value); + set + { + if (_hasAssemblyTerminalObject == value) + { + return; + } + + _hasAssemblyTerminalObject = value; + OnPropertyChanged(nameof(HasAssemblyTerminalObject)); + } } public string AssemblyStartPointText { get => _assemblyStartPointText; - set => SetProperty(ref _assemblyStartPointText, value); + set + { + if (string.Equals(_assemblyStartPointText, value, StringComparison.Ordinal)) + { + return; + } + + _assemblyStartPointText = value; + OnPropertyChanged(nameof(AssemblyStartPointText)); + } } public RailMountMode AssemblyMountMode @@ -538,7 +751,15 @@ namespace NavisworksTransport.UI.WPF.ViewModels get => _assemblyMountMode; set { - if (SetProperty(ref _assemblyMountMode, value) && HasAssemblyTerminalObject) + if (_assemblyMountMode == value) + { + return; + } + + _assemblyMountMode = value; + OnPropertyChanged(nameof(AssemblyMountMode)); + + if (HasAssemblyTerminalObject) { RefreshAssemblyTerminalObjectInfo(); RefreshAssemblyReferenceRodIfNeeded(); @@ -549,7 +770,16 @@ namespace NavisworksTransport.UI.WPF.ViewModels public bool IsSelectingAssemblyStartPoint { get => _isSelectingAssemblyStartPoint; - set => SetProperty(ref _isSelectingAssemblyStartPoint, value); + set + { + if (_isSelectingAssemblyStartPoint == value) + { + return; + } + + _isSelectingAssemblyStartPoint = value; + OnPropertyChanged(nameof(IsSelectingAssemblyStartPoint)); + } } /// /// 更新路径可视化显示:清理其他路径,只显示当前选中的路径 @@ -1072,7 +1302,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels public ICommand SaveAsPathCommand { get; private set; } public ICommand CaptureAssemblyTerminalObjectForCreateCommand { get; private set; } public ICommand ReCaptureAssemblyTerminalObjectForEditCommand { get; private set; } - public ICommand GenerateAssemblyReferenceRodCommand { get; private set; } public ICommand SelectAssemblyStartPointForCreateCommand { get; private set; } public ICommand RepositionRailStartPointCommand { get; private set; } public ICommand SelectAssemblyInstallationPointForCreateCommand { get; private set; } @@ -1119,10 +1348,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels public bool CanExecuteExportPath => _pathPlanningManager?.Routes?.Count > 0 || SelectedPathRoute != null; public bool CanExecuteSaveAsPath => SelectedPathRoute != null && SelectedPathRoute.Points.Count > 0; - public bool CanGenerateAssemblyReferenceRod => HasAssemblyTerminalObject && - _hasAssemblyInstallationReference && - AssemblyReferenceRodLengthInMeters > 0 && - AssemblyReferenceRodDiameterInMeters > 0; public bool CanSelectAssemblyStartPointForCreate => HasAssemblyTerminalObject && _pathPlanningManager != null && AssemblyReferencePathManager.Instance.HasReferenceLine && @@ -1182,6 +1407,28 @@ namespace NavisworksTransport.UI.WPF.ViewModels private bool IsRailCreateWorkflowActive => _railAssemblyWorkflowMode == RailAssemblyWorkflowMode.CreateNewRailPath; private bool IsRailEditingWorkflowActive => _railAssemblyWorkflowMode == RailAssemblyWorkflowMode.EditSelectedRail; + private static bool IsRailAssemblyEditMode(RailAssemblyWorkflowMode workflowMode) + { + return workflowMode == RailAssemblyWorkflowMode.EditSelectedRail; + } + + private static string GetRailAssemblyWorkflowLabel(RailAssemblyWorkflowMode workflowMode) + { + return IsRailAssemblyEditMode(workflowMode) + ? "编辑现有Rail路径" + : "新建Rail路径"; + } + + private bool ShouldShowAssemblyReferenceLineVisuals() + { + if (_assemblyTerminalObject == null || !ModelItemAnalysisHelper.IsModelItemValid(_assemblyTerminalObject)) + { + return false; + } + + return IsRailEditingWorkflowActive || _hasAssemblyInstallationReference; + } + public bool CanExecuteModifyPoint => SelectedPathPoint != null && _pathPlanningManager?.PathEditState != PathEditState.EditingPoint; public bool CanExecuteCancelModifyPoint => _pathPlanningManager?.PathEditState == PathEditState.EditingPoint; @@ -1718,7 +1965,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels SaveAsPathCommand = new RelayCommand(async () => await ExecuteSaveAsPathAsync(), () => CanExecuteSaveAsPath); CaptureAssemblyTerminalObjectForCreateCommand = new RelayCommand(async () => await ExecuteCaptureAssemblyTerminalObjectAsync(RailAssemblyWorkflowMode.CreateNewRailPath)); ReCaptureAssemblyTerminalObjectForEditCommand = new RelayCommand(async () => await ExecuteCaptureAssemblyTerminalObjectAsync(RailAssemblyWorkflowMode.EditSelectedRail)); - GenerateAssemblyReferenceRodCommand = new RelayCommand(async () => await ExecuteGenerateAssemblyReferenceRodAsync(), () => CanGenerateAssemblyReferenceRod); SelectAssemblyStartPointForCreateCommand = new RelayCommand(async () => await ExecuteSelectAssemblyStartPointAsync(), () => CanSelectAssemblyStartPointForCreate); RepositionRailStartPointCommand = new RelayCommand(async () => await ExecuteRepositionRailStartPointAsync(), () => CanRepositionRailStartPoint); SelectAssemblyInstallationPointForCreateCommand = new RelayCommand(async () => await ExecuteSelectAssemblyInstallationPointAsync(RailAssemblyWorkflowMode.CreateNewRailPath), () => CanSelectAssemblyInstallationPointForCreate); @@ -1768,7 +2014,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels ClearAssemblyAnchorMarker(); ClearAssemblyEndFaceAnalysisVisuals(); ClearAssemblyInstallationReferenceVisuals(); - OnPropertyChanged(nameof(CanGenerateAssemblyReferenceRod)); NotifyRailAssemblyCommandStateChanged(); // 新建路径时隐藏其他路径的辅助线 @@ -1803,41 +2048,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels } } - private async Task ExecuteGenerateAssemblyReferenceRodAsync() - { - await SafeExecuteAsync(() => - { - if (_assemblyTerminalObject == null || !ModelItemAnalysisHelper.IsModelItemValid(_assemblyTerminalObject)) - { - throw new InvalidOperationException("终点箱体未设置或已失效,请重新捕获终点箱体"); - } - - AssemblyReferenceLine referenceLine = BuildAssemblyReferenceLine(); - - AssemblyReferencePathManager.Instance.CreateOrUpdateReferenceRod( - referenceLine.StartPoint, - referenceLine.EndPoint, - AssemblyReferenceRodDiameterInMeters); - - _assemblyStartPoint = Point3D.Origin; - AssemblyStartPointText = "未选择"; - RefreshAssemblyTerminalObjectInfo(referenceLine.StartPoint, referenceLine.EndPoint); - RenderAssemblyAnchorMarker(); - RenderAssemblyCenterGuideLine(); - RenderAssemblyReferenceLine(referenceLine); - FocusOnAssemblyReferenceArea(referenceLine.StartPoint, referenceLine.EndPoint); - - UpdateMainStatus("已生成终端安装辅助线,请在三维视图中确认终点锚点、方向、外端位置和辅助线贴合情况"); - NotifyRailAssemblyCommandStateChanged(); - LogManager.Info( - $"[直线装配] 已生成参考杆: {AssemblyTerminalObjectName}, " + - $"终点锚点=({referenceLine.EndPoint.X:F2}, {referenceLine.EndPoint.Y:F2}, {referenceLine.EndPoint.Z:F2}), " + - $"参考线外端=({referenceLine.StartPoint.X:F2}, {referenceLine.StartPoint.Y:F2}, {referenceLine.StartPoint.Z:F2}), " + - $"方向=({referenceLine.Direction.X:F3}, {referenceLine.Direction.Y:F3}, {referenceLine.Direction.Z:F3}), " + - $"资源={AssemblyReferencePathManager.Instance.ReferenceResourceName}"); - }, "生成终端安装辅助线"); - } - private async Task ExecuteSelectAssemblyStartPointAsync() { await SafeExecuteAsync(() => @@ -1854,27 +2064,13 @@ namespace NavisworksTransport.UI.WPF.ViewModels if (!AssemblyReferencePathManager.Instance.HasReferenceLine) { - throw new InvalidOperationException("请先生成终端安装辅助线"); + throw new InvalidOperationException("请先选择安装点,系统生成终端安装辅助线后才能取起点"); } - CleanupAssemblyReferenceSelection(); - - _pathPlanningManager.DisableMouseHandling(); - IsSelectingAssemblyStartPoint = true; - NotifyRailAssemblyCommandStateChanged(); - - PathClickToolPlugin.MouseClicked -= OnAssemblyReferenceMouseClicked; - PathClickToolPlugin.MouseClicked += OnAssemblyReferenceMouseClicked; - - if (!ForceReinitializeToolPlugin(subscribeToEvents: false)) - { - CleanupAssemblyReferenceSelection(); - throw new InvalidOperationException("ToolPlugin 初始化失败,请重试"); - } - - _pathPlanningManager.StartClickTool(PathPointType.StartPoint); - UpdateMainStatus("请在辅助线附近点击一个起点,系统会自动吸附到辅助线上并生成直线路径"); - LogManager.Info("[直线装配] 已进入起点拾取模式"); + BeginAssemblyStartPointSelection( + statusMessage: "请在辅助线附近点击一个起点,系统会自动吸附到辅助线上并生成直线路径", + logMessage: "[直线装配] 已进入起点拾取模式", + toolPluginFailureMessage: "ToolPlugin 初始化失败,请重试"); }, "选择终端安装起点"); } @@ -1905,25 +2101,10 @@ namespace NavisworksTransport.UI.WPF.ViewModels throw new InvalidOperationException("当前 Rail 路径无法生成辅助线,请先检查路径起点和终点。"); } - CleanupAssemblyReferenceSelection(); - - _pathPlanningManager.DisableMouseHandling(); - _isEditingSelectedRailStartPoint = true; - IsSelectingAssemblyStartPoint = true; - NotifyRailAssemblyCommandStateChanged(); - - PathClickToolPlugin.MouseClicked -= OnAssemblyReferenceMouseClicked; - PathClickToolPlugin.MouseClicked += OnAssemblyReferenceMouseClicked; - - if (!ForceReinitializeToolPlugin(subscribeToEvents: false)) - { - CleanupAssemblyReferenceSelection(); - throw new InvalidOperationException("ToolPlugin 初始化失败,请重试。"); - } - - _pathPlanningManager.StartClickTool(PathPointType.StartPoint); - UpdateMainStatus("请在辅助线附近点击新的起点位置,系统会自动吸附到辅助线上并更新当前 Rail 路径。"); - LogManager.Info("[Rail构型] 已进入起点重选模式"); + BeginAssemblyStartPointSelection( + statusMessage: "请在辅助线附近点击新的起点位置,系统会自动吸附到辅助线上并更新当前 Rail 路径。", + logMessage: "[Rail构型] 已进入起点重选模式", + toolPluginFailureMessage: "ToolPlugin 初始化失败,请重试。"); }, "重选 Rail 路径起点"); } @@ -1957,45 +2138,12 @@ namespace NavisworksTransport.UI.WPF.ViewModels throw new InvalidOperationException("终点箱体未设置或已失效,请先捕获终点箱体。"); } - bool isEditingExistingRailRoute = workflowMode == RailAssemblyWorkflowMode.EditSelectedRail; - var selectedRailRoute = isEditingExistingRailRoute ? GetSelectedCoreRoute() : null; - if (isEditingExistingRailRoute) - { - if (selectedRailRoute == null || selectedRailRoute.PathType != PathType.Rail) - { - throw new InvalidOperationException("请先选中一条需要编辑安装点的 Rail 路径。"); - } + PrepareRailAssemblyWorkflowForMode( + workflowMode, + editActionDescription: "请先选中一条需要编辑安装点的 Rail 路径。", + syncMountModeFromRoute: true); - AssemblyMountMode = selectedRailRoute.RailMountMode; - } - - SetRailAssemblyWorkflowMode(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( - $"[直线装配] 已进入端面三点分析模式,模式={(isEditingExistingRailRoute ? "编辑现有Rail路径" : "新建Rail路径")}"); + BeginAssemblyEndFaceSelection(workflowMode); }, "分析终端端面"); } @@ -2013,39 +2161,12 @@ namespace NavisworksTransport.UI.WPF.ViewModels throw new InvalidOperationException("终点箱体未设置或已失效,请先捕获终点箱体。"); } - bool isEditingExistingRailRoute = workflowMode == RailAssemblyWorkflowMode.EditSelectedRail; - var selectedRailRoute = isEditingExistingRailRoute ? GetSelectedCoreRoute() : null; - if (isEditingExistingRailRoute && (selectedRailRoute == null || selectedRailRoute.PathType != PathType.Rail)) - { - throw new InvalidOperationException("请先选中一条需要编辑安装点的 Rail 路径。"); - } + PrepareRailAssemblyWorkflowForMode( + workflowMode, + editActionDescription: "请先选中一条需要编辑安装点的 Rail 路径。", + syncMountModeFromRoute: false); - SetRailAssemblyWorkflowMode(workflowMode); - - CleanupAssemblyReferenceSelection(); - CleanupAssemblyEndFaceSelection(clearVisuals: false); - CleanupAssemblyInstallationSelection(); - ClearAssemblyInstallationReferenceVisuals(); - - _pathPlanningManager.DisableMouseHandling(); - _isSelectingAssemblyInstallationPoint = true; - - _isEditingSelectedRailInstallationPoint = isEditingExistingRailRoute; - - NotifyRailAssemblyCommandStateChanged(); - - PathClickToolPlugin.MouseClicked -= OnAssemblyInstallationMouseClicked; - PathClickToolPlugin.MouseClicked += OnAssemblyInstallationMouseClicked; - - if (!ForceReinitializeToolPlugin(subscribeToEvents: false)) - { - CleanupAssemblyInstallationSelection(); - throw new InvalidOperationException("ToolPlugin 初始化失败,请重试。"); - } - - _assemblyInstallationSeedPoints.Clear(); - UpdateMainStatus("请在终点箱体表面连续点击两个安装面点,系统将按两点和光轴计算安装参考面与安装点。"); - LogManager.Info("[直线装配] 已进入安装点拾取模式"); + BeginAssemblyInstallationSelection(); }, "选择安装点"); } @@ -2067,16 +2188,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels await SafeExecuteAsync(() => { - if (_isEditingSelectedRailStartPoint) - { - UpdateSelectedRailRouteStartPoint(projectedStartPoint); - UpdateMainStatus("已根据辅助线更新当前 Rail 路径起点"); - } - else - { - CreateAssemblyLinearRoute(projectedStartPoint); - UpdateMainStatus("已根据辅助线起点生成终端安装路径"); - } + ApplyAssemblyStartPointForCurrentWorkflow(projectedStartPoint); CleanupAssemblyReferenceSelection(); }, "生成终端安装路径"); @@ -2163,22 +2275,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels _assemblyInstallationSeedPoints[0], _assemblyInstallationSeedPoints[1]); - if (_isEditingSelectedRailInstallationPoint) - { - // 编辑现有路径:更新安装点并同步起点 - var selectedRailRoute = GetSelectedCoreRoute(); - if (selectedRailRoute != null && selectedRailRoute.PathType == PathType.Rail) - { - PersistAssemblyInstallationReferenceToRailRoute( - selectedRailRoute, - "已重选安装点并同步更新 Rail 路径安装参数"); - } - } - else - { - // 创建新路径:生成参考线,等待用户选择起点 - LogManager.Info("[直线装配] 安装点已确定,请继续选择起点以生成新路径"); - } + ApplyAssemblyInstallationReferenceForCurrentWorkflow(); CleanupAssemblyInstallationSelection(clearVisuals: false); }, "处理安装点拾取"); } @@ -2190,6 +2287,138 @@ namespace NavisworksTransport.UI.WPF.ViewModels } } + private void PrepareRailAssemblyWorkflowForMode( + RailAssemblyWorkflowMode workflowMode, + string editActionDescription, + bool syncMountModeFromRoute) + { + PathRoute selectedRailRoute = null; + if (IsRailAssemblyEditMode(workflowMode)) + { + selectedRailRoute = RequireSelectedRailRouteForAssemblyEdit(editActionDescription); + if (syncMountModeFromRoute) + { + AssemblyMountMode = selectedRailRoute.RailMountMode; + } + } + + SetRailAssemblyWorkflowMode(workflowMode); + } + + private PathRoute RequireSelectedRailRouteForAssemblyEdit(string errorMessage) + { + var selectedRailRoute = GetSelectedCoreRoute(); + if (selectedRailRoute == null || selectedRailRoute.PathType != PathType.Rail) + { + throw new InvalidOperationException(errorMessage); + } + + return selectedRailRoute; + } + + private void BeginAssemblyStartPointSelection(string statusMessage, string logMessage, string toolPluginFailureMessage) + { + CleanupAssemblyReferenceSelection(); + + _pathPlanningManager.DisableMouseHandling(); + IsSelectingAssemblyStartPoint = true; + NotifyRailAssemblyCommandStateChanged(); + + PathClickToolPlugin.MouseClicked -= OnAssemblyReferenceMouseClicked; + PathClickToolPlugin.MouseClicked += OnAssemblyReferenceMouseClicked; + + if (!ForceReinitializeToolPlugin(subscribeToEvents: false)) + { + CleanupAssemblyReferenceSelection(); + throw new InvalidOperationException(toolPluginFailureMessage); + } + + _pathPlanningManager.StartClickTool(PathPointType.StartPoint); + UpdateMainStatus(statusMessage); + LogManager.Info(logMessage); + } + + 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(); + CleanupAssemblyEndFaceSelection(clearVisuals: false); + CleanupAssemblyInstallationSelection(); + ClearAssemblyInstallationReferenceVisuals(); + + _pathPlanningManager.DisableMouseHandling(); + _isSelectingAssemblyInstallationPoint = true; + NotifyRailAssemblyCommandStateChanged(); + + PathClickToolPlugin.MouseClicked -= OnAssemblyInstallationMouseClicked; + PathClickToolPlugin.MouseClicked += OnAssemblyInstallationMouseClicked; + + if (!ForceReinitializeToolPlugin(subscribeToEvents: false)) + { + CleanupAssemblyInstallationSelection(); + throw new InvalidOperationException("ToolPlugin 初始化失败,请重试。"); + } + + _assemblyInstallationSeedPoints.Clear(); + UpdateMainStatus("请在终点箱体表面连续点击两个安装面点,系统将按两点和光轴计算安装参考面与安装点。"); + LogManager.Info($"[直线装配] 已进入安装点拾取模式,模式={GetRailAssemblyWorkflowLabel(_railAssemblyWorkflowMode)}"); + } + + private void ApplyAssemblyStartPointForCurrentWorkflow(Point3D projectedStartPoint) + { + if (IsRailEditingWorkflowActive) + { + UpdateSelectedRailRouteStartPoint(projectedStartPoint); + ClearAssemblyReferenceLineVisuals(); + UpdateMainStatus("已根据辅助线更新当前 Rail 路径起点"); + return; + } + + CreateAssemblyLinearRoute(projectedStartPoint); + UpdateMainStatus("已根据辅助线起点生成终端安装路径"); + } + + private void ApplyAssemblyInstallationReferenceForCurrentWorkflow() + { + if (IsRailEditingWorkflowActive) + { + var selectedRailRoute = RequireSelectedRailRouteForAssemblyEdit("当前没有可更新安装点的 Rail 路径。"); + PersistAssemblyInstallationReferenceToRailRoute( + selectedRailRoute, + "已重选安装点并同步更新 Rail 路径安装参数"); + return; + } + + LogManager.Info("[直线装配] 安装点已确定,请继续选择起点以生成新路径"); + } + private void CreateAssemblyLinearRoute(Point3D startPoint) { Point3D endPoint = AssemblyReferencePathManager.Instance.ReferenceLineEnd; @@ -2324,16 +2553,13 @@ namespace NavisworksTransport.UI.WPF.ViewModels ClearAssemblyInstallationReferenceVisuals(); ResetAssemblyEndFaceAnalysisState(); ResetAssemblyInstallationReferenceState(); - - _assemblyTerminalObject = null; - _assemblyStartPoint = Point3D.Origin; + _railAssemblyContext.ResetSession(); HasAssemblyTerminalObject = false; - AssemblyTerminalObjectName = "未选择"; - AssemblyTerminalObjectInfo = "请选择终点处已安装箱体"; - AssemblyStartPointText = "未选择"; + AssemblyTerminalObjectName = _assemblyTerminalObjectName; + AssemblyTerminalObjectInfo = _assemblyTerminalObjectInfo; + AssemblyStartPointText = _assemblyStartPointText; SetRailAssemblyWorkflowMode(RailAssemblyWorkflowMode.None); - OnPropertyChanged(nameof(CanGenerateAssemblyReferenceRod)); NotifyRailAssemblyCommandStateChanged(); if (announce && !string.IsNullOrWhiteSpace(statusMessage)) @@ -2595,7 +2821,13 @@ namespace NavisworksTransport.UI.WPF.ViewModels private void RefreshAssemblyReferenceRodIfNeeded() { - if (!AssemblyReferencePathManager.Instance.HasReferenceLine || _assemblyTerminalObject == null) + if (!ShouldShowAssemblyReferenceLineVisuals()) + { + ClearAssemblyReferenceLineVisuals(); + return; + } + + if (_assemblyTerminalObject == null) { return; } @@ -2672,61 +2904,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels return standardRadiusInMeters * 0.8; } - private void FocusOnAssemblyReferenceArea(Point3D startPoint, Point3D endPoint) - { - try - { - double minX = Math.Min(startPoint.X, endPoint.X); - double minY = Math.Min(startPoint.Y, endPoint.Y); - double minZ = Math.Min(startPoint.Z, endPoint.Z); - double maxX = Math.Max(startPoint.X, endPoint.X); - double maxY = Math.Max(startPoint.Y, endPoint.Y); - double maxZ = Math.Max(startPoint.Z, endPoint.Z); - - if (_assemblyTerminalObject != null && ModelItemAnalysisHelper.IsModelItemValid(_assemblyTerminalObject)) - { - var terminalBounds = _assemblyTerminalObject.BoundingBox(); - minX = Math.Min(minX, terminalBounds.Min.X); - minY = Math.Min(minY, terminalBounds.Min.Y); - minZ = Math.Min(minZ, terminalBounds.Min.Z); - maxX = Math.Max(maxX, terminalBounds.Max.X); - maxY = Math.Max(maxY, terminalBounds.Max.Y); - maxZ = Math.Max(maxZ, terminalBounds.Max.Z); - } - - Point3D center = new Point3D( - (minX + maxX) / 2.0, - (minY + maxY) / 2.0, - (minZ + maxZ) / 2.0); - - double targetSize = Math.Max( - maxX - minX, - Math.Max(maxY - minY, maxZ - minZ)); - - targetSize = Math.Max(targetSize, UnitsConverter.ConvertFromMeters(1.0)); - - ViewpointHelper.FocusOnPosition(center, targetSize, 45.0, 0.35); - - var selection = new List(); - if (_assemblyTerminalObject != null && ModelItemAnalysisHelper.IsModelItemValid(_assemblyTerminalObject)) - { - selection.Add(_assemblyTerminalObject); - } - - var referenceRod = AssemblyReferencePathManager.Instance.CurrentReferenceRod; - if (referenceRod != null) - { - selection.Add(referenceRod); - } - - NavisworksSelectionHelper.SetModelSelection(selection); - } - catch (Exception ex) - { - LogManager.Warning($"[直线装配] 聚焦参考杆区域失败: {ex.Message}"); - } - } - private void RenderAssemblyAnchorMarker() { if (_assemblyTerminalObject == null || !ModelItemAnalysisHelper.IsModelItemValid(_assemblyTerminalObject)) @@ -2930,13 +3107,12 @@ namespace NavisworksTransport.UI.WPF.ViewModels RefreshAssemblyTerminalObjectInfo(); RefreshAssemblyReferenceRodIfNeeded(); UpdateMainStatus( - $"安装参考已计算:安装点=({_assemblyInstallationAnchorPoint.X:F2}, {_assemblyInstallationAnchorPoint.Y:F2}, {_assemblyInstallationAnchorPoint.Z:F2}),偏距={_assemblyInstallationOffsetDistanceInMeters:F3}m"); + $"安装参考已计算:安装点=({_assemblyInstallationAnchorPoint.X:F2}, {_assemblyInstallationAnchorPoint.Y:F2}, {_assemblyInstallationAnchorPoint.Z:F2}),偏距={_assemblyInstallationOffsetDistanceInMeters:F3}m,可继续取起点"); LogManager.Info( $"[直线装配] 安装参考已计算: 安装面点1=({firstPickPoint.X:F3}, {firstPickPoint.Y:F3}, {firstPickPoint.Z:F3}), " + $"安装面点2=({secondPickPoint.X:F3}, {secondPickPoint.Y:F3}, {secondPickPoint.Z:F3}), " + $"安装点=({_assemblyInstallationAnchorPoint.X:F3}, {_assemblyInstallationAnchorPoint.Y:F3}, {_assemblyInstallationAnchorPoint.Z:F3}), " + $"偏距={_assemblyInstallationOffsetDistanceInMeters:F3}m, 平面法向=({result.PlaneNormal.X:F4}, {result.PlaneNormal.Y:F4}, {result.PlaneNormal.Z:F4})"); - OnPropertyChanged(nameof(CanGenerateAssemblyReferenceRod)); NotifyRailAssemblyCommandStateChanged(); } @@ -3139,9 +3315,7 @@ namespace NavisworksTransport.UI.WPF.ViewModels private void ResetAssemblyEndFaceAnalysisState() { - _hasAssemblyEndFaceAnalysis = false; - _assemblyEndFaceCenterPoint = null; - _assemblyEndFaceNormal = default(Vector3); + _railAssemblyContext.ResetEndFaceAnalysis(); } private void ClearAssemblyInstallationReferenceVisuals() @@ -3161,18 +3335,8 @@ namespace NavisworksTransport.UI.WPF.ViewModels private void ResetAssemblyInstallationReferenceState() { - _hasAssemblyInstallationReference = false; - _assemblyInstallationPickPoint = null; - _assemblyInstallationBaseAnchorPoint = null; - _assemblyInstallationAnchorPoint = null; - _assemblyInstallationPlaneNormal = default(Vector3); - _assemblyInstallationPlaneSpanDirection = default(Vector3); - _assemblyInstallationOffsetDistanceInMeters = 0.0; - _assemblyInstallationReferenceRouteId = null; - _assemblyInstallationSeedPoints.Clear(); - _assemblyAnchorVerticalOffsetInMeters = DefaultAssemblyAnchorVerticalOffsetInMeters; + _railAssemblyContext.ResetInstallationReference(); OnPropertyChanged(nameof(AssemblyAnchorVerticalOffsetInMeters)); - OnPropertyChanged(nameof(CanGenerateAssemblyReferenceRod)); NotifyRailAssemblyCommandStateChanged(); } @@ -3182,7 +3346,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels { PathClickToolPlugin.MouseClicked -= OnAssemblyReferenceMouseClicked; IsSelectingAssemblyStartPoint = false; - _isEditingSelectedRailStartPoint = false; _pathPlanningManager?.EnableMouseHandling(); _pathPlanningManager?.StopClickTool(); NotifyRailAssemblyCommandStateChanged(); @@ -3199,7 +3362,6 @@ namespace NavisworksTransport.UI.WPF.ViewModels { PathClickToolPlugin.MouseClicked -= OnAssemblyInstallationMouseClicked; _isSelectingAssemblyInstallationPoint = false; - _isEditingSelectedRailInstallationPoint = false; _pathPlanningManager?.EnableMouseHandling(); _pathPlanningManager?.StopClickTool(); if (clearVisuals) diff --git a/src/UI/WPF/ViewModels/RailAssemblyWorkflowContext.cs b/src/UI/WPF/ViewModels/RailAssemblyWorkflowContext.cs new file mode 100644 index 0000000..f5c3262 --- /dev/null +++ b/src/UI/WPF/ViewModels/RailAssemblyWorkflowContext.cs @@ -0,0 +1,154 @@ +using System.Collections.Generic; +using System.Numerics; +using Autodesk.Navisworks.Api; + +namespace NavisworksTransport.UI.WPF.ViewModels +{ + internal enum RailAssemblyWorkflowMode + { + None, + CreateNewRailPath, + EditSelectedRail + } + + internal sealed class RailAssemblyWorkflowContext + { + private const string DefaultTerminalObjectName = "未选择"; + private const string DefaultTerminalObjectInfo = "请选择终点处已安装箱体"; + private const string DefaultAssemblyStartPointText = "未选择"; + + private readonly double _defaultReferenceRodLengthInMeters; + private readonly double _defaultReferenceRodDiameterInMeters; + private readonly double _defaultAnchorVerticalOffsetInMeters; + private readonly double _defaultSphereCenterX; + private readonly double _defaultSphereCenterY; + private readonly double _defaultSphereCenterZ; + + public RailAssemblyWorkflowContext( + double defaultReferenceRodLengthInMeters, + double defaultReferenceRodDiameterInMeters, + double defaultAnchorVerticalOffsetInMeters, + double defaultSphereCenterX, + double defaultSphereCenterY, + double defaultSphereCenterZ) + { + _defaultReferenceRodLengthInMeters = defaultReferenceRodLengthInMeters; + _defaultReferenceRodDiameterInMeters = defaultReferenceRodDiameterInMeters; + _defaultAnchorVerticalOffsetInMeters = defaultAnchorVerticalOffsetInMeters; + _defaultSphereCenterX = defaultSphereCenterX; + _defaultSphereCenterY = defaultSphereCenterY; + _defaultSphereCenterZ = defaultSphereCenterZ; + + TerminalObjectName = DefaultTerminalObjectName; + TerminalObjectInfo = DefaultTerminalObjectInfo; + ReferenceRodLengthInMeters = _defaultReferenceRodLengthInMeters; + ReferenceRodDiameterInMeters = _defaultReferenceRodDiameterInMeters; + AnchorVerticalOffsetInMeters = _defaultAnchorVerticalOffsetInMeters; + SphereCenterX = _defaultSphereCenterX; + SphereCenterY = _defaultSphereCenterY; + SphereCenterZ = _defaultSphereCenterZ; + StartPointText = DefaultAssemblyStartPointText; + MountMode = RailMountMode.UnderRail; + InstallationSeedPoints = new List(); + EndFaceSeedPoints = new List(); + } + + public RailAssemblyWorkflowMode WorkflowMode { get; set; } + + public string TerminalObjectName { get; set; } + + public string TerminalObjectInfo { get; set; } + + public double ReferenceRodLengthInMeters { get; set; } + + public double ReferenceRodDiameterInMeters { get; set; } + + public double AnchorVerticalOffsetInMeters { get; set; } + + public double SphereCenterX { get; set; } + + public double SphereCenterY { get; set; } + + public double SphereCenterZ { get; set; } + + public string StartPointText { get; set; } + + public RailMountMode MountMode { get; set; } + + public bool HasTerminalObject { get; set; } + + public bool IsSelectingStartPoint { get; set; } + + public bool IsSelectingEndFacePoints { get; set; } + + public bool IsSelectingInstallationPoint { get; set; } + + public bool HasEndFaceAnalysis { get; set; } + + public bool HasInstallationReference { get; set; } + + public ModelItem TerminalObject { get; set; } + + public Point3D StartPoint { get; set; } + + public Point3D EndFaceCenterPoint { get; set; } + + public Vector3 EndFaceNormal { get; set; } + + public Point3D InstallationPickPoint { get; set; } + + public Point3D InstallationBaseAnchorPoint { get; set; } + + public Point3D InstallationAnchorPoint { get; set; } + + public Vector3 InstallationPlaneNormal { get; set; } + + public Vector3 InstallationPlaneSpanDirection { get; set; } + + public double InstallationOffsetDistanceInMeters { get; set; } + + public string InstallationReferenceRouteId { get; set; } + + public List InstallationSeedPoints { get; } + + public List EndFaceSeedPoints { get; } + + public void ResetEndFaceAnalysis() + { + HasEndFaceAnalysis = false; + EndFaceCenterPoint = null; + EndFaceNormal = default(Vector3); + EndFaceSeedPoints.Clear(); + } + + public void ResetInstallationReference() + { + HasInstallationReference = false; + InstallationPickPoint = null; + InstallationBaseAnchorPoint = null; + InstallationAnchorPoint = null; + InstallationPlaneNormal = default(Vector3); + InstallationPlaneSpanDirection = default(Vector3); + InstallationOffsetDistanceInMeters = 0.0; + InstallationReferenceRouteId = null; + InstallationSeedPoints.Clear(); + AnchorVerticalOffsetInMeters = _defaultAnchorVerticalOffsetInMeters; + } + + public void ResetSession() + { + WorkflowMode = RailAssemblyWorkflowMode.None; + HasTerminalObject = false; + IsSelectingStartPoint = false; + IsSelectingEndFacePoints = false; + IsSelectingInstallationPoint = false; + TerminalObject = null; + StartPoint = Point3D.Origin; + TerminalObjectName = DefaultTerminalObjectName; + TerminalObjectInfo = DefaultTerminalObjectInfo; + StartPointText = DefaultAssemblyStartPointText; + ResetEndFaceAnalysis(); + ResetInstallationReference(); + } + } +} diff --git a/src/UI/WPF/Views/PathEditingView.xaml b/src/UI/WPF/Views/PathEditingView.xaml index 4ea9e67..73e7b6d 100644 --- a/src/UI/WPF/Views/PathEditingView.xaml +++ b/src/UI/WPF/Views/PathEditingView.xaml @@ -488,10 +488,6 @@ NavisworksTransport 路径编辑页签视图 - 采用与动画控制和分层管 Command="{Binding SelectAssemblyInstallationPointForCreateCommand}" Style="{StaticResource SecondaryButtonStyle}" IsEnabled="{Binding CanSelectAssemblyInstallationPointForCreate}"/> -