@EgaNator
Учусь на программиста

Алгоритм кривой Безье, как можно преобразовать код?

Нашёл код реализации кривой Безье. У меня он не запускался, немного подшаманил его. В этом коде часть кривой Безье описывается через другую кривую Безье. И эта другая кривая Безье уже отрисовывается с помощью обычных средств, как я понял. Можно ли как-то попроще реализовать этот алгоритм, например, сразу рисовать кривую? Пытался кардинально всё изменить, но не получается.
Вот сам код:
widget.h
#ifndef WIDGET_H
#define WIDGET_H

#include <QApplication>
#include <QWidget>
#include <QLabel>
#include <QSlider>
#include <QLayout>
#include <QPainter>
#include <QMouseEvent>
#include <QSignalMapper>

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = nullptr);
    ~Widget();

public slots:
    // from 0 to 100%
    void setT0(int val) { setPart(0, 0.01*val); }
    void setT1(int val) { setPart(1, 0.01*val); }

protected:
    virtual void paintEvent(QPaintEvent *event);
    virtual void mousePressEvent(QMouseEvent *event);
    virtual void mouseReleaseEvent(QMouseEvent *event);
    virtual void mouseMoveEvent(QMouseEvent *event);

private:
    int pointIdx(const QPointF& p);
    void updatePart();
    void setPart(int idx, qreal val);
    QList<QPointF> pts;
    QList<QPointF> ptsPart;
    qreal t0, t1;
    QPointF prev;
    int movingIdx;
    int overIdx;

    Ui::Widget *ui;
};

#endif // WIDGET_H


widget.cpp
#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    setMouseTracking(true);
    pts << QPointF(50, 50) << QPointF(450, 100)
        << QPointF(350, 450) << QPointF(750, 500);
    ptsPart = pts;
    updatePart();

    ui->setupUi(this);
}

const qreal r = 5.0;

void Widget::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event)
    QPainter painter(this);
    painter.fillRect(0, 0, width(), height(), Qt::darkGray);
    painter.setRenderHint(QPainter::Antialiasing);
    // draw original bezier
    painter.setPen(QPen(QBrush(Qt::white), 1.5));
    painter.setBrush(Qt::NoBrush);
    QPainterPath path(pts[0]);
    path.cubicTo(pts[1], pts[2], pts[3]);
    painter.drawPath(path);
    // draw path for control points
    path = QPainterPath(pts[0]);
    path.lineTo(pts[1]);
    path.lineTo(pts[2]);
    path.lineTo(pts[3]);
    QBrush b(Qt::yellow);
    painter.setPen(QPen(b, 0.75));
    painter.setBrush(Qt::NoBrush);
    painter.drawPath(path);
    // draw control points
    QBrush b1(Qt::cyan);
    painter.setPen(Qt::NoPen);
    for (int idx = 0; idx < pts.size(); ++idx) {
        painter.setBrush(idx == overIdx ? b1 : b);
        painter.drawEllipse(pts[idx], r, r);
    // draw part of original bezier
    painter.setPen(QPen(QBrush(QColor(0, 255, 0, 100)), 12.0));
    painter.setBrush(Qt::NoBrush);
    path = QPainterPath(ptsPart[0]);
    path.cubicTo(ptsPart[1], ptsPart[2], ptsPart[3]);
    painter.drawPath(path);
    }
}

void Widget::mousePressEvent(QMouseEvent *event)
{
    if (movingIdx == -1 && event->button() == Qt::LeftButton) {
        movingIdx = pointIdx(event->pos());
        prev = event->pos();
    }
}

void Widget::mouseReleaseEvent(QMouseEvent *event)
{
    if (movingIdx != -1 && event->button() == Qt::LeftButton)
        movingIdx = -1;
}

void Widget::mouseMoveEvent(QMouseEvent *event)
{
    if (movingIdx != -1) {
        pts[movingIdx] += (event->pos() - prev);
        updatePart();
        prev = event->pos();
        update();
    } else {
        int idx = pointIdx(event->pos());
        if (idx != overIdx)
            update();
        overIdx = idx;
    }
}

int Widget::pointIdx(const QPointF& p)
{
    for (int idx = 0; idx < pts.size(); ++idx) {
        if (QLineF(p, pts[idx]).length() <= 1.2*r)
            return idx;
    }
    return -1;
}

void Widget::updatePart()
{
    qreal u0 = 1.0 - t0;
    qreal u1 = 1.0 - t1;

    qreal x1 = pts[0].x();
    qreal y1 = pts[0].y();
    qreal x2 = pts[3].x();
    qreal y2 = pts[3].y();
    qreal bx1 = pts[1].x();
    qreal by1 = pts[1].y();
    qreal bx2 = pts[2].x();
    qreal by2 = pts[2].y();

    qreal qxa =  x1*u0*u0 + bx1*2*t0*u0 + bx2*t0*t0;
    qreal qxb =  x1*u1*u1 + bx1*2*t1*u1 + bx2*t1*t1;
    qreal qxc = bx1*u0*u0 + bx2*2*t0*u0 +  x2*t0*t0;
    qreal qxd = bx1*u1*u1 + bx2*2*t1*u1 +  x2*t1*t1;

    qreal qya =  y1*u0*u0 + by1*2*t0*u0 + by2*t0*t0;
    qreal qyb =  y1*u1*u1 + by1*2*t1*u1 + by2*t1*t1;
    qreal qyc = by1*u0*u0 + by2*2*t0*u0 +  y2*t0*t0;
    qreal qyd = by1*u1*u1 + by2*2*t1*u1 +  y2*t1*t1;

    ptsPart[0].setX(qxa*u0 + qxc*t0);
    ptsPart[1].setX(qxa*u1 + qxc*t1);
    ptsPart[2].setX(qxb*u0 + qxd*t0);
    ptsPart[3].setX(qxb*u1 + qxd*t1);

    ptsPart[0].setY(qya*u0 + qyc*t0);
    ptsPart[1].setY(qya*u1 + qyc*t1);
    ptsPart[2].setY(qyb*u0 + qyd*t0);
    ptsPart[3].setY(qyb*u1 + qyd*t1);

}

void Widget::setPart(int idx, qreal val)
{
    qreal& t = (idx == 0) ? t0 : t1;
    t = val;
    updatePart();
    update();
}

Widget::~Widget()
{
    delete ui;
}


main.cpp
#include "widget.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;

    QGridLayout* layout = new QGridLayout(&w);
    layout->addWidget(new QLabel("t0:"), 0, 0);
    layout->addWidget(new QLabel("t1:"), 1, 0);
    QSlider* s0 = new QSlider(Qt::Horizontal);
    QSlider* s1 = new QSlider(Qt::Horizontal);
    layout->addWidget(s0, 0, 1);
    layout->addWidget(s1, 1, 1);
    s0->setRange(0, 100);
    s1->setRange(0, 100);
    Widget* widget = new Widget();
    layout->addWidget(widget, 2, 0, 1, 2);
    QObject::connect(s0, SIGNAL(valueChanged(int)), widget, SLOT(setT0(int)));
    QObject::connect(s1, SIGNAL(valueChanged(int)), widget, SLOT(setT1(int)));
    s0->setSliderPosition(20);
    s1->setSliderPosition(75);

    w.resize(800, 600);
    w.show();

    return a.exec();
}
  • Вопрос задан
  • 425 просмотров
Пригласить эксперта
Ответы на вопрос 1
@vanyamba-electronics
Кривая задаётся четырьмя точками, что и происходит в данном алгоритме.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы