From a304191b1396e9d6231e65d231163991796907e7 Mon Sep 17 00:00:00 2001 From: tian <11429339@qq.com> Date: Tue, 17 Feb 2026 10:21:35 +0800 Subject: [PATCH] =?UTF-8?q?=E7=A2=B0=E6=92=9E=E6=8A=A5=E5=91=8A=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E5=AF=B9=E7=A2=B0=E6=92=9E=E7=82=B9=E6=88=AA=E5=9B=BE?= =?UTF-8?q?=EF=BC=9B=E7=BA=A0=E6=AD=A3=E6=8F=92=E4=BB=B6=E6=94=B9=E5=90=8D?= =?UTF-8?q?=E9=80=A0=E6=88=90=E7=9A=84=E8=B7=AF=E5=BE=84=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .claude/settings.local.json | 8 +- IFLOW.md | 4 +- QWEN.md | 12 +- TransportPlugin.csproj | 1 + .../System_Architecture_Design.md | 4 +- doc/design/2017/navisworks_api_analysis.md | 2 +- doc/design/2026/Idea.md | 2 +- doc/design/2026/MSI_Installation_Guide.md | 26 ++-- doc/design/Design_Plan.md | 10 +- doc/design/logistics_path.xml | 2 +- doc/requirement/todo_features.md | 2 +- doc/working/2017/动画创建功能开发任务.md | 2 +- doc/working/2017/类别属性功能开发任务.md | 2 +- doc/working/2017/路径构建功能开发任务.md | 2 +- doc/working/cleanup_summary.md | 2 +- ..._import_implementation_summary_20251107.md | 2 +- ...deo_export_ffmpegcore_solution_20250929.md | 2 +- doc/working/第二阶段优化计划_20250814.md | 2 +- .../GenerateCollisionReportCommand.cs | 123 +++++++++++++++-- src/Core/Config/ConfigManager.cs | 2 +- .../ViewModels/CollisionReportViewModel.cs | 103 ++------------- src/Utils/CollisionSceneHelper.cs | 124 ++++++++++++++++++ src/Utils/LogManager.cs | 2 +- src/Utils/PathHelper.cs | 38 ++++-- 24 files changed, 321 insertions(+), 158 deletions(-) create mode 100644 src/Utils/CollisionSceneHelper.cs diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 68d8de7..2142e15 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -12,8 +12,8 @@ "Bash(compile.bat)", "Bash(./compile.bat)", "Bash(./tool/compile.bat:*)", - "Bash(\"C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\MSBuild\\Current\\Bin\\MSBuild.exe\" NavisworksTransportPlugin.csproj /p:Configuration=Debug /p:Platform=AnyCPU /verbosity:minimal)", - "Bash(\"C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\MSBuild\\Current\\Bin\\MSBuild.exe\" NavisworksTransportPlugin.csproj /p:Configuration=Debug /p:Platform=AnyCPU)", + "Bash(\"C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\MSBuild\\Current\\Bin\\MSBuild.exe\" TransportPlugin.csproj /p:Configuration=Debug /p:Platform=AnyCPU /verbosity:minimal)", + "Bash(\"C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\MSBuild\\Current\\Bin\\MSBuild.exe\" TransportPlugin.csproj /p:Configuration=Debug /p:Platform=AnyCPU)", "WebFetch(domain:forums.autodesk.com)", "mcp__serena__search_for_pattern", "mcp__serena__find_symbol", @@ -42,13 +42,13 @@ "Bash(./nuget.exe install:*)", "Bash(dotnet test:*)", "Bash(msbuild:*)", - "Bash(\"C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\MSBuild\\Current\\Bin\\MSBuild.exe\" \"C:\\Users\\Tellme\\apps\\NavisworksTransport\\NavisworksTransportPlugin.csproj\" /p:Configuration=Debug /p:Platform=AnyCPU /verbosity:minimal)", + "Bash(\"C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\MSBuild\\Current\\Bin\\MSBuild.exe\" \"C:\\Users\\Tellme\\apps\\NavisworksTransport\\TransportPlugin.csproj\" /p:Configuration=Debug /p:Platform=AnyCPU /verbosity:minimal)", "Bash(grep:*)", "Bash(find:*)", "mcp__context7__get-library-docs", "Bash(powershell:*)", "mcp__serena__insert_before_symbol", - "Bash(\"C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\MSBuild\\Current\\Bin\\MSBuild.exe\" NavisworksTransportPlugin.csproj /p:Configuration=Debug /p:Platform=AnyCPU /verbosity:normal)", + "Bash(\"C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\MSBuild\\Current\\Bin\\MSBuild.exe\" TransportPlugin.csproj /p:Configuration=Debug /p:Platform=AnyCPU /verbosity:normal)", "Bash(cmd:*)", "WebFetch(domain:twentytwo.space)", "Bash(git add:*)", diff --git a/IFLOW.md b/IFLOW.md index 2771c83..bc016ad 100644 --- a/IFLOW.md +++ b/IFLOW.md @@ -273,7 +273,7 @@ deploy-plugin.bat 1. 编译生成 `TransportPlugin.dll` 2. 将输出目录内容复制到Navisworks插件目录: - `[Navisworks安装路径]\Plugins\NavisworksTransportPlugin\` + `[Navisworks安装路径]\Plugins\TransportPlugin\` 3. 重启Navisworks即可使用 ### 安装包生成 @@ -558,7 +558,7 @@ detection_gap_meters = 0.05 ### 日志位置 日志文件位于: -`[Navisworks安装路径]\Plugins\NavisworksTransportPlugin\logs\debug.log` +`[Navisworks安装路径]\Plugins\TransportPlugin\logs\debug.log` ### 文档资源 diff --git a/QWEN.md b/QWEN.md index 5129752..ff8e467 100644 --- a/QWEN.md +++ b/QWEN.md @@ -46,7 +46,7 @@ NavisworksTransport 是一个针对 Autodesk Navisworks Manage 2026 开发的插 ### 项目结构 ``` -NavisworksTransportPlugin/ +TransportPlugin/ ├── src/ │ ├── Core/ # 核心业务逻辑 │ │ ├── Animation/ # 动画管理 (LogisticsAnimationManager, TimeLinerIntegrationManager) @@ -67,7 +67,7 @@ NavisworksTransportPlugin/ │ └── Legacy/ # 为兼容性保留的旧代码 ├── Properties/ │ └── AssemblyInfo.cs -├── NavisworksTransportPlugin.csproj # 项目文件 +├── TransportPlugin.csproj # 项目文件 └── ... ``` @@ -126,19 +126,19 @@ NavisworksTransportPlugin/ 2. 确保项目引用指向正确的 Navisworks 2026 API DLL 文件(路径在 `.csproj` 文件中定义)。 3. 选择 "Debug" 或 "Release" 配置。 4. 构建项目 (`Ctrl+Shift+B`)。 -5. 输出文件为 `NavisworksTransportPlugin.dll`,位于 `bin\Debug\` 或 `bin\Release\` 目录下。 +5. 输出文件为 `TransportPlugin.dll`,位于 `bin\Debug\` 或 `bin\Release\` 目录下。 ### 部署与安装 -1. 编译生成 `NavisworksTransportPlugin.dll`。 +1. 编译生成 `TransportPlugin.dll`。 2. 插件会自动安装到 Navisworks 插件目录: - `[Navisworks安装路径]\Plugins\NavisworksTransportPlugin\` + `[Navisworks安装路径]\Plugins\TransportPlugin\` 3. 重启 Navisworks 即可在 "附加模块" 选项卡中找到插件。 ### 运行与调试 * 在 Visual Studio 中可以直接调试插件,方法是设置 Navisworks 可执行文件(如 `NwAddinDev.exe` 或 `Navisworks.exe`)为启动外部程序。 -* 插件运行时会在 `%AppData%\Autodesk Navisworks Manage 2026\PluginsData\NavisworksTransportPlugin` 目录下生成日志文件。 +* 插件运行时会在 `%AppData%\Autodesk Navisworks Manage 2026\PluginsData\TransportPlugin` 目录下生成日志文件。 ## 开发约定与实践 diff --git a/TransportPlugin.csproj b/TransportPlugin.csproj index bc7dc70..1f0a6fd 100644 --- a/TransportPlugin.csproj +++ b/TransportPlugin.csproj @@ -331,6 +331,7 @@ + diff --git a/doc/architecture/System_Architecture_Design.md b/doc/architecture/System_Architecture_Design.md index a6a0827..3f0f100 100644 --- a/doc/architecture/System_Architecture_Design.md +++ b/doc/architecture/System_Architecture_Design.md @@ -553,8 +553,8 @@ public class NavisworksIntegration ``` %ProgramFiles%\Autodesk\Navisworks Manage 2026\Plugins\ -└── NavisworksTransportPlugin\ - ├── NavisworksTransportPlugin.dll # 主程序集 +└── TransportPlugin\ + ├── TransportPlugin.dll # 主程序集 ├── RoyT.AStar.dll # A*算法库 ├── Newtonsoft.Json.dll # JSON处理库 ├── Resources\ # 资源文件 diff --git a/doc/design/2017/navisworks_api_analysis.md b/doc/design/2017/navisworks_api_analysis.md index c9a6e20..dbe0b67 100644 --- a/doc/design/2017/navisworks_api_analysis.md +++ b/doc/design/2017/navisworks_api_analysis.md @@ -654,7 +654,7 @@ public class PluginInstaller private static readonly string NavisworksPath = @"%PROGRAMFILES%\Autodesk\Navisworks Manage 2017"; private static readonly string PluginTargetPath = - @"%PROGRAMFILES%\Autodesk\Navisworks Manage 2017\Plugins\NavisworksTransportPlugin"; + @"%PROGRAMFILES%\Autodesk\Navisworks Manage 2017\Plugins\TransportPlugin"; public static bool InstallPlugin() { diff --git a/doc/design/2026/Idea.md b/doc/design/2026/Idea.md index 6770153..90d2205 100644 --- a/doc/design/2026/Idea.md +++ b/doc/design/2026/Idea.md @@ -40,5 +40,5 @@ ## 编译命令 ``` -& "C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Current\Bin\MSBuild.exe" NavisworksTransportPlugin.csproj /p:Configuration=Debug /p:Platform=AnyCPU /verbosity:minimal +& "C:\Program Files\Microsoft Visual Studio\2022\Community\MSBuild\Current\Bin\MSBuild.exe" TransportPlugin.csproj /p:Configuration=Debug /p:Platform=AnyCPU /verbosity:minimal ``` \ No newline at end of file diff --git a/doc/design/2026/MSI_Installation_Guide.md b/doc/design/2026/MSI_Installation_Guide.md index 087e86c..b14082d 100644 --- a/doc/design/2026/MSI_Installation_Guide.md +++ b/doc/design/2026/MSI_Installation_Guide.md @@ -95,7 +95,7 @@ 在 `添加项目输出组` 对话框中: -- 项目:`NavisworksTransportPlugin` +- 项目:`TransportPlugin` - 选择配置:`Release` - 平台:`x64`(**重要:必须与项目平台一致,否则会出现平台不兼容错误**) - 输出类型:选择 `Primary output` @@ -142,7 +142,7 @@ **排除方法:** 1. **通过文件系统编辑器排除** - - 在文件系统编辑器中,展开 `Application Folder` → `Primary output from NavisworksTransportPlugin (Active)` + - 在文件系统编辑器中,展开 `Application Folder` → `Primary output from TransportPlugin (Active)` - 找到需要排除的DLL(如System.Net.Http.dll) - 右键点击该DLL → `属性窗口` - 将 `Exclude` 属性设置为 `TRUE` @@ -190,7 +190,7 @@ 插件需要安装到 Navisworks 的插件目录: -默认路径: C:\ProgramData\Autodesk\Navisworks Manage 2026\plugins\NavisworksTransportPlugin\ +默认路径: C:\ProgramData\Autodesk\Navisworks Manage 2026\plugins\TransportPlugin\ ### 设置方法 @@ -199,7 +199,7 @@ 3. 将AlwaysCreate属性设置为`TRUE` 4. 在属性窗口中设置 `DefaultLocation`: -DefaultLocation = [CommonAppDataFolder]\Autodesk\Navisworks Manage 2026\plugins\NavisworksTransportPlugin +DefaultLocation = [CommonAppDataFolder]\Autodesk\Navisworks Manage 2026\plugins\TransportPlugin ### 目录结构说明 @@ -328,8 +328,8 @@ Visual Studio Installer Projects 会生成两个安装文件,它们各有不 - `{ProductCode}`: 安装日志中的产品代码 3. **验证安装**: - - 检查目录:`C:\ProgramData\Autodesk\Navisworks Manage 2026\plugins\NavisworksTransportPlugin\` - - 确认文件存在:`NavisworksTransportPlugin.dll` + - 检查目录:`C:\ProgramData\Autodesk\Navisworks Manage 2026\plugins\TransportPlugin\` + - 确认文件存在:`TransportPlugin.dll` - 启动Navisworks 2026,检查插件是否加载 --- @@ -397,7 +397,7 @@ pause msiexec /i "bin\Release\NavisworksTransport.Setup.msi" /qn /l*v "logs\install.log" @echo 检查安装结果... -if exist "C:\ProgramData\Autodesk\Navisworks Manage 2026\plugins\NavisworksTransportPlugin\NavisworksTransportPlugin.dll" ( +if exist "C:\ProgramData\Autodesk\Navisworks Manage 2026\plugins\TransportPlugin\TransportPlugin.dll" ( echo ✅ 部署成功! ) else ( echo ❌ 部署失败,请检查安装日志:logs\install.log @@ -416,7 +416,7 @@ pause **解决**: -1. 检查项目引用:`NavisworksTransportPlugin.csproj` +1. 检查项目引用:`TransportPlugin.csproj` 2. 确保所有NuGet包已还原 3. 清理解决方案:`Build` → `Clean Solution` 4. 重新构建:`Build` → `Rebuild Solution` @@ -433,7 +433,7 @@ pause 1. 检查安装目录: - C:\ProgramData\Autodesk\Navisworks Manage 2026\plugins\NavisworksTransportPlugin\ + C:\ProgramData\Autodesk\Navisworks Manage 2026\plugins\TransportPlugin\ 2. 检查Navisworks加载日志: @@ -492,8 +492,8 @@ pause ### 1. 项目组织 NavisworksTransport/ -├── NavisworksTransportPlugin.sln -├── NavisworksTransportPlugin/ # 插件项目 +├── TransportPlugin.sln +├── TransportPlugin/ # 插件项目 ├── NavisworksTransport.Setup/ # 安装项目 ├── doc/design/2026/ │ └── MSI_Installation_Guide.md @@ -529,7 +529,7 @@ NavisworksTransport/ **仅包含必要的文件:** -- 自定义应用程序DLL(NavisworksTransportPlugin.dll) +- 自定义应用程序DLL(TransportPlugin.dll) - 第三方库DLL(如SQLite.NET.dll等) - 配置文件(config.json等) - 资源文件(图标、文档等) @@ -590,7 +590,7 @@ NavisworksTransport/ NavisworksTransport.Setup/ ├── 文件系统编辑器 │ ├── Application Folder/ -│ │ ├── Primary output from NavisworksTransportPlugin (Active) +│ │ ├── Primary output from TransportPlugin (Active) │ │ └── license.txt └── 系统必备组件 ├── Microsoft .NET Framework 4.8 (x86 and x64) diff --git a/doc/design/Design_Plan.md b/doc/design/Design_Plan.md index c6dc5cf..348a60a 100644 --- a/doc/design/Design_Plan.md +++ b/doc/design/Design_Plan.md @@ -203,22 +203,22 @@ 4.2 构建与产物 - 解决方案:NavisworksTransport.sln; -- 项目:NavisworksTransportPlugin.csproj; -- 产物:NavisworksTransportPlugin.dll(bin/Debug 或 bin/Release)。 +- 项目:TransportPlugin.csproj; +- 产物:TransportPlugin.dll(bin/Debug 或 bin/Release)。 4.3 安装与部署流程 - 自动安装(一键安装): 1) 识别 Navisworks 安装目录; - 2) 将插件 DLL 与必要资源复制到 [Navisworks安装路径]\Plugins\NavisworksTransportPlugin\; + 2) 将插件 DLL 与必要资源复制到 [Navisworks安装路径]\Plugins\TransportPlugin\; 3) 注册菜单/配置(如需); - 手动安装: - 1) 复制 NavisworksTransportPlugin.dll 至上述目录; + 1) 复制 TransportPlugin.dll 至上述目录; 2) 重启 Navisworks,在“附加模块”中查看“物流路径规划”。 4.4 运行配置 -- 日志输出:%AppData%\Autodesk Navisworks Manage 2017\PluginsData\NavisworksTransportPlugin(按 QWEN 中 2026 路径作适配); +- 日志输出:%AppData%\Autodesk Navisworks Manage 2017\PluginsData\TransportPlugin(按 QWEN 中 2026 路径作适配); - 配置切换: - 自动路径规划模式网格参数(cellSize、objectSize、safetyMargin、objectHeight); - 2.5D/BoundingBox 模式选择(自动/强制选项)。 diff --git a/doc/design/logistics_path.xml b/doc/design/logistics_path.xml index 295ef83..0e0c0ad 100644 --- a/doc/design/logistics_path.xml +++ b/doc/design/logistics_path.xml @@ -1,7 +1,7 @@ PRJ-12345 Main Hospital Construction Path for Delivery Truck #1 and Crane #2 diff --git a/doc/requirement/todo_features.md b/doc/requirement/todo_features.md index b7cb2c5..ecb23c1 100644 --- a/doc/requirement/todo_features.md +++ b/doc/requirement/todo_features.md @@ -15,7 +15,7 @@ 3. [ ] (优化)考虑是否给截图按碰撞记录组织成子文件夹 4. [ ] (优化)研究如何利用ClashDetective的多线程(支持打开多线程) 5. [x] (优化)给每个检测到的碰撞对象增加单独视角(45度,右上方) -6. [ ] (优化)点击碰撞列表的碰撞详情时,要把运动物体移动到位,查看碰撞情况 +6. [x] (优化)点击碰撞列表的碰撞详情时,要把运动物体移动到位,查看碰撞情况 ### [2026/2/6] diff --git a/doc/working/2017/动画创建功能开发任务.md b/doc/working/2017/动画创建功能开发任务.md index 55a2846..827768a 100644 --- a/doc/working/2017/动画创建功能开发任务.md +++ b/doc/working/2017/动画创建功能开发任务.md @@ -28,7 +28,7 @@ NavisworksTransport是一个Navisworks 2017插件项目,旨在实现物流路 2. **关键文件发现**: - `PathAnimationManager.cs`:已实现但使用了不可用的API - `NavigationMapWindow.cs`:已集成动画控制面板和事件处理 - - `NavisworksTransportPlugin.csproj`:已包含PathAnimationManager.cs + - `TransportPlugin.csproj`:已包含PathAnimationManager.cs 3. **API限制发现**: - Navisworks 2017项目引用:`Autodesk.Navisworks.Api.dll`、`Autodesk.Navisworks.ComApi.dll`等 diff --git a/doc/working/2017/类别属性功能开发任务.md b/doc/working/2017/类别属性功能开发任务.md index 5e32ef5..9a94ab9 100644 --- a/doc/working/2017/类别属性功能开发任务.md +++ b/doc/working/2017/类别属性功能开发任务.md @@ -302,7 +302,7 @@ cpropcates.SetUserDefined(0, "物流分类", "Logistics_InternalName", newcate); * [2025-01-11 当前时间] * 步骤:4. 更新项目引用 - * 修改:在NavisworksTransportPlugin.csproj中添加System.Drawing引用 + * 修改:在TransportPlugin.csproj中添加System.Drawing引用 * 更改摘要:验证现有COM API引用完整性,添加缺失的System.Drawing引用以支持UI控件的Font、Color等类型,确保编译所需的所有引用都已包含 * 原因:执行计划步骤4 * 阻碍:无 diff --git a/doc/working/2017/路径构建功能开发任务.md b/doc/working/2017/路径构建功能开发任务.md index 0ad4d90..1c4fd83 100644 --- a/doc/working/2017/路径构建功能开发任务.md +++ b/doc/working/2017/路径构建功能开发任务.md @@ -156,7 +156,7 @@ public class PathRoute * [2024-12-22 01:32:15] * 步骤:9. 添加路径验证/优化功能 - * 修改:PathPlanningManager.cs(添加路径验证和优化方法、无参构造函数、ShowPathPlanningInterface和AddRoute方法)、PathPlanningModels.cs(添加验证优化数据结构)、NavigationMapWindow.cs(添加验证优化UI)、NavisworksTransportPlugin.csproj(添加源文件引用) + * 修改:PathPlanningManager.cs(添加路径验证和优化方法、无参构造函数、ShowPathPlanningInterface和AddRoute方法)、PathPlanningModels.cs(添加验证优化数据结构)、NavigationMapWindow.cs(添加验证优化UI)、TransportPlugin.csproj(添加源文件引用) * 更改摘要:成功实现路径验证和优化功能,包括基本结构验证、几何有效性验证、通道约束验证、碰撞检测、可达性验证,以及路径优化算法(移除重复点、路径平滑、角度优化、通道中心调整)。修复了MainPlugin.cs兼容性问题,确保项目能正确编译 * 原因:执行计划步骤 9(包含微小修正) * 阻碍:无 diff --git a/doc/working/cleanup_summary.md b/doc/working/cleanup_summary.md index d860470..36af9e4 100644 --- a/doc/working/cleanup_summary.md +++ b/doc/working/cleanup_summary.md @@ -76,7 +76,7 @@ ### 最终编译结果 ``` -NavisworksTransportPlugin -> bin\Debug\NavisworksTransportPlugin.dll +TransportPlugin -> bin\Debug\TransportPlugin.dll Build successful! ``` diff --git a/doc/working/json_import_implementation_summary_20251107.md b/doc/working/json_import_implementation_summary_20251107.md index a765a22..0712fbd 100644 --- a/doc/working/json_import_implementation_summary_20251107.md +++ b/doc/working/json_import_implementation_summary_20251107.md @@ -69,7 +69,7 @@ **编译结果**: ✅ 成功 - 仅有警告,无错误 -- 生成的DLL: `bin/Debug/NavisworksTransportPlugin.dll` +- 生成的DLL: `bin/Debug/TransportPlugin.dll` --- diff --git a/doc/working/video_export_ffmpegcore_solution_20250929.md b/doc/working/video_export_ffmpegcore_solution_20250929.md index cee1d47..6aa2ddf 100644 --- a/doc/working/video_export_ffmpegcore_solution_20250929.md +++ b/doc/working/video_export_ffmpegcore_solution_20250929.md @@ -268,7 +268,7 @@ private async void OnExportVideoButtonClick(object sender, RoutedEventArgs e) ### 文件分发清单 ``` NavisworksTransport插件目录/ -├── NavisworksTransportPlugin.dll(主插件) +├── TransportPlugin.dll(主插件) ├── FFMpegCore.dll(NuGet自动处理) ├── Instances.dll(依赖项) ├── System.Text.Json.dll(依赖项) diff --git a/doc/working/第二阶段优化计划_20250814.md b/doc/working/第二阶段优化计划_20250814.md index 6c26b79..6df2427 100644 --- a/doc/working/第二阶段优化计划_20250814.md +++ b/doc/working/第二阶段优化计划_20250814.md @@ -325,7 +325,7 @@ public class ChannelSlopeInfo #### **编译验证** ✅ -- ✅ 项目编译成功:`NavisworksTransportPlugin.dll` +- ✅ 项目编译成功:`TransportPlugin.dll` - ✅ 新文件已添加到项目文件中 - ✅ 语法错误已修复 - ✅ 依赖关系正确配置 diff --git a/src/Commands/GenerateCollisionReportCommand.cs b/src/Commands/GenerateCollisionReportCommand.cs index 94e5730..d7a8c3b 100644 --- a/src/Commands/GenerateCollisionReportCommand.cs +++ b/src/Commands/GenerateCollisionReportCommand.cs @@ -6,6 +6,8 @@ using System.Threading; using System.Threading.Tasks; using Autodesk.Navisworks.Api; using Autodesk.Navisworks.Api.Clash; +using NavisworksTransport.Core; +using NavisworksTransport.Core.Animation; using NavisworksTransport.Utils; using NavisworksTransport.UI.WPF.Views; @@ -278,6 +280,7 @@ namespace NavisworksTransport.Commands UpdateProgress(95, "加载碰撞报告截图..."); // 加载多截图数据(从新的截图表) + bool loadedScreenshotsFromDatabase = false; var pathDatabase = PathPlanningManager.Instance?.GetPathDatabase(); if (pathDatabase != null) { @@ -306,6 +309,7 @@ namespace NavisworksTransport.Commands Description = r.Description, SortOrder = r.SortOrder }).ToList(); + loadedScreenshotsFromDatabase = true; LogManager.Info($"从数据库加载了 {result.Screenshots.Count} 张截图 (ResultId={testRecord.Id})"); } @@ -331,17 +335,25 @@ namespace NavisworksTransport.Commands } } - // 如果没有加载到任何截图,生成一张默认截图 + // 检查并创建路径子目录(用于存放该路径的所有截图) + string pathDir = System.IO.Path.Combine(PathHelper.GetScreenshotDirectory(), + string.Format("{0}_{1}", result.RouteId.Substring(0, 8), result.PathName ?? "collision")); + PathHelper.EnsureDirectoryExists(pathDir); + + // 先生成默认截图(整条路径的概览) if (result.Screenshots == null || result.Screenshots.Count == 0) { try { - string screenshotPath = PathHelper.GenerateSceneScreenshot( - result.PathName ?? "collision", + UpdateProgress(92, "生成默认路径截图..."); + + string screenshotPath = PathHelper.GenerateSceneScreenshotToDirectory( + pathDir, + "path", 1920, 1080, System.Drawing.Imaging.ImageFormat.Jpeg, - "collision" + "overview" ); if (screenshotPath != null) @@ -354,17 +366,18 @@ namespace NavisworksTransport.Commands Format = "JPG", Width = 1920, Height = 1080, - CaptureTime = DateTime.Now + CaptureTime = DateTime.Now, + Description = "路径概览", + SortOrder = 0 } }; - LogManager.Info($"自动生成默认截图: {screenshotPath}"); + LogManager.Info(string.Format("生成默认截图: {0}", screenshotPath)); - // 保存截图到数据库(新表支持多截图) + // 保存截图到数据库 if (pathDatabase != null && result.ResultId > 0) { try { - // 保存到新表 CollisionReportScreenshots int screenshotId = pathDatabase.SaveCollisionReportScreenshot( result.ResultId, screenshotPath, @@ -372,20 +385,106 @@ namespace NavisworksTransport.Commands 1920, 1080, 0, - "默认场景截图" + "路径概览" ); - LogManager.Info($"默认截图已保存到数据库: ScreenshotId={screenshotId}, ResultId={result.ResultId}, Path={screenshotPath}"); + LogManager.Info(string.Format("默认截图已保存到数据库: ScreenshotId={0}", screenshotId)); } catch (Exception dbEx) { - LogManager.Error($"保存默认截图到数据库失败: {dbEx.Message}"); + LogManager.Error(string.Format("保存默认截图到数据库失败: {0}", dbEx.Message)); } } } } catch (Exception ex) { - LogManager.Error($"自动生成碰撞场景截图失败: {ex.Message}"); + LogManager.Error(string.Format("生成默认截图失败: {0}", ex.Message)); + } + } + + // 再生成每个碰撞对的单独截图(需要移动物体到碰撞位置) + // 只有未从数据库加载截图时才生成 + if (!loadedScreenshotsFromDatabase && collisionData.AllCollisions?.Count > 0) + { + try + { + UpdateProgress(94, string.Format("正在为 {0} 个碰撞对生成视角截图...", collisionData.AllCollisions.Count)); + + int sortOrder = result.Screenshots?.Count ?? 0; + int successCount = 0; + + // 保存动画物体原始状态(用于截图后恢复) + ModelItem animatedObject = null; + ModelItemTransformHelper.ObjectStateSnapshot savedObjectState = null; + + // 找到第一个有位置信息的碰撞来获取动画物体 + foreach (var c in collisionData.AllCollisions) + { + if (c.Item1 != null && c.HasPositionInfo) + { + animatedObject = c.Item1; + savedObjectState = CollisionSceneHelper.SaveAnimatedObjectState(animatedObject); + break; + } + } + + for (int i = 0; i < collisionData.AllCollisions.Count; i++) + { + var collision = collisionData.AllCollisions[i]; + try + { + // 使用通用方法移动物体到碰撞位置并聚焦 + CollisionSceneHelper.MoveToCollisionAndFocus(collision, animatedObject, waitForViewUpdate: true); + + // 生成截图 + string screenshotPath = PathHelper.GenerateSceneScreenshotToDirectory( + pathDir, "collision", 1920, 1080, + System.Drawing.Imaging.ImageFormat.Jpeg, string.Format("collision_{0:D3}", i + 1)); + + if (screenshotPath != null) + { + string item1Name = collision.Item1 != null ? collision.Item1.DisplayName : "物体1"; + string item2Name = collision.Item2 != null ? collision.Item2.DisplayName : "物体2"; + string description = string.Format("碰撞对 {0}/{1}: {2} vs {3}", i + 1, collisionData.AllCollisions.Count, item1Name, item2Name); + + var screenshot = new CollisionReportScreenshot + { + FilePath = screenshotPath, + Format = "JPG", + Width = 1920, + Height = 1080, + CaptureTime = DateTime.Now, + Description = description, + SortOrder = sortOrder++ + }; + result.Screenshots.Add(screenshot); + + // 保存到数据库 + if (pathDatabase != null && result.ResultId > 0) + { + pathDatabase.SaveCollisionReportScreenshot(result.ResultId, screenshotPath, "JPG", + 1920, 1080, screenshot.SortOrder, description); + } + + successCount++; + } + + Thread.Sleep(50); // 短暂延迟 + } + catch (Exception ex) + { + LogManager.Error(string.Format("生成碰撞对 {0} 截图失败: {1}", i + 1, ex.Message)); + } + } + + // 恢复动画物体到原始状态 + CollisionSceneHelper.RestoreAnimatedObjectState(animatedObject, savedObjectState); + + LogManager.Info(string.Format("已生成 {0}/{1} 个碰撞对视角截图", successCount, collisionData.AllCollisions.Count)); + } + catch (Exception ex) + { + LogManager.Error(string.Format("生成碰撞对视角截图失败: {0}", ex.Message)); } } diff --git a/src/Core/Config/ConfigManager.cs b/src/Core/Config/ConfigManager.cs index d5a3df5..02b8e6f 100644 --- a/src/Core/Config/ConfigManager.cs +++ b/src/Core/Config/ConfigManager.cs @@ -107,7 +107,7 @@ namespace NavisworksTransport.Core.Config "Autodesk", "Navisworks Manage 2026", "plugins", - "NavisworksTransportPlugin", + "TransportPlugin", "config.toml" ); } diff --git a/src/UI/WPF/ViewModels/CollisionReportViewModel.cs b/src/UI/WPF/ViewModels/CollisionReportViewModel.cs index 5c94831..84b171b 100644 --- a/src/UI/WPF/ViewModels/CollisionReportViewModel.cs +++ b/src/UI/WPF/ViewModels/CollisionReportViewModel.cs @@ -1244,52 +1244,18 @@ namespace NavisworksTransport.UI.WPF.ViewModels { var collisionData = collisionItem.CollisionData; - // 获取被撞对象(Item2是运动物体碰撞的静态对象) - var hitObject = collisionData.Item2; - if (hitObject == null) - { - // 如果没有Item2,使用Item1 - hitObject = collisionData.Item1; - } - - if (hitObject != null) - { - // 清除之前的高亮 - ModelHighlightHelper.ClearAllHighlights(); - - // 高亮被撞对象(使用碰撞检测结果专用红色) - ModelHighlightHelper.HighlightItems(ModelHighlightHelper.ClashDetectiveResultsCategory, new[] { hitObject }); - - // 聚焦到被撞对象 - ViewpointHelper.FocusOnModelItem(hitObject, viewAngleDegrees: 60.0, targetViewRatio: 0.25); - - LogManager.Info($"聚焦到被撞对象: {collisionItem.Title}"); - } - - // 还原运动物体到碰撞时的位置和朝向 - LogManager.Debug($"[碰撞详情点击] Item1={collisionData.Item1?.DisplayName}, HasPositionInfo={collisionData.HasPositionInfo}, Item1Position={collisionData.Item1Position}"); + // 首次查看碰撞时保存运动物体状态 if (collisionData.Item1 != null && collisionData.HasPositionInfo && collisionData.Item1Position != null) { - // 首次查看碰撞时保存运动物体状态 if (_savedAnimatedObjectState == null || _currentAnimatedObject != collisionData.Item1) { _currentAnimatedObject = collisionData.Item1; - // 🔥 关键:从 PathAnimationManager 获取当前实际朝向 - // 因为 Transform 返回的是CAD原始朝向,不是当前实际朝向 - var pam = PathAnimationManager.GetInstance(); - var currentYaw = pam.CurrentYaw; - var transformYaw = ModelItemTransformHelper.GetYawFromTransform(collisionData.Item1.Transform); - LogManager.Debug($"[碰撞查看调试] PathAnimationManager.CurrentYaw={currentYaw * 180 / Math.PI:F2}°, Transform.Yaw={transformYaw * 180 / Math.PI:F2}°"); - _savedAnimatedObjectState = ModelItemTransformHelper.SaveObjectState(collisionData.Item1, currentYaw); - LogManager.Info($"[碰撞查看] 已保存运动物体原始状态: pos=({_savedAnimatedObjectState.Position.X:F2},{_savedAnimatedObjectState.Position.Y:F2},{_savedAnimatedObjectState.Position.Z:F2}), yaw={currentYaw * 180 / Math.PI:F2}°"); + _savedAnimatedObjectState = CollisionSceneHelper.SaveAnimatedObjectState(collisionData.Item1); } - - RestoreAnimatedObjectToCollisionPosition(collisionData); - } - else - { - LogManager.Warning($"[碰撞详情点击] 无法还原运动物体位置: Item1={(collisionData.Item1 != null ? "有" : "无")}, HasPositionInfo={collisionData.HasPositionInfo}, Item1Position={(collisionData.Item1Position != null ? "有" : "无")}"); } + + // 使用通用方法移动并聚焦到碰撞位置 + CollisionSceneHelper.MoveToCollisionAndFocus(collisionData, _currentAnimatedObject, waitForViewUpdate: false); } catch (Exception ex) { @@ -1297,65 +1263,16 @@ namespace NavisworksTransport.UI.WPF.ViewModels } } - /// - /// 将运动物体还原到碰撞时的位置和朝向 - /// 使用ModelItemTransformHelper.MoveItemToPositionAndYaw从CAD原始状态精确定位 - /// - private void RestoreAnimatedObjectToCollisionPosition(CollisionResult collisionData) - { - try - { - var animatedObject = collisionData.Item1; - var targetPosition = collisionData.Item1Position; - var targetYaw = collisionData.Item1YawRadians; - - if (animatedObject == null || targetPosition == null) - { - LogManager.Warning("[还原碰撞位置] 运动物体或位置信息为空"); - return; - } - - // 计算目标底面位置(Item1Position存储的是包围盒中心,需要转换为底面) - var currentBounds = animatedObject.BoundingBox(); - double halfHeight = (currentBounds.Max.Z - currentBounds.Min.Z) / 2.0; - var targetGroundPosition = new Point3D( - targetPosition.X, - targetPosition.Y, - targetPosition.Z - halfHeight - ); - - // 使用工具方法从CAD原始状态移动到目标位置 - ModelItemTransformHelper.MoveItemToPositionAndYaw(animatedObject, targetGroundPosition, targetYaw); - - LogManager.Info($"[还原碰撞位置] 运动物体已移动到碰撞位置: ({targetGroundPosition.X:F2}, {targetGroundPosition.Y:F2}, {targetGroundPosition.Z:F2}), 朝向: {targetYaw * 180 / Math.PI:F2}°"); - } - catch (Exception ex) - { - LogManager.Error($"[还原碰撞位置] 失败: {ex.Message}", ex); - } - } - /// /// 恢复运动物体到原始状态(查看碰撞前保存的状态) /// public void RestoreAnimatedObjectToOriginalState() { - try - { - if (_currentAnimatedObject != null && _savedAnimatedObjectState != null) - { - ModelItemTransformHelper.RestoreObjectState(_currentAnimatedObject, _savedAnimatedObjectState); - LogManager.Info("[碰撞查看] 运动物体已恢复到原始状态"); - - // 清除保存的状态 - _savedAnimatedObjectState = null; - _currentAnimatedObject = null; - } - } - catch (Exception ex) - { - LogManager.Error($"[恢复运动物体状态] 失败: {ex.Message}", ex); - } + CollisionSceneHelper.RestoreAnimatedObjectState(_currentAnimatedObject, _savedAnimatedObjectState); + + // 清除保存的状态 + _savedAnimatedObjectState = null; + _currentAnimatedObject = null; } #endregion diff --git a/src/Utils/CollisionSceneHelper.cs b/src/Utils/CollisionSceneHelper.cs new file mode 100644 index 0000000..1178eaa --- /dev/null +++ b/src/Utils/CollisionSceneHelper.cs @@ -0,0 +1,124 @@ +using System; +using Autodesk.Navisworks.Api; +using NavisworksTransport.Core; +using NavisworksTransport.Core.Animation; + +namespace NavisworksTransport.Utils +{ + /// + /// 碰撞场景辅助类 + /// 提供碰撞场景还原和截图的通用功能 + /// + public static class CollisionSceneHelper + { + /// + /// 将动画物体移动到碰撞位置并聚焦到碰撞场景 + /// + /// 碰撞结果 + /// 动画物体(运动物体) + /// 是否等待视图更新 + public static void MoveToCollisionAndFocus(CollisionResult collision, ModelItem animatedObject, bool waitForViewUpdate = true) + { + if (collision == null) return; + + try + { + // 获取被撞对象(Item2是运动物体碰撞的静态对象) + var hitObject = collision.Item2 ?? collision.Item1; + + if (hitObject != null) + { + // 清除之前的高亮 + ModelHighlightHelper.ClearAllHighlights(); + + // 高亮被撞对象(使用碰撞检测结果专用红色) + ModelHighlightHelper.HighlightItems(ModelHighlightHelper.ClashDetectiveResultsCategory, new[] { hitObject }); + + // 聚焦到被撞对象 + ViewpointHelper.FocusOnModelItem(hitObject, viewAngleDegrees: 60.0, targetViewRatio: 0.25); + + LogManager.Info(string.Format("聚焦到被撞对象: {0}", hitObject.DisplayName)); + } + + // 移动动画物体到碰撞位置 + if (animatedObject != null && collision.Item1 == animatedObject && collision.HasPositionInfo && collision.Item1Position != null) + { + // 计算目标底面位置(Item1Position存储的是包围盒中心,需要转换为底面) + var bounds = animatedObject.BoundingBox(); + double halfHeight = (bounds.Max.Z - bounds.Min.Z) / 2.0; + var targetGroundPosition = new Point3D( + collision.Item1Position.X, + collision.Item1Position.Y, + collision.Item1Position.Z - halfHeight + ); + + // 使用工具方法从CAD原始状态移动到目标位置 + ModelItemTransformHelper.MoveItemToPositionAndYaw(animatedObject, targetGroundPosition, collision.Item1YawRadians); + + LogManager.Info(string.Format("运动物体已移动到碰撞位置: ({0:F2}, {1:F2}, {2:F2}), 朝向: {3:F2}°", + targetGroundPosition.X, targetGroundPosition.Y, targetGroundPosition.Z, + collision.Item1YawRadians * 180 / Math.PI)); + } + + // 等待视图更新 + if (waitForViewUpdate) + { + ViewpointHelper.WaitForViewUpdate(); + } + } + catch (Exception ex) + { + LogManager.Error(string.Format("移动并聚焦到碰撞位置失败: {0}", ex.Message), ex); + } + } + + /// + /// 保存动画物体当前状态 + /// + /// 动画物体 + /// 状态快照 + public static ModelItemTransformHelper.ObjectStateSnapshot SaveAnimatedObjectState(ModelItem animatedObject) + { + if (animatedObject == null) return null; + + try + { + // 从PathAnimationManager获取当前实际朝向 + var pam = PathAnimationManager.GetInstance(); + var currentYaw = pam.CurrentYaw; + var state = ModelItemTransformHelper.SaveObjectState(animatedObject, currentYaw); + + LogManager.Info(string.Format("已保存动画物体状态: {0}, 位置=({1:F2},{2:F2},{3:F2}), 朝向={4:F2}°", + animatedObject.DisplayName, state.Position.X, state.Position.Y, state.Position.Z, + currentYaw * 180 / Math.PI)); + + return state; + } + catch (Exception ex) + { + LogManager.Error(string.Format("保存动画物体状态失败: {0}", ex.Message), ex); + return null; + } + } + + /// + /// 恢复动画物体到保存的状态 + /// + /// 动画物体 + /// 状态快照 + public static void RestoreAnimatedObjectState(ModelItem animatedObject, ModelItemTransformHelper.ObjectStateSnapshot state) + { + if (animatedObject == null || state == null) return; + + try + { + ModelItemTransformHelper.RestoreObjectState(animatedObject, state); + LogManager.Info(string.Format("动画物体已恢复到原始状态: {0}", animatedObject.DisplayName)); + } + catch (Exception ex) + { + LogManager.Error(string.Format("恢复动画物体状态失败: {0}", ex.Message), ex); + } + } + } +} diff --git a/src/Utils/LogManager.cs b/src/Utils/LogManager.cs index 865f0ab..ef74992 100644 --- a/src/Utils/LogManager.cs +++ b/src/Utils/LogManager.cs @@ -22,7 +22,7 @@ namespace NavisworksTransport { private static readonly string _logFilePath = Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), - "Autodesk", "Navisworks Manage 2026", "plugins", "NavisworksTransportPlugin", "logs", "debug.log"); + "Autodesk", "Navisworks Manage 2026", "plugins", "TransportPlugin", "logs", "debug.log"); private static readonly object _lockObject = new object(); diff --git a/src/Utils/PathHelper.cs b/src/Utils/PathHelper.cs index 2ea2007..8f0c53e 100644 --- a/src/Utils/PathHelper.cs +++ b/src/Utils/PathHelper.cs @@ -21,7 +21,7 @@ namespace NavisworksTransport.Utils "Autodesk", "Navisworks Manage 2026", "plugins", - "NavisworksTransportPlugin" + "TransportPlugin" ); } @@ -147,20 +147,42 @@ namespace NavisworksTransport.Utils /// 文件名前缀 /// 截图文件路径,失败返回null public static string GenerateSceneScreenshot(string sceneName, int width, int height, ImageFormat format, string prefix = "scene") + { + return GenerateSceneScreenshotInternal(GetScreenshotDirectory(), sceneName, width, height, format, prefix); + } + + /// + /// 生成场景截图到指定目录 + /// + /// 输出目录 + /// 场景名称 + /// 图像宽度 + /// 图像高度 + /// 图像格式 + /// 文件名前缀 + /// 截图文件路径,失败返回null + public static string GenerateSceneScreenshotToDirectory(string outputDirectory, string sceneName, int width, int height, ImageFormat format, string prefix = "scene") + { + return GenerateSceneScreenshotInternal(outputDirectory, sceneName, width, height, format, prefix); + } + + /// + /// 生成场景截图内部实现 + /// + private static string GenerateSceneScreenshotInternal(string outputDirectory, string sceneName, int width, int height, ImageFormat format, string prefix) { try { - LogManager.Info($"开始生成场景截图: {prefix}_{sceneName}, 尺寸={width}x{height}, 格式={ImageFormatToExtension(format)}"); + LogManager.Info(string.Format("开始生成场景截图: {0}_{1}, 尺寸={2}x{3}, 目录={4}", prefix, sceneName, width, height, outputDirectory)); // 1. 确保截图目录存在 - string screenshotDir = GetScreenshotDirectory(); - EnsureDirectoryExists(screenshotDir); + EnsureDirectoryExists(outputDirectory); // 2. 生成文件名 string extension = ImageFormatToExtension(format); string sanitizedName = SanitizeFileName(sceneName); - string filename = GenerateTimestampedFileName($"{prefix}_{sanitizedName}", extension); - string screenshotPath = Path.Combine(screenshotDir, filename); + string filename = GenerateTimestampedFileName(string.Format("{0}_{1}", prefix, sanitizedName), extension); + string screenshotPath = Path.Combine(outputDirectory, filename); // 3. 调用截图生成器(复用 NavigationMapGenerator) var generator = new Core.NavigationMapGenerator(); @@ -174,12 +196,12 @@ namespace NavisworksTransport.Utils // 4. 保存截图 generator.SaveNavigationMapImage(bitmap, screenshotPath, format); - LogManager.Info($"场景截图已生成: {screenshotPath}"); + LogManager.Info(string.Format("场景截图已生成: {0}", screenshotPath)); return screenshotPath; } catch (Exception ex) { - LogManager.Error($"生成场景截图失败: {ex.Message}", ex); + LogManager.Error(string.Format("生成场景截图失败: {0}", ex.Message), ex); return null; } }