QPainterPath-创建以弧为边缘的凹面区域

问题描述 投票:0回答:1

我希望能够绘制填充区域,该填充区域由直线和圆弧的边缘组成。凸形图形没有问题,但凹形图形有问题。这是我要绘制的:

What I want to get

我可以很容易地绘制轮廓。我使用如下创建的QPainterPath中的笔画:

path = QPainterPath()
path.moveTo(v1)
path.lineTo(v2)
path.lineTo(v3)
path.arcTo(v1) #this is simplified 

但是我无法以相同的方式创建填充区域。因为v3v1之间的弧的中心在图的外面。因此,填充区域在左侧。

What I've got

我尝试用this question的圆弧的三次Bezier逼近来创建它,并取得了一些成功(左图)。不幸的是,这种近似并不完美,当圆弧超过圆弧的一半时会变得发疯(再次在左侧)。 (右图)

What I achieved with Bezier

如何使用QPainterPath在第一张图片上创建形状?

qt qpainterpath
1个回答
0
投票

我无法重现问题,因此在此答案中,我将发布用于测试的代码。也许您不正确地构建了P1P3曲线。

#include <cmath>
#include <QtWidgets>


class Widget: public QWidget
{
    Q_OBJECT
public:
    Widget(QWidget *parent=nullptr): 
        QWidget(parent),
        path_item(new QGraphicsPathItem),
        circle_item(new QGraphicsEllipseItem)
    {
        QDoubleSpinBox *radius_spinbox = new QDoubleSpinBox;
        radius_spinbox->setMinimum(0);
        radius_spinbox->setMaximum(10000);
        connect(radius_spinbox, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &Widget::updateRadius);

        QCheckBox *circle_checkbox = new QCheckBox("Circle visibility");

        QGraphicsScene *scene = new QGraphicsScene(this);
        QGraphicsView *view = new QGraphicsView(scene);
        view->scale(1, -1);
        view->setRenderHints(QPainter::Antialiasing);

        path_item->setBrush(QBrush(QColor("gray")));
        path_item->setPen(QPen(QColor("black"), 5));

        circle_item->setBrush(QBrush(QColor("salmon")));
        circle_item->setPen(QPen(QColor("red"), 5));

        scene->addItem(path_item);
        scene->addItem(circle_item);

        connect(circle_checkbox, &QCheckBox::toggled, [this](bool checked){
            circle_item->setVisible(checked);
        });

        circle_checkbox->setChecked(true);

        QVBoxLayout *lay = new QVBoxLayout(this);
        lay->addWidget(radius_spinbox);
        lay->addWidget(circle_checkbox);
        lay->addWidget(view);

        radius_spinbox->setValue(550);
    }
private:
    Q_SLOT void updateRadius(double radius){

        QPointF v1(100, 100);
        QPointF v2(0, 0);
        QPointF v3(400, -100);

        QPointF uu = (v1 + v3) / 2;

        QLineF nv = QLineF(uu, v3).normalVector();
        double d2 = radius * radius - nv.length() * nv.length();
        if(d2 < 0){
            qDebug() << "radius < d(v1, v3)";
            return;
        }
        QPointF c = nv.p1() + sqrt(d2) * (nv.p1() - nv.p2()) / nv.length();

        QRectF rectangle = QRectF(QPointF(), 2 * radius * QSizeF(1, 1));
        rectangle.moveCenter(c);

        double angle1 = QLineF(c, v3).angle();
        double angle2 = QLineF(c, v1).angle();

        QPainterPath path;
        path.moveTo(v1);
        path.lineTo(v2);
        path.lineTo(v3);
        path.arcTo(rectangle, angle1, angle2 - angle1);

        path_item->setPath(path);
        circle_item->setRect(rectangle.adjusted(5, 5, -5, -5));
    }
    QGraphicsPathItem *path_item;
    QGraphicsEllipseItem *circle_item;

};

int main(int argc, char *argv[]) {
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QApplication app(argc, argv);
    Widget w;
    w.resize(640, 480);
    w.show();
    return app.exec();
}

#include "main.moc"

enter image description here

enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.