用ClashDetective API的标准用法重构碰撞检测部分,增加了碰撞分组;

三维视图选点光标改成十字形,当失去焦点时,按空格键切换回来。
This commit is contained in:
tian 2025-09-06 04:13:12 +08:00
parent 3ba3d328b8
commit 101c929f15
7 changed files with 284 additions and 78 deletions

View File

@ -1,5 +1,115 @@
# NavisworksTransport 变更日志
## [0.10.0] - 2025-09-06
### 🎯 路径编辑用户体验重大提升 - 工具切换与视觉反馈优化
#### 核心功能突破
**🔥 智能工具切换系统**
- **十字光标精确指示**
- PathClickToolPlugin返回Cursor.Measure提供清晰的十字光标视觉反馈
- 路径点选择时显示专业的精确定位光标
- 告别默认箭头光标的模糊体验,明确当前处于路径编辑模式
- **空格键快速切换**
- 实现一键切换:从导航模式瞬间回到路径编辑模式
- 智能检测当前工具状态,只在需要时执行切换操作
- 支持所有路径编辑状态Creating、AddingPoints、EditingPoint
**🔥 工具状态管理重构**
- **准确的状态检测机制**
- ReactivateToolPlugin改为检查实际Tool.Value而非内部标志
- 强制重置_isToolPluginActive标志确保完整的工具重新激活
- 解决导航工具覆盖后的状态同步问题
- **完整的工具重置流程**
- ActivateToolPlugin统一使用Tool.None进行工具状态重置
- 先重置再设置Tool.None → SetCustomToolPlugin → 十字光标显示
- 与DeactivateToolPlugin保持一致的重置逻辑
#### 重大技术突破
**🔧 PathInputMonitor架构简化**
- **单一职责优化**
- 移除重复的鼠标点击处理逻辑避免与PathClickToolPlugin冲突
- PathInputMonitor专注于空格键切换功能
- PathClickToolPlugin负责所有鼠标点击处理
- 消除工具间的交互干扰和重复处理
- **导航操作保护**
- 用户使用导航工具时,点击操作专用于导航而非路径编辑
- 避免在旋转、平移等导航操作中误触路径点添加
- 明确分离导航操作与路径编辑操作的边界
**🔧 ClashDetective碰撞检测API重构**
- **标准API迁移**
- 完全使用Navisworks官方ClashDetective API替代自制碰撞算法
- 重构ClashDetectiveIntegration使用标准Search和DocumentClash API
- 提升碰撞检测的准确性和性能表现
- **分组管理增强**
- 新增碰撞分组功能,支持按类型、区域、时间等维度组织碰撞结果
- 实现批量碰撞测试管理,提升大型项目的碰撞分析效率
- 集成Navisworks原生测试管理机制确保结果可靠性
#### 用户体验革命
**🔧 流畅的工作流设计**
- **直观的操作模式**
1. 路径编辑开始 → 自动显示十字光标
2. 使用导航工具 → 保持导航光标,点击用于导航
3. 按空格键 → 瞬间切换回十字光标,继续路径编辑
- **视觉状态反馈**
- 十字光标:明确指示当前可进行路径点选择
- 导航光标保持原生Navisworks导航体验
- 状态切换:按空格键看到即时的光标变化
**🔧 零干扰导航体验**
- **导航操作保护**
- 旋转、平移、缩放等操作不会意外触发路径编辑
- 用户可在路径编辑过程中自由使用导航功能
- 导航和编辑状态明确分离,避免功能冲突
### 技术架构成果
**架构质量提升**
- **工具管理统一化**:建立清晰的工具状态管理机制,消除状态不一致问题
- **职责分离优化**:各组件专注单一职责,减少耦合和冲突
- **标准API集成**使用Navisworks官方API提升系统稳定性和兼容性
**用户体验突破**
- **操作直观性**:通过视觉反馈让用户清晰了解当前工具状态
- **工作流顺畅性**:空格键快速切换,不中断用户思路
- **功能边界清晰**:导航和编辑功能明确分工,避免误操作
### 验证结果 ✅
- ✅ 十字光标正确显示,提供清晰的路径编辑视觉指示
- ✅ 空格键切换功能完美工作,从导航模式瞬间回到编辑模式
- ✅ 导航操作不受干扰,用户可正常旋转、平移、缩放模型
- ✅ 工具状态检测准确,避免状态不一致导致的功能异常
- ✅ ClashDetective API重构完成碰撞检测更准确更可靠
- ✅ 分组管理功能正常,支持复杂项目的碰撞分析需求
### 技术里程碑
- **用户体验设计**:从功能实现到体验优化的转型,建立专业级的交互设计
- **架构简化重构**:消除冗余组件和重复逻辑,建立清晰的系统边界
- **标准API集成**从自制算法到官方API的升级提升系统可靠性
- **工具状态管理**:建立完整的工具生命周期管理机制
---
## [0.9.0] - 2025-09-04
### 🎯 核心架构重构与性能优化突破 - 代码解耦与搜索引擎优化

