occ中以鼠标所在位置进行缩放

原理分析

鼠标中心缩放的核心原理是通过视口变换矩阵 调整摄像机位置或投影参数。OpenCASCADE通过StartZoomAtPoint和ZoomAtPoint两个关键方法实现:

  • 视点锚定:将鼠标当前位置作为缩放中心点,避免传统缩放导致的视觉偏移。
  • 模拟拖动:通过计算虚拟位移量(delta)触发动态缩放效果,实际是修改投影矩阵的缩放因子。

关键概念

1. 视口坐标系转换

鼠标坐标(mx, my)需转换为OpenCASCADE内部使用的视口坐标系。OCC视图默认原点在左上角,Y轴向下为正方向。

2. 滚轮刻度处理

高精度滚轮事件angleDelta()返回的数值以120为基本单位。正值表示滚轮向前(放大),负值表示向后(缩小)。

3. 缩放因子计算

固定比例系数zoomFactor(示例为1.1)控制缩放幅度。通过判断滚轮方向决定放大或缩小:

  • 放大:scale = zoomFactor
  • 缩小:scale = 1.0 / zoomFactor

代码实现解析

步骤1:获取鼠标位置

cpp 复制代码
const QPoint pos = theEvent->position().toPoint();
const Standard_Integer mx = pos.x();
const Standard_Integer my = pos.y();

将Qt的浮点坐标转换为整型,适应OCC接口要求。

步骤2:处理滚轮事件

cpp 复制代码
const int steps = theEvent->angleDelta().y() / 120;
if (steps == 0) { theEvent->accept(); return; }

过滤无效事件(如横向滚轮),避免不必要的计算。

步骤3:计算缩放比例

cpp 复制代码
const Standard_Real zoomFactor = 1.1;
const Standard_Real scale = (steps > 0) ? zoomFactor : 1.0 / zoomFactor;

通过三元运算符快速确定缩放方向。

步骤4:执行缩放操作

cpp 复制代码
myView->StartZoomAtPoint(mx, my);
const Standard_Integer delta = (steps > 0) ? -10 : 10;
myView->ZoomAtPoint(mx, my, mx + delta, my + delta);
  • StartZoomAtPoint:锁定当前鼠标位置为缩放中心。
  • ZoomAtPoint:通过虚拟位移触发动态缩放。正负delta控制放大/缩小方向。

扩展优化

非线性缩放

可通过动态调整zoomFactor实现加速缩放效果:

cpp 复制代码
const Standard_Real zoomFactor = 1.0 + 0.1 * abs(steps);

视口边界保护

添加边界检查防止过度缩放:

cpp 复制代码
if (myView->Scale() > MAX_SCALE || myView->Scale() < MIN_SCALE) return;

完整代码

cpp 复制代码
void wheelEvent(QWheelEvent* theEvent)
{
    if (myView.IsNull()) return;

    const QPoint pos = theEvent->position().toPoint();
    const Standard_Integer mx = pos.x();
    const Standard_Integer my = pos.y();

    // 高分辨率滚轮:每120为一刻度
    const int steps = theEvent->angleDelta().y() / 120;
    if (steps == 0) { theEvent->accept(); return; }

    // 使用OpenCASCADE内置的缩放功能
    const Standard_Real zoomFactor = 1.1;
    const Standard_Real scale = (steps > 0) ? zoomFactor : 1.0 / zoomFactor;

    // 以鼠标位置为中心进行缩放
    myView->StartZoomAtPoint(mx, my);

    // 模拟拖动来缩放
    const Standard_Integer delta = (steps > 0) ? -10 : 10;
    myView->ZoomAtPoint(mx, my, mx + delta, my + delta);


    theEvent->accept(); // 已处理,不传递给 QWidget
}
相关推荐
蓝祁子yoky20 小时前
Qt学习日记 Day13:网络编程(一)-TCP基础与Socket实战
网络·qt·学习
飞浪纪元[FWC–FE]1 天前
从零到一键绿:Qt 5.14.2 + VS2019 开发环境搭建、Kit 套件配置与构建错误修复完全手册
开发语言·qt
ShineWinsu1 天前
对于Qt:QCheckBox常见属性的详细解析
c++·qt·面试·笔试·gui·qcheckbox·多选框
ShineWinsu1 天前
对于Qt:QPushButton常见属性的解析
开发语言·c++·qt·api·gui·按钮·qpushbutton
飞浪纪元[FWC–FE]1 天前
Qt 工程创建与 CMake / qmake 构建规范
开发语言·数据库·qt
Lhan.zzZ1 天前
用 Qt 构建线程安全的通讯静态库:从线程亲和性到完整工程
c++·vscode·qt·tcp/ip·udp
飞浪纪元[FWC–FE]1 天前
Qt 构建排错实录:从 MSB 1009 到生成器选型
开发语言·数据库·qt
小徐不徐说2 天前
C++ 接口与插件设计:从工厂注册到 Qt 动态插件
数据库·c++·qt·系统架构·程序设计
小王C语言2 天前
Qt常用控件:容器类控件,标题分组框、标签页(浏览器标签)
开发语言·qt
TMedical2 天前
MedPlanning 截骨模拟矫形功能
c++·图像处理·人工智能·qt·健康医疗