Qt5与现代OpenGL学习(八)在Widget里绘制曲面

发布于:2025-05-08 ⋅ 阅读:(12) ⋅ 点赞:(0)

请添加图片描述
surfacewidget.h

#ifndef SURFACEWIDGET_H
#define SURFACEWIDGET_H

#include <QWidget>
#include <QPainter>
#include <QMouseEvent>
#include <QToolTip>
#include <QDebug>
#include <cmath>

class SurfaceWidget : public QWidget
{
    Q_OBJECT

public:
    explicit SurfaceWidget(QWidget *parent = nullptr);

protected:
    void paintEvent(QPaintEvent *event) override;

private:
    // 声明为const成员函数,因为不修改类成员
    double surfaceFunction(double x, double y) const;

    QTransform m_transform;
    double m_scale = 50.0;
    bool m_selectedPointValid = false;
    double m_selectedX = 0;
    double m_selectedY = 0;
};

#endif // SURFACEWIDGET_H

surfacewidget.cpp

#include "surfacewidget.h"

SurfaceWidget::SurfaceWidget(QWidget *parent) : QWidget(parent)
{
    setMouseTracking(true); // 启用鼠标移动跟踪
}

void SurfaceWidget::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);

    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);

    int width = this->width();
    int height = this->height();

    // 设置坐标系:原点在中心,Y轴向上
    painter.translate(width/2, height/2);
    painter.scale(1, -1);

    // 保存变换矩阵用于鼠标坐标转换
    m_transform = painter.transform();

    // 绘制曲面网格
    int steps = 50;

    // 绘制水平线
    for (int i = -steps; i <= steps; ++i) {
        double x = i * m_scale / steps;

        QPainterPath path;
        bool first = true;

        for (int j = -steps; j <= steps; ++j) {
            double y = j * m_scale / steps;
            double z = surfaceFunction(x, y);

            QPointF point(x * m_scale, y * m_scale - z * m_scale/2);

            if (first) {
                path.moveTo(point);
                first = false;
            } else {
                path.lineTo(point);
            }
        }

        painter.setPen(QPen(Qt::blue, 1));
        painter.drawPath(path);
    }

    // 绘制垂直线
    for (int j = -steps; j <= steps; ++j) {
        double y = j * m_scale / steps;

        QPainterPath path;
        bool first = true;

        for (int i = -steps; i <= steps; ++i) {
            double x = i * m_scale / steps;
            double z = surfaceFunction(x, y);

            QPointF point(x * m_scale, y * m_scale - z * m_scale/2);

            if (first) {
                path.moveTo(point);
                first = false;
            } else {
                path.lineTo(point);
            }
        }

        painter.setPen(QPen(Qt::red, 1));
        painter.drawPath(path);
    }

    // 绘制选中的顶点
    if (m_selectedPointValid) {
        double z = surfaceFunction(m_selectedX, m_selectedY);
        QPointF point(m_selectedX * m_scale,
                     m_selectedY * m_scale - z * m_scale/2);

        painter.setPen(QPen(Qt::green, 4));
        painter.drawPoint(point);
    }
}

double SurfaceWidget::surfaceFunction(double x, double y)  const
{
    // 定义曲面函数 - 双曲抛物面
    return (x*x - y*y) / 100.0;

    // 可选其他曲面函数:
    // return 5 * sin(sqrt(x*x + y*y) / 2.0; // 正弦曲面
}

在mainwindow.ui中,添加QWidget,并提升为:SurfaceWidget


网站公告

今日签到

点亮在社区的每一天
去签到