QPainterPath - 创建以圆弧为边的凹面
QPainterPath - create concave areas with arcs as edges
我希望能够绘制由直线和弧线组成的填充区域。我对凸图形没有问题,但对凹图形有问题。这就是我要画的:
我可以很容易地画出轮廓。我使用我创建的 QPainterPath 中的笔画如下:
path = QPainterPath()
path.moveTo(v1)
path.lineTo(v2)
path.lineTo(v3)
path.arcTo(v1) #this is simplified
但我不能用同样的方法创建填充区域。因为 v3
和 v1
之间的圆弧圆心在图形之外。所以填充区域在左侧。
我已经尝试使用来自 this question 的弧的三次贝塞尔近似来创建它并取得了一些成功(左图)。不幸的是,这种近似并不完美,当圆弧超过圆的一半时,它会变得疯狂(再次在左侧)。 (右图)
如何使用 QPainterPath
创建第一张图片中的形状?
我无法重现该问题,因此在此答案中我将发布我用于测试的代码。也许你错误地构建了 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"
我希望能够绘制由直线和弧线组成的填充区域。我对凸图形没有问题,但对凹图形有问题。这就是我要画的:
我可以很容易地画出轮廓。我使用我创建的 QPainterPath 中的笔画如下:
path = QPainterPath()
path.moveTo(v1)
path.lineTo(v2)
path.lineTo(v3)
path.arcTo(v1) #this is simplified
但我不能用同样的方法创建填充区域。因为 v3
和 v1
之间的圆弧圆心在图形之外。所以填充区域在左侧。
我已经尝试使用来自 this question 的弧的三次贝塞尔近似来创建它并取得了一些成功(左图)。不幸的是,这种近似并不完美,当圆弧超过圆的一半时,它会变得疯狂(再次在左侧)。 (右图)
如何使用 QPainterPath
创建第一张图片中的形状?
我无法重现该问题,因此在此答案中我将发布我用于测试的代码。也许你错误地构建了 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"