Open CASCADE+Qt:实现以鼠标为锚点缩放、平移、旋转

Open CASCADE+Qt:实现以鼠标为锚点缩放、平移、旋转 - 知乎

简介

本文实现在三维窗口中添加一个立方体,并实现以鼠标为锚点视图缩放、平移、旋转操作,效果见如下动图:

动图封面
 

 

添加立方体

基于前面建立的三维窗口:

OCCWidget构造函数末尾,添加立方体,并将其添加到上下文中显示该立方体(绘制立方体不是本文重点):

OCCWidget::OCCWidget(QWidget *parent)
    : QWidget{parent}
    , m_dpiScale{this->devicePixelRatioF()}
{
    ...
    // 绘制立方体
    TopoDS_Shape box =  BRepPrimAPI_MakeBox(100, 100, 100);
    Handle(AIS_Shape) box_AIS = new AIS_Shape(box);
    m_context->Display(box_AIS, Standard_True);
}

显示效果如下:

可以看到在画面中央,出现了我们绘制的立方体,默认立方体以边显示,没有显示面,并且默认视角为等轴测视角。

视图缩放、平移、旋转实现

这里鼠标实现视图的缩放、平移以及旋转操作详细描述为:当鼠标滚轮向前滚动时,视图放大,反之视图缩小;按下鼠标右键不放并移动鼠标,视图跟随鼠标移动而平移;按下鼠标中键不放并移动鼠标,视图跟随鼠标移动而旋转。上述事件包含:鼠标滚动事件、鼠标右键按下事件、鼠标中键按下事件以及鼠标移动事件,因此,要实现视图缩放、平移、以及旋转操作,需要重写以下鼠标事件:

    void mousePressEvent(QMouseEvent* event) override;
    void mouseReleaseEvent(QMouseEvent* event) override;
    void mouseMoveEvent(QMouseEvent* event) override;
    void wheelEvent(QWheelEvent* event) override;

分表为鼠标按下、释放、移动以及滚轮滚动事件。

鼠标按下事件中,当按下的为右键时,模式m_mode赋值为平移Action3d_Panning,并将点击位置的初始坐标赋值给m_xm_y,以便在鼠标移动事件中,实现视图平移;当按下的为中键时,模式m_mode赋值为平移Action3d_Rotation,并调用m_view成员函数StartRotation函数以当前中键按下的点为初始点,开始旋转。

void OCCWidget::mousePressEvent(QMouseEvent* event){
    //平移 鼠标右键
    if ((event->buttons() & Qt::RightButton))
    {
        m_mode = Action3d_Panning;
        m_x = event->pos().x();
        m_y = event->pos().y();
    }
    //旋转 鼠标中键
    else if (event->buttons() & Qt::MiddleButton)
    {
        m_mode = Action3d_Rotation;
        m_view->StartRotation(m_dpiScale*event->pos().x(), m_dpiScale*event->pos().y());
    }
}

鼠标移动事件中,判断m_mode的模式,当为平移模式Action3d_Panning时,调用m_view成员函数Pan平移视图;当为旋转模式Action3d_Rotation时,调用m_view成员函数Rotation旋转视图。

void OCCWidget::mouseMoveEvent(QMouseEvent* event){
    switch (m_mode)
    {
    case OCCWidget::Action3d_Panning:
        m_view->Pan(m_dpiScale*(event->pos().x() - m_x), m_dpiScale*(m_y - event->pos().y()));
        m_x = event->pos().x();
        m_y = event->pos().y();
        break;
    case OCCWidget::Action3d_Rotation:
        m_view->Rotation(m_dpiScale*event->pos().x(), m_dpiScale*event->pos().y());
        break;
    default:
        break;
    }
};

鼠标滚轮滚动事件中,通过鼠标滚轮滚动事件event的成员函数angleDelta().y()的值来判断鼠标滚轮滚动方向,该值为正时,表示滚轮向前滚动,值为负时表示滚轮向后滚动。m_view调用成员函数StartZoomAtPoint设置缩放锚点,即当前鼠标所在位置,而后调用ZoomAtPoint实现缩放。

void OCCWidget::wheelEvent(QWheelEvent* event){
    double aFactor = 5;

    double aX = event->position().x();
    double aY = event->position().y();

    if (event->angleDelta().y() > 0)
    {
        aX += aFactor;
        aY += aFactor;
    }
    else
    {
        aX -= aFactor;
        aY -= aFactor;
    }
    m_view->StartZoomAtPoint(m_dpiScale*event->position().x(), m_dpiScale*event->position().y());
    m_view->ZoomAtPoint(event->position().x(), event->position().y(), aX, aY);
};

最后补充鼠标释放事件:

void OCCWidget::mouseReleaseEvent(QMouseEvent* event){
    m_mode = Action3d_Nothing;
}

显示器缩放比

需要注意的是,在实现上述成员函数过程中,例如视图平移操作中m_view->Pan(m_dpiScale*(event->pos().x() - m_x), m_dpiScale*(m_y - event->pos().y()));其中m_dpiScale表示显示器缩放比,默认显示器缩放比为100%,但对于高分辨率显示器,默认缩放比使得桌面图标以及文字过小,并不舒适,此时往往会更改显示器缩放比,当显示器缩放比不为100%时,若调用m_view->Pan(event->pos().x() - m_x, m_y - event->pos().y());那么平移将出现异常。

源码

源码见:

posted @   unicornsir  阅读(42)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
历史上的今天:
2023-01-16 c# ?的用法
点击右上角即可分享
微信分享提示