View File

@ -1 +1 @@
0.9.0
0.10.0

View File

@ -1645,3 +1645,112 @@ using Autodesk.Navisworks.Api.Controls;
}
}
```
### Tool Enumeration
Member name Description
None No active tool
Select Select
SelectBox Select Box
RedlineFreehand Redline Freehand
RedlineLine Redline Line
RedlineEllipse Redline Ellipse
RedlineCloud Redline Cloud
RedlineLineString Redline Line String
RedlineTag Redline Tag
RedlineText Redline Text
RedlineErase Redline Erase
RedlineArrow Redline Arrow
MeasurePointToPoint Measure Point To Point
MeasurePointToMultiplePoints Measure Point To Multiple Points
MeasurePointLine Measure Point Line
MeasureAccumulate Measure Accumulate
MeasureAngle Measure Angle
MeasureArea Measure Area
MeasureSingle
BasicViewObjectWheel Basic View Object Wheel
BasicTourBuildingWheel Basic Tour Building Wheel
FullNavigationWheel Full Navigation Wheel
MiniViewObjectWheel Mini View Object Wheel
MiniTourBuildingWheel Mini Tour Building Wheel
MiniFullNavigationWheel Mini Full Navigation Wheel
Full2DNavigationWheel Full 2D Navigation Wheel
CommonPan Pan common across all Autodesk products
CommonZoom Zoom common across all Autodesk products
CommonZoomWindow Zoom Window common across all Autodesk products
CommonOrbit Orbit common across all Autodesk products
CommonFreeOrbit Free Orbit common across all Autodesk products
CommonConstrainedOrbit Constrained Orbit common across all Autodesk products
CommonLookAt Look At common across all Autodesk products
CommonLookAround Look Around common across all Autodesk products
CommonWalk Walk common across all Autodesk products
CommonCenter Center common across all Autodesk products
NavigateFixed Camera fixed in place
NavigateFreeLookAround Classic Navisworks Free Look Around (Swivel)
NavigateFreeOrbit Classic Navisworks Free Orbit (Examine)
NavigateWalk Classic Navisworks Walk
NavigateFly Classic Navisworks Fly
NavigateConstrainedOrbit Classic Navisworks Constrained Orbit (Turntable)
NavigateZoom Classic Navisworks Zoom
NavigatePan Classic Navisworks Pan
NavigateConstrainedPan Classic Navisworks Constrained Pan
NavigateLookAround Clasic Navisworks Look Around (Swivel)
NavigateOrbit Classic Navisworks Orbit
NavigateZoomWindow Classic Navisworks Zoom Window (Zoom Box)
CustomToolPlugin Functionality is provided by a ToolPlugin
### Cursor枚举成员
| 成员名称 | 描述 |
|-----------------|----------------------------|
| Unhandled | 特殊情况。如果已经处理则由GetCursor()返回 |
| Handled | 已处理光标 |
| Walk | 行走光标 |
| Fly | 飞行光标 |
| Orbit | 环绕光标 |
| Swivel | 旋转光标 |
| Examine | 检查光标 |
| Pan | 平移光标 |
| Zoom | 缩放光标 |
| Turntable | 转盘光标 |
| Focus | 聚焦光标 |
| Application | 应用程序光标 |
| ZoomBox | 缩放框光标 |
| Measure | 测量光标(十字线) |
| HyperHand | 超级手势光标 |
| PanWorld | 世界平移光标 |
| Roll | 滚动光标 |
| Stop | 停止光标 |
| MeasureEdge | 测量边缘光标 |
| MeasureVertex | 测量顶点光标 |
| Redline | 红线光标 |
| Erase | 擦除光标 |
| Wheel | 滚轮光标 |
| MarkupSelection | 标记选择光标 |
| MarkupSnapping | 标记捕捉光标 |
| MarkupEraser | 标记擦除光标 |
| MarkupQuickPick | 标记快速选择光标 |
| MarkupBucket | 标记桶光标 |
| MarkupAutoPoly | 标记自动多边形光标 |
使用方式:
```csharp
public class PathClickToolPlugin : ToolPlugin
{
....
/// <summary>
/// 重写光标样式,使用捕捉光标提供更好的视觉反馈
/// </summary>
/// <param name="view">当前视图</param>
/// <param name="modifier">键盘修饰键</param>
/// <returns>返回捕捉光标</returns>
public override Cursor GetCursor(View view, KeyModifiers modifier)
{
// 使用捕捉光标,提供更好的视觉反馈用于精确路径点选择
return Cursor.MarkupSnapping;
}
}
```

View File

@ -2,10 +2,15 @@
## 功能点
### [2025/09/05]
1. [x] (功能)把三维视图选点光标改成十字形,当失去焦点时,按空格键切换回来。
### [2025/09/04]
1. [x] (代码重构)将节点关系和几何体关系代码从动画管理器中抽取出来,形成工具类
2. [ ] (BUG) 多层建筑动画碰撞有结果但ClashDetective检测不出来
2. [ ] (BUG) 特殊的运动物体动画碰撞有结果正确但ClashDetective检测不出来可能是因为树只是线不是solid类型
3. [x] (优化) 用ClashDetective API的标准用法重构碰撞检测部分增加了碰撞分组
### [2025/09/03]

View File

@ -105,5 +105,17 @@ namespace NavisworksTransport
// 暂时不处理鼠标移动事件,避免日志过多
return false;
}
/// <summary>
/// 重写光标样式,使用捕捉光标提供更好的视觉反馈
/// </summary>
/// <param name="view">当前视图</param>
/// <param name="modifier">键盘修饰键</param>
/// <returns>返回捕捉光标</returns>
public override Cursor GetCursor(View view, KeyModifiers modifier)
{
// 使用测量光标(十字线),提供更好的视觉反馈用于精确路径点选择
return Cursor.Measure;
}
}
}

View File

@ -14,67 +14,14 @@ namespace NavisworksTransport
{
/// <summary>
/// 鼠标按下事件处理
/// 在路径编辑模式下捕获鼠标点击即使ToolPlugin失活也能响应
/// 不处理鼠标点击让PathClickToolPlugin和导航工具正常工作
/// </summary>
public override bool MouseDown(View view, KeyModifiers modifiers, ushort button, int x, int y, double timeOffset)
{
try
{
// 只处理左键点击
if (button != 1) return false;
// 获取PathPlanningManager实例
var pathManager = PathPlanningManager.GetActivePathManager();
if (pathManager == null) return false;
// 只在路径编辑模式下处理
if (pathManager.PathEditState == PathEditState.AddingPoints ||
pathManager.PathEditState == PathEditState.EditingPoint)
{
LogManager.WriteLog("[InputMonitor] 检测到路径编辑模式下的鼠标点击");
// 如果ToolPlugin未激活自动重新激活
if (!pathManager.IsToolPluginActive)
{
LogManager.WriteLog("[InputMonitor] ToolPlugin未激活自动重新激活");
pathManager.ReactivateToolPlugin();
// 给用户一个视觉反馈
var uiStateManager = UIStateManager.Instance;
uiStateManager?.QueueUIUpdate(() =>
{
// 这里可以添加状态栏提示或其他UI反馈
});
}
// 获取精确的3D坐标
PickItemResult itemResult = view.PickItemFromPoint(x, y);
if (itemResult != null)
{
LogManager.WriteLog($"[InputMonitor] 获取到3D坐标: ({itemResult.Point.X:F3}, {itemResult.Point.Y:F3}, {itemResult.Point.Z:F3})");
// 触发PathClickToolPlugin的事件复用现有的完整处理逻辑
// 这确保了自动路径、手动路径的所有模式都能正常工作
PathClickToolPlugin.TriggerMouseClicked(this, itemResult);
LogManager.WriteLog("[InputMonitor] 已触发PathClickToolPlugin事件");
return true; // 返回true表示已处理阻止其他处理程序
}
else
{
LogManager.WriteLog("[InputMonitor] 未点击到有效对象");
}
return false; // 让其他处理程序继续处理
}
return false; // 不在编辑模式,不处理
}
catch (Exception ex)
{
LogManager.WriteLog($"[InputMonitor] 处理鼠标点击异常: {ex.Message}");
return false;
}
// 不处理鼠标点击让PathClickToolPlugin和导航工具正常工作
// PathClickToolPlugin会在CustomToolPlugin模式下处理点击
// 导航工具会在导航模式下处理点击
return false;
}
/// <summary>
@ -98,13 +45,17 @@ namespace NavisworksTransport
{
var pathManager = PathPlanningManager.GetActivePathManager();
if (pathManager != null &&
(pathManager.PathEditState == PathEditState.AddingPoints ||
pathManager.PathEditState == PathEditState.EditingPoint) &&
!pathManager.IsToolPluginActive)
(pathManager.PathEditState == PathEditState.Creating ||
pathManager.PathEditState == PathEditState.AddingPoints ||
pathManager.PathEditState == PathEditState.EditingPoint))
{
LogManager.WriteLog("[InputMonitor] 用户按空格键,重新激活工具");
pathManager.ReactivateToolPlugin();
return true;
var currentTool = Application.MainDocument.Tool.Value;
if (currentTool != Tool.CustomToolPlugin)
{
LogManager.WriteLog($"[InputMonitor] 用户按空格键,当前工具为{currentTool},重新激活工具");
pathManager.ReactivateToolPlugin();
return true;
}
}
}

View File

@ -2282,6 +2282,13 @@ namespace NavisworksTransport
// 4. 设置为活动工具
LogManager.WriteLog("[ToolPlugin] 步骤4: 设置为活动工具");
// 先重置工具状态,清除可能的导航工具
// 这一步很重要确保从导航工具如Pan、Orbit切换回自定义工具
Application.MainDocument.Tool.Value = Tool.None;
LogManager.WriteLog("[ToolPlugin] 已重置工具状态为None");
// 然后设置自定义工具插件
Application.MainDocument.Tool.SetCustomToolPlugin(loadedPlugin);
LogManager.WriteLog("[ToolPlugin] ✓ 工具设置成功");
@ -2317,28 +2324,40 @@ namespace NavisworksTransport
{
try
{
// 只有在编辑模式且工具未激活时才重新激活
if (!_isToolPluginActive &&
(PathEditState == PathEditState.AddingPoints ||
// 检查当前状态和实际工具值
if ((PathEditState == PathEditState.Creating ||
PathEditState == PathEditState.AddingPoints ||
PathEditState == PathEditState.EditingPoint))
{
LogManager.WriteLog("[ReactivateToolPlugin] 开始重新激活ToolPlugin");
// 调用现有的激活方法,但不重复订阅事件
if (ActivateToolPlugin(false))
// 检查当前工具是否为自定义工具,如果不是则需要重新激活
var currentTool = Application.MainDocument.Tool.Value;
if (currentTool != Tool.CustomToolPlugin)
{
LogManager.WriteLog("[ReactivateToolPlugin] ToolPlugin重新激活成功");
RaiseStatusChanged("工具已重新激活", PathPlanningStatusType.Info);
LogManager.WriteLog($"[ReactivateToolPlugin] 当前工具为{currentTool}开始重新激活ToolPlugin");
// 重要先将激活标志设置为false强制执行完整的激活流程
_isToolPluginActive = false;
// 调用现有的激活方法,但不重复订阅事件
if (ActivateToolPlugin(false))
{
LogManager.WriteLog("[ReactivateToolPlugin] ToolPlugin重新激活成功");
RaiseStatusChanged("工具已重新激活", PathPlanningStatusType.Info);
}
else
{
LogManager.WriteLog("[ReactivateToolPlugin] ToolPlugin重新激活失败");
RaiseErrorOccurred("无法重新激活编辑工具");
}
}
else
{
LogManager.WriteLog("[ReactivateToolPlugin] ToolPlugin重新激活失败");
RaiseErrorOccurred("无法重新激活编辑工具");
LogManager.WriteLog("[ReactivateToolPlugin] 当前已是CustomToolPlugin无需重新激活");
}
}
else
{
LogManager.WriteLog($"[ReactivateToolPlugin] 跳过重新激活 - IsToolPluginActive: {_isToolPluginActive}, PathEditState: {PathEditState}");
LogManager.WriteLog($"[ReactivateToolPlugin] 跳过重新激活 - PathEditState: {PathEditState}");
}
}
catch (Exception ex)