Here is the modified code from QtCharts which works well for me to return a
QPainterPath made from bezier curves. I don’t understand the algorithm but got
the code to work with no dependencies.
The only problem now is to smoothly vary the pen width along the path to
produce something like the attached image. Is there any way to produce vectors
like this in Qt5?
static QVector<qreal> firstControlPoints(const QVector<qreal>& vector)
{
QVector<qreal> result;
int count = vector.count();
result.resize(count);
result[0] = vector[0] / 2.0;
QVector<qreal> temp;
temp.resize(count);
temp[0] = 0;
qreal b = 2.0;
for (int i = 1; i < count; i++) {
temp[i] = 1 / b;
b = (i < count - 1 ? 4.0 : 3.5) - temp[i];
result[i] = (vector[i] - result[i - 1]) / b;
}
for (int i = 1; i < count; i++)
result[count - i - 1] -= temp[count - i] * result[count - i];
return result;
}
/*!
Calculates control points which are needed by QPainterPath.cubicTo function
to draw the cubic Bezier cureve between two points.
*/
static QVector<QPointF> calculateControlPoints(const QVector<QPointF> &points)
{
QVector<QPointF> controlPoints;
controlPoints.resize(points.count() * 2 - 2);
int n = points.count() - 1;
if (n == 1) {
//for n==1
controlPoints[0].setX((2 * points[0].x() + points[1].x()) / 3);
controlPoints[0].setY((2 * points[0].y() + points[1].y()) / 3);
controlPoints[1].setX(2 * controlPoints[0].x() - points[0].x());
controlPoints[1].setY(2 * controlPoints[0].y() - points[0].y());
return controlPoints;
}
// Calculate first Bezier control points
// Set of equations for P0 to Pn points.
//
// | 2 1 0 0 ... 0 0 0 ... 0 0 0 | | P1_1 |
| P0 + 2 * P1 |
// | 1 4 1 0 ... 0 0 0 ... 0 0 0 | | P1_2 |
| 4 * P1 + 2 * P2 |
// | 0 1 4 1 ... 0 0 0 ... 0 0 0 | | P1_3 |
| 4 * P2 + 2 * P3 |
// | . . . . . . . . . . . . | | ... |
| ... |
// | 0 0 0 0 ... 1 4 1 ... 0 0 0 | * | P1_i | =
| 4 * P(i-1) + 2 * Pi |
// | . . . . . . . . . . . . | | ... |
| ... |
// | 0 0 0 0 0 0 0 0 ... 1 4 1 | | P1_(n-1)|
| 4 * P(n-2) + 2 * P(n-1) |
// | 0 0 0 0 0 0 0 0 ... 0 2 7 | | P1_n |
| 8 * P(n-1) + Pn |
//
QVector<qreal> vector;
vector.resize(n);
vector[0] = points[0].x() + 2 * points[1].x();
for (int i = 1; i < n - 1; ++i)
vector[i] = 4 * points[i].x() + 2 * points[i + 1].x();
vector[n - 1] = (8 * points[n - 1].x() + points[n].x()) / 2.0;
QVector<qreal> xControl = firstControlPoints(vector);
vector[0] = points[0].y() + 2 * points[1].y();
for (int i = 1; i < n - 1; ++i)
vector[i] = 4 * points[i].y() + 2 * points[i + 1].y();
vector[n - 1] = (8 * points[n - 1].y() + points[n].y()) / 2.0;
QVector<qreal> yControl = firstControlPoints(vector);
for (int i = 0, j = 0; i < n; ++i, ++j) {
controlPoints[j].setX(xControl[i]);
controlPoints[j].setY(yControl[i]);
j++;
if (i < n - 1) {
controlPoints[j].setX(2 * points[i + 1].x() - xControl[i + 1]);
controlPoints[j].setY(2 * points[i + 1].y() - yControl[i + 1]);
} else {
controlPoints[j].setX((points[n].x() + xControl[n - 1]) / 2);
controlPoints[j].setY((points[n].y() + yControl[n - 1]) / 2);
}
}
return controlPoints;
}
QPainterPath splineFromPoints(const QVector<QPointF> &points, int penWidth)
{
QPainterPath splinePath;
QVector<QPointF> controlPoints;
if (points.count() >= 2)
controlPoints = calculateControlPoints(points);
if ((points.size() < 2) || (controlPoints.size() < 2)) {
return splinePath;
}
Q_ASSERT(points.count() * 2 - 2 == controlPoints.count());
// Use worst case scenario to determine required margin.
qreal margin = penWidth * 1.42;
splinePath.moveTo(points.at(0));
for (int i = 0; i < points.size() - 1; i++) {
const QPointF &point = points.at(i + 1);
splinePath.cubicTo(controlPoints[2 * i], controlPoints[2 * i + 1],
point);
}
return splinePath;
}
> On Feb 28, 2017, at 10:58 AM, Patrick Stinson <[email protected]> wrote:
>
> Wow wow wow. This is a great example for me to port. I am working in Python,
> and if I can get a working snippet I'll pass it on for sure.
>
> On Feb 28, 2017, at 8:38 AM, Mike Chinander <[email protected]
> <mailto:[email protected]>> wrote:
>
>> If you are doing this within a QGraphicsView, make sure you turn on
>> antialiasing <http://doc.qt.io/qt-5/qgraphicsview.html#renderHints-prop>.
>> Also, you might want to try a rounded join style
>> <http://doc.qt.io/qt-5/qpen.html#join-style> on the QPen you are using.
>> Posting an example of what you are getting now would help others help you.
>>
>> On Tue, Feb 21, 2017 at 4:17 AM, Patrick Stinson <[email protected]
>> <mailto:[email protected]>> wrote:
>> Hello!
>>
>> I am painting a series of connected QLineF's with varying vectors and
>> widths. Is there any way to smooth them out to be more vector-ish, so you
>> don't see the jagged transitions between the segments?
>>
>>
>>
>> This is for hand writing notes with the Apple Pencil. I have one segment per
>> event with pressure determining width and it just looks so jagged now...
>>
>>
>>
>> Thanks!
>>
>>
>> _______________________________________________
>> Interest mailing list
>> [email protected] <mailto:[email protected]>
>> http://lists.qt-project.org/mailman/listinfo/interest
>> <http://lists.qt-project.org/mailman/listinfo/interest>
>>
>>
>> _______________________________________________
>> Interest mailing list
>> [email protected] <mailto:[email protected]>
>> http://lists.qt-project.org/mailman/listinfo/interest
>> <http://lists.qt-project.org/mailman/listinfo/interest>
_______________________________________________
Interest mailing list
[email protected]
http://lists.qt-project.org/mailman/listinfo/interest