From 3cc840b183b594664954762024b3355be9fedf1f Mon Sep 17 00:00:00 2001 From: tian <11429339@qq.com> Date: Fri, 10 Oct 2025 09:44:29 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=A0=E6=8E=89serena=E7=9A=84=E6=8F=90?= =?UTF-8?q?=E7=A4=BA=E8=AF=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .claude/settings.local.json | 3 +- CLAUDE.md | 232 +++++++++++++++--------------------- 2 files changed, 96 insertions(+), 139 deletions(-) diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 9263755..92707e1 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -159,7 +159,8 @@ "Read(//c/Program Files/Autodesk/Navisworks Manage 2026/**)", "Bash(where:*)", "Read(//c/Users/Tellme/Pictures/Screenshots/**)", - "Bash(./deploy-plugin.bat)" + "Bash(./deploy-plugin.bat)", + "Read(//c/Users/Tellme/**)" ], "deny": [], "additionalDirectories": [ diff --git a/CLAUDE.md b/CLAUDE.md index 510349a..93b08dc 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -42,6 +42,100 @@ The system implements multiple Navisworks plugin types working together: - **GeometryExtractor.cs**: Spatial analysis and bounding box calculations - **FloorDetector.cs**: Automatic floor/level detection for multi-story logistics +#### ⚠️ 模型单位系统 - 极其重要! + +**核心原则:网格地图生成和路径规划中统一使用模型单位(Model Units),不使用米制单位** + +本项目中出现的大量bug都源于混淆模型单位和米制单位。必须严格遵守以下规则: + +**1. 单位转换原则** +```csharp +// ✅ 正确做法:在函数入口处一次性转换所有参数 +public GridMap GenerateFromBIM(BoundingBox3D bounds, double cellSize, double vehicleRadius, ...) +{ + // 第一步:立即转换所有米制参数为模型单位 + double metersToModelUnitsConversionFactor = UnitsConverter.GetMetersToUnitsConversionFactor(Application.ActiveDocument.Units); + double cellSizeInModelUnits = cellSize * metersToModelUnitsConversionFactor; + double vehicleRadiusInModelUnits = vehicleRadius * metersToModelUnitsConversionFactor; + double safetyMarginInModelUnits = safetyMargin * metersToModelUnitsConversionFactor; + double vehicleHeightInModelUnits = vehicleHeight * metersToModelUnitsConversionFactor; + + // 之后所有计算都使用模型单位变量 + var gridMap = new GridMap(bounds, cellSizeInModelUnits); +} + +// ❌ 错误做法:在计算过程中混用米制和模型单位 +``` + +**2. 网格地图内部统一使用模型单位** + +GridMapGenerator和AutoPathFinder中的所有空间计算都基于模型单位: +- 网格单元大小(CellSize):模型单位 +- 车辆半径(VehicleRadius):模型单位 +- 安全间隙(SafetyMargin):模型单位 +- 车辆高度(VehicleHeight):模型单位 +- 扫描高度(ScanHeight):模型单位 +- 膨胀半径(InflationRadius):模型单位 +- 高度差阈值(MaxHeightDiff):模型单位 +- 网格坐标和世界坐标转换:模型单位 + +**3. 常见错误模式及避免方法** + +```csharp +// ❌ 错误:直接使用常量米制值 +private const double MAX_HEIGHT_DIFF = 0.35; // 这是米! +if (heightDiff > MAX_HEIGHT_DIFF) // Bug!heightDiff是模型单位 + +// ✅ 正确:转换后使用 +private const double MAX_HEIGHT_DIFF_METERS = 0.35; // 明确标注单位 +double maxHeightDiffInModelUnits = MAX_HEIGHT_DIFF_METERS * UnitsConverter.GetMetersToUnitsConversionFactor(); +if (heightDiff > maxHeightDiffInModelUnits) // 正确! + +// ❌ 错误:在循环中重复转换 +for (int i = 0; i < count; i++) { + double modelValue = meterValue * UnitsConverter.GetMetersToUnitsConversionFactor(); // 性能浪费 +} + +// ✅ 正确:提前转换一次 +double metersToModelUnits = UnitsConverter.GetMetersToUnitsConversionFactor(); +double modelValue = meterValue * metersToModelUnits; // 转换一次 +for (int i = 0; i < count; i++) { + // 使用modelValue进行计算 +} +``` + +**4. 变量命名约定** + +为了避免混淆,强制使用以下命名规范: +- 米制变量:使用`Meters`后缀,如`vehicleHeightMeters`、`cellSizeMeters` +- 模型单位变量:使用`InModelUnits`后缀,如`vehicleHeightInModelUnits`、`cellSizeInModelUnits` +- 转换系数:统一命名为`metersToModelUnitsConversionFactor` + +**5. 关键API的单位约定** + +```csharp +// Navisworks API返回的坐标和尺寸都是模型单位 +BoundingBox3D bbox = modelItem.BoundingBox(); // 模型单位 +Point3D worldPos = gridMap.GridToWorld3D(gridPos); // 模型单位 + +// 用户配置的参数通常是米制 +double cellSize = 0.5; // 米,需要转换 +double vehicleRadius = 0.3; // 米,需要转换 +``` + +**6. 日志输出最佳实践** + +```csharp +// ✅ 正确:在日志中明确标注单位 +LogManager.Info($"网格大小: {cellSize}米 → {cellSizeInModelUnits:F2}模型单位"); +LogManager.Info($"高度差阈值: {MAX_HEIGHT_DIFF_METERS}米 = {maxHeightDiffInModelUnits:F2}模型单位"); + +// ❌ 错误:日志中不标注单位,容易造成误解 +LogManager.Info($"网格大小: {cellSize}"); +``` + +**记住:违反这些规则会导致路径规划失败、碰撞检测错误、网格生成异常等各种难以追踪的bug!** + ### UI Architecture: WPF + WinForms Hybrid - **WPF Components**: Modern MVVM-based controls in `src\UI\WPF\` @@ -139,144 +233,6 @@ public class PathClickToolPlugin : ToolPlugin { } - **Modern animation system**: Use Navisworks 2026 native animation components instead of manual Transform manipulation - **Enhanced APIs**: Take advantage of improved 2026 APIs for collision detection, animation, and model management -### Serena MCP工具配置 - -- **Token限制策略**: 所有serena MCP工具调用必须使用`max_answer_chars: 3000`参数 -- **适用工具**: 包括但不限于: - - `mcp__serena__search_for_pattern` - - `mcp__serena__find_symbol` - - `mcp__serena__get_symbols_overview` - - `mcp__serena__find_referencing_symbols` - - 所有其他支持`max_answer_chars`参数的serena工具 - -#### 查询最佳实践 - -**核心原则**: 分步定位 + 分段读取,避免一次性获取大量内容 - -##### ❌ 错误做法 - -```python -# 错误1: 对大方法使用 include_body=true -mcp__serena__find_symbol( - name_path="LargeMethod", - include_body=true, # ❌ 500行方法 → 20k+ 字符 → 必然失败 - max_answer_chars=3000 -) - -# 错误2: 使用OR模式的宽泛搜索 -mcp__serena__search_for_pattern( - substring_pattern="时间标签|TimeTag|预估.*时间|总时间", # ❌ 多个模式 → 178k+ 字符 - output_mode="files_with_matches" -) - -# 错误3: 使用通用词搜索 -mcp__serena__search_for_pattern( - substring_pattern="Manager", # ❌ 匹配太多文件 - output_mode="content" -) - -# 错误4: 使用 depth=1 获取所有成员 -mcp__serena__find_symbol( - name_path="LargeViewModel", - include_body=false, - depth=1, # ❌ 返回所有方法签名 → 5k+ 字符 - max_answer_chars=3000 -) -``` - -##### ✅ 正确做法 - -**步骤1: 精确定位文件** - -```python -# 方式A: 搜索精确的类名或方法名(单一关键词) -mcp__serena__search_for_pattern( - substring_pattern="TimeTagViewModel", # ✅ 单一精确词,不用OR模式 - paths_include_glob="**/*ViewModel.cs", # ✅ 限定文件类型 - output_mode="files_with_matches" -) - -# 方式B: 符号查找定位(不使用depth) -mcp__serena__find_symbol( - name_path="TimeTagViewModel", - include_body=false, # ✅ 只获取类本身 - depth=0, # ✅ 不获取成员,避免内容过多 - max_answer_chars=3000 -) -``` - -**步骤2: 搜索关键方法调用** - -```python -# 找到关键API调用,而不是搜索通用词 -mcp__serena__search_for_pattern( - substring_pattern="CalculateTimeMarkers", # ✅ 搜索具体API名称 - relative_path="src/UI/WPF/ViewModels/TimeTagViewModel.cs", # ✅ 限定文件 - output_mode="content", - context_lines_before=2, - context_lines_after=2, - max_answer_chars=3000 -) -``` - -**步骤3: 定位实现类** - -```python -# 根据步骤2找到的服务类,定位实现文件 -mcp__serena__search_for_pattern( - substring_pattern="TimeMarkerCalculationService", # ✅ 精确类名 - paths_include_glob="**/*.cs", - output_mode="files_with_matches" -) -``` - -**步骤4: 分段读取实现代码** - -```python -# 使用Read工具分段获取 -Read( - file_path="src/PathPlanning/TimeMarkerCalculationService.cs", - offset=97, # 从方法起始行 - limit=80 # 读取关键逻辑部分 -) - -# 如需继续,读取下一段 -Read( - file_path="...", - offset=185, # 继续往下 - limit=20 -) -``` - -##### 何时可以使用 include_body=true - -- ✅ 小方法(<100行) -- ✅ 属性定义 -- ✅ 简单类结构 -- ❌ 大型方法(>200行) -- ❌ 复杂类定义 -- ❌ 带有 `depth=1` 的大型类 - -##### 常见错误模式总结 - -| 错误模式 | 为什么失败 | 正确做法 | -|---------|-----------|---------| -| `substring_pattern="A\|B\|C"` | OR模式匹配过多 | 使用单一精确关键词 | -| `substring_pattern="总时间"` | 通用词匹配太广 | 搜索具体API名称 | -| `depth=1` + 大型类 | 返回所有成员签名 | 使用 `depth=0` 或直接搜索方法 | -| `include_body=true` + 大方法 | 方法体太长 | 先定位再用Read分段 | -| 不限定文件范围 | 搜索整个代码库 | 使用 `paths_include_glob` 或 `relative_path` | - -##### 执行原则总结 - -1. **单一精确关键词** > OR模式或通用词 -2. **限定搜索范围**: 始终使用 `paths_include_glob` 或 `relative_path` -3. **分步骤获取信息**: 定位 → 搜索调用 → 定位实现 → 分段读取 -4. **避免使用depth**: 对于大型类,使用 `depth=0` 或直接搜索方法名 -5. **先定位后读取**: 用 `output_mode="files_with_matches"` 定位,再用 `Read` 获取 -6. **善用context参数**: 搜索时只需少量上下文(2-3行) -7. 如遇到3k限制,使用更精确的搜索条件重新查询,而非提高限制 - ## API Documentation Search Strategy ### CHM文档搜索最佳实践