15inline QPointF
lerp(
const QPointF&
p1,
const QPointF&
p2, qreal t)
17 return (1 - t) *
p1 + t *
p2;
21 qreal t, QPointF *
p1, QPointF *
p2,
22 QPointF *
p3, QPointF *p4, QPointF *p5)
35 for (
unsigned short j = 1; j <= 3; ++j) {
36 for (
unsigned short i = 0; i <= 3 - j; ++i) {
37 q[i] = (1.0 - t) * q[i] + t * q[i + 1];
54QPair<std::array<QPointF, 4>, std::array<QPointF, 4>>
splitAt(
const std::array<QPointF, 4>& points, qreal t)
56 QPointF newCP2, newCP1, splitP, splitCP1, splitCP2;
57 deCasteljau(points, t, &newCP2, &splitCP1, &splitP, &splitCP2, &newCP1);
58 return {{points[0], newCP2, splitCP1, splitP},
59 {splitP, splitCP2, newCP1, points[3]}};
64 , m_startingPoint(startingPoint)
65 , m_parametricCoords({QPointF(0, 0), {1, 0}, {1, 1}, {0, 1}})
70 : m_newPath(other.m_newPath)
71 , m_startingPoint(other.m_startingPoint)
72 , m_nodes(other.m_nodes)
73 , controlPoints(other.controlPoints)
74 , m_parametricCoords({QPointF(0, 0), {1, 0}, {1, 1}, {0, 1}})
130 path.cubicTo(i[1], i[2], i[3]);
137 return getPath().boundingRect();
147 std::array<QPointF, 4>
p;
148 std::array<QPointF, 4> curvedBoundary0;
149 std::array<QPointF, 4> curvedBoundary1;
151 QPointF midpointRuled0;
152 QPointF midpointRuled1;
169 std::reverse(curvedBoundary1.begin(), curvedBoundary1.end());
173 (curvedBoundary0[0] + curvedBoundary1[0]) / 2,
174 (curvedBoundary0[1] + curvedBoundary1[1]) / 2,
175 (curvedBoundary0[2] + curvedBoundary1[2]) / 2,
176 (curvedBoundary0[3] + curvedBoundary1[3]) / 2,
180 QPointF x_2_1 =
lerp(midpointRuled0, midpointRuled1, 1.0 / 3);
181 QPointF x_2_2 =
lerp(midpointRuled0, midpointRuled1, 2.0 / 3);
184 QPointF x_3_1 =
lerp(midCurved[0], midCurved[3], 1.0 / 3);
185 QPointF x_3_2 =
lerp(midCurved[0], midCurved[3], 2.0 / 3);
188 p[0] = midpointRuled0;
191 p[1] = midCurved[1] + x_2_1 - x_3_1;
194 p[2] = midCurved[2] + x_2_2 - x_3_2;
196 p[3] = midpointRuled1;
209 std::reverse(rMidHor.begin(), rMidHor.end());
215 QColor midc23 = colors[1];
216 QColor midc41 = colors[3];
232 subdivided.append(patch);
245 subdivided.append(patch);
256 std::reverse(rMidVer.begin(), rMidVer.end());
262 QColor midc12 = colors[0];
263 QColor midc34 = colors[2];
279 subdivided.append(patch);
292 subdivided.append(patch);
304 const QPair<std::array<QPointF, 4>, std::array<QPointF, 4>> splitTop =
segmentSplitAt(
Top, 0.5);
305 const QPair<std::array<QPointF, 4>, std::array<QPointF, 4>> splitRight =
segmentSplitAt(
Right, 0.5);
306 const QPair<std::array<QPointF, 4>, std::array<QPointF, 4>> splitBottom =
segmentSplitAt(
Bottom, 0.5);
307 const QPair<std::array<QPointF, 4>, std::array<QPointF, 4>> splitLeft =
segmentSplitAt(
Left, 0.5);
330 QPair<std::array<QPointF, 4>, std::array<QPointF, 4>> midHor =
splitAt(
getMidCurve(
false), 0.5);
331 QPair<std::array<QPointF, 4>, std::array<QPointF, 4>> midVer =
splitAt(
getMidCurve(
true), 0.5);
334 std::array<QPointF, 4> reversedMidHorFirst = midHor.first;
335 std::reverse(reversedMidHorFirst.begin(), reversedMidHorFirst.end());
336 std::array<QPointF, 4> reversedMidHorSecond = midHor.second;
337 std::reverse(reversedMidHorSecond.begin(), reversedMidHorSecond.end());
339 std::array<QPointF, 4> reversedMidVerFirst = midVer.first;
340 std::reverse(reversedMidVerFirst.begin(), reversedMidVerFirst.end());
341 std::array<QPointF, 4> reversedMidVerSecond = midVer.second;
342 std::reverse(reversedMidVerSecond.begin(), reversedMidVerSecond.end());
348 QColor midc12 = colors[0];
349 QColor midc23 = colors[1];
350 QColor midc34 = colors[2];
351 QColor midc41 = colors[3];
352 QColor center = colors[4];
359 QPointF centerP = 0.5 * (midTopP + midBottomP);
373 subdivided.append(patch);
387 subdivided.append(patch);
401 subdivided.append(patch);
408 patch->
addStop(reversedMidVerSecond, midc34,
Left);
415 subdivided.append(patch);
419 return QLineF(path[0], path[1]).length() +
420 QLineF(path[1], path[2]).length() +
421 QLineF(path[2], path[3]).length();
427 const qreal minlength = 1.7;
432 if ((line1 + control1 / 2) < minlength) {
438 if ((line2 + control2 / 2) < minlength) {
448 const qreal minlength = 1.7;
453 if ((line1 + control1 / 2) < minlength) {
459 if ((line2 + control2 / 2) < minlength) {
488 curveTo(pathPoints[1], pathPoints[2], pathPoints[3]);
510 m_nodes[type].point = newPath[0];
531 for (
int i = 0; i <
Size; ++i) {
533 for (
int j = 0; j < 4; ++j) {
553 const QByteArray buffer = d.toLatin1();
554 const char *ptr = buffer.constData();
557 qreal tox, toy, x1, y1, x2, y2;
558 bool relative =
false;
559 char command = *(ptr++);
582 if (pathIncomplete) {
611 if (pathIncomplete) {
616 curveTo(QPointF(x1, y1), QPointF(x2, y2), QPointF(tox, toy));
621 qWarning() <<
"SvgMeshPatch::parseMeshPath: Bad command \"" << command <<
"\"";
633 int integer, exponent;
647 else if (*ptr ==
'-') {
653 while (*ptr !=
'\0' && *ptr >=
'0' && *ptr <=
'9')
654 integer = (integer * 10) + *(ptr++) -
'0';
657 while (*ptr !=
'\0' && *ptr >=
'0' && *ptr <=
'9')
658 decimal += (*(ptr++) -
'0') * (frac *= 0.1);
661 if (*ptr ==
'e' || *ptr ==
'E') {
667 else if (*ptr ==
'-') {
673 while (*ptr !=
'\0' && *ptr >=
'0' && *ptr <=
'9') {
675 exponent += *ptr -
'0';
679 number = integer + decimal;
680 number *=
sign * pow((qreal)10, qreal(expsign * exponent));
QPair< std::array< QPointF, 4 >, std::array< QPointF, 4 > > splitAt(const std::array< QPointF, 4 > &points, qreal t)
static qreal controlrectLen(const SvgMeshPath &path)
QPointF lerp(const QPointF &p1, const QPointF &p2, qreal t)
void deCasteljau(const std::array< QPointF, 4 > &points, qreal t, QPointF *p1, QPointF *p2, QPointF *p3, QPointF *p4, QPointF *p5)
std::array< QPointF, 4 > SvgMeshPath
QSizeF size() const
Get size swept by mesh in pts.
QPainterPath getPath() const
Get full (closed) meshpath.
SvgMeshPatch(QPointF startingPoint)
Type
Position of stop in the patch.
QRectF boundingRect() const
const char * getCoord(const char *ptr, qreal &number)
QPointF getMidpointParametric(Type type) const
returns the midPoint in parametric space
void subdivideVertically(QVector< SvgMeshPatch * > &subdivided, const QVector< QColor > &colors) const
QPair< std::array< QPointF, 4 >, std::array< QPointF, 4 > > segmentSplitAt(Type type, qreal t) const
split a segment using De Casteljau's algorithm
QPointF m_startingPoint
This is the starting point for each path.
std::array< SvgMeshStop, Size > m_nodes
std::array< std::array< QPointF, 4 >, 4 > controlPoints
void subdivideHorizontally(QVector< SvgMeshPatch * > &subdivided, const QVector< QColor > &colors) const
void setTransform(const QTransform &matrix)
std::array< QPointF, 4 > m_parametricCoords
Coordinates in UV space.
void addStop(const QString &pathStr, QColor color, Type edge, bool pathIncomplete=false, QPointF lastPoint=QPointF())
void addStopLinear(const std::array< QPointF, 2 > &pathPoints, QColor color, Type edge)
Adds linear path to the shape.
std::array< QPointF, 4 > getMidCurve(bool isVertical) const
Gets the curve passing through the middle of meshpatch.
QPointF parseMeshPath(const QString &path, bool pathIncomplete=false, const QPointF lastPoint=QPointF())
void moveTo(const QPointF &p)
void modifyPath(SvgMeshPatch::Type type, std::array< QPointF, 4 > newPath)
void setStopColor(SvgMeshPatch::Type type, const QColor &color)
bool isDivisibleHorizontally() const
void subdivide(QVector< SvgMeshPatch * > &subdivided, const QVector< QColor > &colors) const
void curveTo(const QPointF &c1, const QPointF &c2, const QPointF &p)
add points as curve.
SvgMeshStop getStop(Type type) const
returns the starting point of the stop
bool isDivisibleVertically() const
void lineTo(const QPointF &p)
Helper to convert to a cubic curve internally.
QPointF segmentPointAt(Type type, qreal t) const
get the point on a segment using De Casteljau's algorithm
std::array< QPointF, 4 > getSegment(Type type) const
Get a segment of the path in the meshpatch.
void modifyCorner(SvgMeshPatch::Type type, const QPointF &delta)