# 坐标轴系统修复说明 ## 问题描述 用户报告主程序中的坐标轴系统无响应: - 鼠标悬停在坐标轴上无高亮效果 - 点击坐标轴无法开始拖拽 - 独立的demo程序(`standalone_gizmo_test.py`)工作正常 ## 根本原因 经过分析发现,问题出在**Qt集成环境下的窗口尺寸获取不准确**: 1. **独立demo**:直接继承自`ShowBase`,使用`self.win.getXSize()`和`self.win.getYSize()`获取窗口尺寸是准确的 2. **主程序**:使用Qt集成的`Panda3DWorld`基类,`self.win.getXSize()`返回的尺寸与实际Qt渲染区域尺寸不匹配 3. **坐标轴点击检测**:依赖屏幕空间投影计算,窗口尺寸错误导致投影坐标计算错误 ## 修复方案 ### 1. 添加Qt部件引用机制 在`MyWorld`类中添加: ```python # Qt部件引用(用于获取准确的渲染区域尺寸) self.qtWidget = None def setQtWidget(self, widget): """设置Qt部件引用""" self.qtWidget = widget def getWindowSize(self): """获取准确的窗口尺寸""" if self.qtWidget: # 优先使用Qt部件的实际尺寸 width, height = self.qtWidget.getActualSize() if width > 0 and height > 0: return width, height # 备用方案:使用Panda3D窗口尺寸 if hasattr(self, 'win') and self.win: width = self.win.getXSize() height = self.win.getYSize() return width, height # 最后的默认值 return 800, 600 ``` ### 2. 修改CustomPanda3DWidget 添加方法以获取Qt部件实际尺寸: ```python def getActualSize(self): """获取Qt部件的实际渲染尺寸""" return (self.width(), self.height()) ``` 在构造函数中建立引用: ```python # 让world引用这个widget,以便获取准确的尺寸 if hasattr(world, 'setQtWidget'): world.setQtWidget(self) ``` ### 3. 修改所有屏幕坐标计算 将所有使用`self.win.getXSize()`和`self.win.getYSize()`的地方改为使用新的`getWindowSize()`方法: #### 修改前: ```python win_x = (screen_pos.getX() + 1.0) * 0.5 * self.win.getXSize() win_y = (1.0 - screen_pos.getY()) * 0.5 * self.win.getYSize() ``` #### 修改后: ```python # 获取准确的窗口尺寸 win_width, win_height = self.getWindowSize() win_x = (screen_pos.getX() + 1.0) * 0.5 * win_width win_y = (1.0 - screen_pos.getY()) * 0.5 * win_height ``` ### 4. 修改的关键方法 1. `checkGizmoClick()` - 坐标轴点击检测的主方法 2. `updateGizmoHighlight()` - 坐标轴悬停高亮 3. `updateGizmoDrag()` - 坐标轴拖拽更新 4. `mousePressEventLeft()` - 鼠标点击事件处理 5. `mouseMoveEvent()` - 鼠标移动事件处理 6. `checkGizmoClickFallback()` - 备用点击检测方法 ## 技术原理 ### 屏幕空间投影算法 坐标轴点击检测使用以下步骤: 1. **世界坐标 → 相机坐标**: ```python cam_space_pos = self.cam.getRelativePoint(self.render, world_pos) ``` 2. **相机坐标 → 标准化屏幕坐标**: ```python screen_pos = Point2() self.cam.node().getLens().project(cam_space_pos, screen_pos) ``` 3. **标准化坐标 → 像素坐标**: ```python win_x = (screen_pos.getX() + 1.0) * 0.5 * win_width win_y = (1.0 - screen_pos.getY()) * 0.5 * win_height ``` 4. **点到线段距离计算**: ```python distance = self.distanceToLine((mouse_x, mouse_y), center_screen, axis_screen) ``` ### 窗口尺寸差异的影响 如果窗口尺寸不准确: - 步骤3中的像素坐标计算错误 - 坐标轴在屏幕上的投影位置计算错误 - 鼠标点击位置与计算出的轴位置不匹配 - 导致点击检测失败 ## 测试验证 创建了测试脚本`demo/test_size_fix.py`来验证修复效果: - 对比Qt部件尺寸和Panda3D窗口尺寸 - 实时监控尺寸变化 - 验证`getWindowSize()`方法的正确性 ## 预期效果 修复后的坐标轴系统应该: 1. ✅ 鼠标悬停时正确高亮对应的轴(红色X轴、绿色Y轴、蓝色Z轴变为黄色) 2. ✅ 点击坐标轴能够正确开始拖拽 3. ✅ 拖拽时只沿选定轴方向移动物体 4. ✅ 松开鼠标时正确结束拖拽 ## 兼容性 修复方案完全向后兼容: - 如果没有Qt环境,自动回退到使用Panda3D窗口尺寸 - 如果Qt部件引用未设置,使用备用方案 - 不影响独立的ShowBase应用程序