最后,我实现了某种解决方法,基本上采用两条连接线,删除它们之间的连接点并用曲线替换它。由于我有很多小线,这样的变化是不可见的,我删除了所有非常短的线并重新连接开放端。该功能主要由 Bojan Kverh 提供,查看他的教程:https ://www.toptal.com/c-plus-plus/rounded-corners-bezier-curves-qpainter
这里的功能:
namespace
{
float distance(const QPointF& pt1, const QPointF& pt2)
{
float hd = (pt1.x() - pt2.x()) * (pt1.x() - pt2.x());
float vd = (pt1.y() - pt2.y()) * (pt1.y() - pt2.y());
return std::sqrt(hd + vd);
}
QPointF getLineStart(const QPointF& pt1, const QPointF& pt2)
{
QPointF pt;
float rat = 10.0 / distance(pt1, pt2);
if (rat > 0.5) {
rat = 0.5;
}
pt.setX((1.0 - rat) * pt1.x() + rat * pt2.x());
pt.setY((1.0 - rat) * pt1.y() + rat * pt2.y());
return pt;
}
QPointF getLineEnd(const QPointF& pt1, const QPointF& pt2)
{
QPointF pt;
float rat = 10.0 / distance(pt1, pt2);
if (rat > 0.5) {
rat = 0.5;
}
pt.setX(rat * pt1.x() + (1.0 - rat)*pt2.x());
pt.setY(rat * pt1.y() + (1.0 - rat)*pt2.y());
return pt;
}
}
void PainterPath::smoothOut(const float& factor)
{
QList<QPointF> points;
QPointF p;
for (int i = 0; i < mPath->elementCount() - 1; i++) {
p = QPointF(mPath->elementAt(i).x, mPath->elementAt(i).y);
// Except for first and last points, check what the distance between two
// points is and if its less then min, don't add them to the list.
if (points.count() > 1 && (i < mPath->elementCount() - 2) && (distance(points.last(), p) < factor)) {
continue;
}
points.append(p);
}
// Don't proceed if we only have 3 or less points.
if (points.count() < 3) {
return;
}
QPointF pt1;
QPointF pt2;
QPainterPath* path = new QPainterPath();
for (int i = 0; i < points.count() - 1; i++) {
pt1 = getLineStart(points[i], points[i + 1]);
if (i == 0) {
path->moveTo(pt1);
} else {
path->quadTo(points[i], pt1);
}
pt2 = getLineEnd(points[i], points[i + 1]);
path->lineTo(pt2);
}
delete mPath;
mPath = path;
prepareGeometryChange();
}