CloudCompare-源码分析-处理滚轮事件
文章目录
- 🧠 函数结构概览
- ✅ 判断是否处于 Bubble View 模式
- ✅ 非 Bubble 模式:正常透视/正交视图
- ✅ 强制重绘 + LOD 设置
- 🎯 那比例尺是如何更新的?
- 🧩 举个例子
- ✅ 总结:比例尺是如何被更新的
void ccGLWindowInterface::onWheelEvent(float wheelDelta_deg)
{if (m_bubbleViewModeEnabled){//to zoom in and out we simply change the fov in bubble-view mode!setBubbleViewFov(m_bubbleViewFov_deg - wheelDelta_deg / 3.6f); //1 turn = 100 degrees}else{double delta = 0.0;if (m_viewportParams.perspectiveView){delta = static_cast<double>(wheelDelta_deg * computeDefaultIncrement()) / 8.0 * getDisplayParameters().zoomSpeed;double speedRatio = 10.0 * m_viewportParams.zNear / m_visibleObjectsBBox.getMaxBoxDim();double speedCoef = std::min(16.0, exp(speedRatio));delta *= speedCoef;}else{double cameraCenterToPivotDist = m_viewportParams.getFocalDistance();delta = (std::abs(cameraCenterToPivotDist) / (wheelDelta_deg < 0.0 ? -20.0 : 20.0)) * getDisplayParameters().zoomSpeed;}CCVector3d v(0.0, 0.0, -delta);moveCamera(v);}setLODEnabled(true);m_currentLODState.level = 0;redraw();
}
这个函数:
void ccGLWindowInterface::onWheelEvent(float wheelDelta_deg)
是 CloudCompare 中响应鼠标滚轮滚动事件的核心函数。我们来分析它的逻辑流程,重点聚焦比例尺是如何被间接更新的。
🧠 函数结构概览
✅ 判断是否处于 Bubble View 模式
if (m_bubbleViewModeEnabled)
{setBubbleViewFov(m_bubbleViewFov_deg - wheelDelta_deg / 3.6f);
}
- 如果是 Bubble View 模式(球形全景相机视图),通过调整 FOV 来实现缩放。
- 比例尺不显示在该模式下,所以不相关。
✅ 非 Bubble 模式:正常透视/正交视图
else
{// 计算 delta(缩放幅度)if (m_viewportParams.perspectiveView){// 透视模式// 根据距离、近裁剪面与最大包围盒尺寸,动态计算缩放速度}else{// 正交模式// 按照焦距(camera-to-pivot)线性缩放}// 构造一个 z 方向的缩放向量,作用于摄像头位置moveCamera(v);
}
这段代码通过 moveCamera(v)
调整相机参数(特别是 m_viewportParams.zoom
或 cameraCenter/focal
等),从而影响单位像素代表的实际距离(pixelSize)。
✅ 强制重绘 + LOD 设置
setLODEnabled(true);
m_currentLODState.level = 0;
redraw();
redraw()
是关键,它会触发 paintGL()
→ drawScene()
→ drawForeground()
→ drawScale()
。
🎯 那比例尺是如何更新的?
比例尺绘制依赖于:
👉 m_viewportParams.pixelSize
:单位长度对应的像素大小,缩放改变后它会变化。
滚轮缩放发生时:
-
调用
moveCamera()
→ 修改视图变换参数。 -
moveCamera()
内部(或随后)会触发updatePixelSize()
:m_viewportParams.pixelSize = computePixelSize();
-
在正交视图下:
pixelSize = totalDisplayedSceneSize / glWidth();
-
在透视视图下则更复杂,与
zNear
、FOV 有关。
-
-
drawForeground()
→drawScale()
→ 用pixelSize
决定比例尺长度。
🧩 举个例子
假设比例尺绘制逻辑是:
float targetPixelWidth = 320; // 固定像素长度
float worldLength = pixelSize * targetPixelWidth;
那么:
- 滚轮放大 → pixelSize 变小 → worldLength 变小(比如 10m → 5m)
- 滚轮缩小 → pixelSize 变大 → worldLength 变大(比如 10m → 20m)
你可以在比例尺的控制类 ScaleBarController
中,通过监听 pixelSize
的变化来重新计算比例标签和刻度。
✅ 总结:比例尺是如何被更新的
步骤 | 动作 | 影响 |
---|---|---|
1 | 用户滚动滚轮 | onWheelEvent() 被调用 |
2 | 计算 delta → 调用 moveCamera(v) | 改变视角或 zoom |
3 | 触发 updatePixelSize() | pixelSize 被更新 |
4 | redraw() 调用 drawForeground() | 重绘比例尺 |
5 | drawScale() 用 pixelSize → 显示比例尺 | 实现随滚轮缩放自动更新的视觉效果 |
如果你正在开发或替换比例尺系统(比如接入 ScaleBarController
),可以在 drawScale
或一个 updateScaleBar(pixelSize)
中使用当前的 pixelSize
进行逻辑跳变和更新。