Krita Source Code Documentation
Loading...
Searching...
No Matches
SvgMeshPatch Class Reference

#include <SvgMeshPatch.h>

Public Types

enum  Type {
  Top = 0 , Right , Bottom , Left ,
  Size
}
 Position of stop in the patch. More...
 

Public Member Functions

void addStop (const QString &pathStr, QColor color, Type edge, bool pathIncomplete=false, QPointF lastPoint=QPointF())
 
void addStop (const std::array< QPointF, 4 > &pathPoints, QColor color, Type edge)
 Adds path to the shape.
 
void addStopLinear (const std::array< QPointF, 2 > &pathPoints, QColor color, Type edge)
 Adds linear path to the shape.
 
QRectF boundingRect () const
 
int countPoints () const
 
void curveTo (const QPointF &c1, const QPointF &c2, const QPointF &p)
 add points as curve.
 
std::array< QPointF, 4 > getMidCurve (bool isVertical) const
 Gets the curve passing through the middle of meshpatch.
 
QPointF getMidpointParametric (Type type) const
 returns the midPoint in parametric space
 
QPainterPath getPath () const
 Get full (closed) meshpath.
 
std::array< QPointF, 4 > getSegment (Type type) const
 Get a segment of the path in the meshpatch.
 
SvgMeshStop getStop (Type type) const
 returns the starting point of the stop
 
bool isDivisibleHorizontally () const
 
bool isDivisibleVertically () const
 
void lineTo (const QPointF &p)
 Helper to convert to a cubic curve internally.
 
void modifyCorner (SvgMeshPatch::Type type, const QPointF &delta)
 
void modifyPath (SvgMeshPatch::Type type, std::array< QPointF, 4 > newPath)
 
void moveTo (const QPointF &p)
 
QPointF segmentPointAt (Type type, qreal t) const
 get the point on a segment using De Casteljau's algorithm
 
QPair< std::array< QPointF, 4 >, std::array< QPointF, 4 > > segmentSplitAt (Type type, qreal t) const
 split a segment using De Casteljau's algorithm
 
void setStopColor (SvgMeshPatch::Type type, const QColor &color)
 
void setTransform (const QTransform &matrix)
 
QSizeF size () const
 Get size swept by mesh in pts.
 
void subdivide (QVector< SvgMeshPatch * > &subdivided, const QVector< QColor > &colors) const
 
void subdivideHorizontally (QVector< SvgMeshPatch * > &subdivided, const QVector< QColor > &colors) const
 
void subdivideVertically (QVector< SvgMeshPatch * > &subdivided, const QVector< QColor > &colors) const
 
 SvgMeshPatch (const SvgMeshPatch &other)
 
 SvgMeshPatch (QPointF startingPoint)
 

Private Member Functions

const char * getCoord (const char *ptr, qreal &number)
 
QPointF parseMeshPath (const QString &path, bool pathIncomplete=false, const QPointF lastPoint=QPointF())
 

Private Attributes

std::array< std::array< QPointF, 4 >, 4 > controlPoints
 
int counter {0}
 
bool m_newPath
 
std::array< SvgMeshStop, Sizem_nodes
 
std::array< QPointF, 4 > m_parametricCoords
 Coordinates in UV space.
 
QPointF m_startingPoint
 This is the starting point for each path.
 

Detailed Description

Definition at line 35 of file SvgMeshPatch.h.

Member Enumeration Documentation

◆ Type

Position of stop in the patch.

Enumerator
Top 
Right 
Bottom 
Left 
Size 

Definition at line 39 of file SvgMeshPatch.h.

39 {
40 Top = 0,
41 Right,
42 Bottom,
43 Left,
44 Size,
45 };

Constructor & Destructor Documentation

◆ SvgMeshPatch() [1/2]

SvgMeshPatch::SvgMeshPatch ( QPointF startingPoint)

Definition at line 62 of file SvgMeshPatch.cpp.

63 : m_newPath(true)
64 , m_startingPoint(startingPoint)
65 , m_parametricCoords({QPointF(0, 0), {1, 0}, {1, 1}, {0, 1}})
66{
67}
QPointF m_startingPoint
This is the starting point for each path.
std::array< QPointF, 4 > m_parametricCoords
Coordinates in UV space.

◆ SvgMeshPatch() [2/2]

SvgMeshPatch::SvgMeshPatch ( const SvgMeshPatch & other)

Definition at line 69 of file SvgMeshPatch.cpp.

70 : m_newPath(other.m_newPath)
72 , m_nodes(other.m_nodes)
74 , m_parametricCoords({QPointF(0, 0), {1, 0}, {1, 1}, {0, 1}})
75{
76}
std::array< SvgMeshStop, Size > m_nodes
std::array< std::array< QPointF, 4 >, 4 > controlPoints

Member Function Documentation

◆ addStop() [1/2]

void SvgMeshPatch::addStop ( const QString & pathStr,
QColor color,
Type edge,
bool pathIncomplete = false,
QPointF lastPoint = QPointF() )

Definition at line 466 of file SvgMeshPatch.cpp.

471{
472 SvgMeshStop node(color, m_startingPoint);
473 m_nodes[edge] = node;
474
475 m_startingPoint = parseMeshPath(pathStr, pathIncomplete, lastPoint);
476}
QPointF parseMeshPath(const QString &path, bool pathIncomplete=false, const QPointF lastPoint=QPointF())

References m_nodes, m_startingPoint, and parseMeshPath().

◆ addStop() [2/2]

void SvgMeshPatch::addStop ( const std::array< QPointF, 4 > & pathPoints,
QColor color,
Type edge )

Adds path to the shape.

Definition at line 478 of file SvgMeshPatch.cpp.

479{
480 SvgMeshStop stop(color, pathPoints[0]);
481 m_nodes[edge] = stop;
482
483 if (edge == SvgMeshPatch::Top) {
484 moveTo(pathPoints[0]);
485 m_newPath = false;
486 }
487
488 curveTo(pathPoints[1], pathPoints[2], pathPoints[3]);
489 m_startingPoint = pathPoints[3];
490}
void moveTo(const QPointF &p)
void curveTo(const QPointF &c1, const QPointF &c2, const QPointF &p)
add points as curve.

References curveTo(), m_newPath, m_nodes, m_startingPoint, moveTo(), and Top.

◆ addStopLinear()

void SvgMeshPatch::addStopLinear ( const std::array< QPointF, 2 > & pathPoints,
QColor color,
Type edge )

Adds linear path to the shape.

Definition at line 493 of file SvgMeshPatch.cpp.

494{
495 SvgMeshStop stop(color, pathPoints[0]);
496 m_nodes[edge] = stop;
497
498 if (edge == SvgMeshPatch::Top) {
499 moveTo(pathPoints[0]);
500 m_newPath = false;
501 }
502
503 lineTo(pathPoints[1]);
504 m_startingPoint = pathPoints[1];
505}
void lineTo(const QPointF &p)
Helper to convert to a cubic curve internally.

References lineTo(), m_newPath, m_nodes, m_startingPoint, moveTo(), and Top.

◆ boundingRect()

QRectF SvgMeshPatch::boundingRect ( ) const

Definition at line 135 of file SvgMeshPatch.cpp.

136{
137 return getPath().boundingRect();
138}
QPainterPath getPath() const
Get full (closed) meshpath.

References getPath().

◆ countPoints()

int SvgMeshPatch::countPoints ( ) const

Definition at line 539 of file SvgMeshPatch.cpp.

540{
541 return m_nodes.size();
542}

References m_nodes.

◆ curveTo()

void SvgMeshPatch::curveTo ( const QPointF & c1,
const QPointF & c2,
const QPointF & p )

add points as curve.

Definition at line 93 of file SvgMeshPatch.cpp.

94{
95 controlPoints[counter][1] = c1;
96 controlPoints[counter][2] = c2;
98 counter++;
99 if (counter < Size)
100 controlPoints[counter][0] = p;
101}
const Params2D p

References controlPoints, counter, p, and Size.

◆ getCoord()

const char * SvgMeshPatch::getCoord ( const char * ptr,
qreal & number )
private

Definition at line 630 of file SvgMeshPatch.cpp.

631{
632 // copied from KoPathShapeLoader, see the copyright above
633 int integer, exponent;
634 qreal decimal, frac;
635 int sign, expsign;
636
637 exponent = 0;
638 integer = 0;
639 frac = 1.0;
640 decimal = 0;
641 sign = 1;
642 expsign = 1;
643
644 // read the sign
645 if (*ptr == '+')
646 ++ptr;
647 else if (*ptr == '-') {
648 ++ptr;
649 sign = -1;
650 }
651
652 // read the integer part
653 while (*ptr != '\0' && *ptr >= '0' && *ptr <= '9')
654 integer = (integer * 10) + *(ptr++) - '0';
655 if (*ptr == '.') { // read the decimals
656 ++ptr;
657 while (*ptr != '\0' && *ptr >= '0' && *ptr <= '9')
658 decimal += (*(ptr++) - '0') * (frac *= 0.1);
659 }
660
661 if (*ptr == 'e' || *ptr == 'E') { // read the exponent part
662 ++ptr;
663
664 // read the sign of the exponent
665 if (*ptr == '+')
666 ++ptr;
667 else if (*ptr == '-') {
668 ++ptr;
669 expsign = -1;
670 }
671
672 exponent = 0;
673 while (*ptr != '\0' && *ptr >= '0' && *ptr <= '9') {
674 exponent *= 10;
675 exponent += *ptr - '0';
676 ++ptr;
677 }
678 }
679 number = integer + decimal;
680 number *= sign * pow((qreal)10, qreal(expsign * exponent));
681
682 // skip the following space
683 if (*ptr == ' ')
684 ++ptr;
685
686 return ptr;
687}

References sign().

◆ getMidCurve()

std::array< QPointF, 4 > SvgMeshPatch::getMidCurve ( bool isVertical) const

Gets the curve passing through the middle of meshpatch.

Definition at line 145 of file SvgMeshPatch.cpp.

146{
147 std::array<QPointF, 4> p;
148 std::array<QPointF, 4> curvedBoundary0;
149 std::array<QPointF, 4> curvedBoundary1;
150
151 QPointF midpointRuled0;
152 QPointF midpointRuled1;
153
154 if (isVertical) {
155 curvedBoundary0 = getSegment(Right);
156 curvedBoundary1 = getSegment(Left);
157
158 midpointRuled0 = segmentPointAt(Top, 0.5);
159 midpointRuled1 = segmentPointAt(Bottom, 0.5);
160 } else {
161 curvedBoundary0 = getSegment(Top);
162 curvedBoundary1 = getSegment(Bottom);
163
164 midpointRuled0 = segmentPointAt(Left, 0.5);
165 midpointRuled1 = segmentPointAt(Right, 0.5);
166 }
167
168 // we have to reverse it, cB1 & cB2 are in opposite direction
169 std::reverse(curvedBoundary1.begin(), curvedBoundary1.end());
170
171 // Sum of two Bezier curve is a Bezier curve
172 QVector<QPointF> midCurved = {
173 (curvedBoundary0[0] + curvedBoundary1[0]) / 2,
174 (curvedBoundary0[1] + curvedBoundary1[1]) / 2,
175 (curvedBoundary0[2] + curvedBoundary1[2]) / 2,
176 (curvedBoundary0[3] + curvedBoundary1[3]) / 2,
177 };
178
179 // line cutting the bilinear surface in middle
180 QPointF x_2_1 = lerp(midpointRuled0, midpointRuled1, 1.0 / 3);
181 QPointF x_2_2 = lerp(midpointRuled0, midpointRuled1, 2.0 / 3);
182
183 // line cutting rulled surface in middle
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);
186
187
188 p[0] = midpointRuled0;
189
190 // X_1 = x_1_1 + x_2_1 - x_3_1
191 p[1] = midCurved[1] + x_2_1 - x_3_1;
192
193 // X_2 = x_1_2 + x_2_2 - x_3_2
194 p[2] = midCurved[2] + x_2_2 - x_3_2;
195
196 p[3] = midpointRuled1;
197
198 return p;
199}
QPointF lerp(const QPointF &p1, const QPointF &p2, qreal t)
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.

References Bottom, getSegment(), Left, lerp(), p, Right, segmentPointAt(), and Top.

◆ getMidpointParametric()

QPointF SvgMeshPatch::getMidpointParametric ( Type type) const
inline

returns the midPoint in parametric space

Definition at line 62 of file SvgMeshPatch.h.

62 {
63 return (m_parametricCoords[type] + m_parametricCoords[(type + 1) % Size]) * 0.5;
64 }

◆ getPath()

QPainterPath SvgMeshPatch::getPath ( ) const

Get full (closed) meshpath.

Definition at line 125 of file SvgMeshPatch.cpp.

126{
127 QPainterPath path;
128 path.moveTo(controlPoints[Top][0]);
129 for (const auto& i: controlPoints) {
130 path.cubicTo(i[1], i[2], i[3]);
131 }
132 return path;
133}

References controlPoints, and Top.

◆ getSegment()

std::array< QPointF, 4 > SvgMeshPatch::getSegment ( Type type) const

Get a segment of the path in the meshpatch.

Definition at line 120 of file SvgMeshPatch.cpp.

121{
122 return controlPoints[type];
123}

References controlPoints.

◆ getStop()

SvgMeshStop SvgMeshPatch::getStop ( SvgMeshPatch::Type type) const

returns the starting point of the stop

Definition at line 103 of file SvgMeshPatch.cpp.

104{
105 return m_nodes[type];
106}

References m_nodes.

◆ isDivisibleHorizontally()

bool SvgMeshPatch::isDivisibleHorizontally ( ) const

Definition at line 445 of file SvgMeshPatch.cpp.

446{
447 // I arrived at this number by the virtue called trial 'n error
448 const qreal minlength = 1.7;
449
450 // a decent average, thanks to Khronos's forums
451 const qreal line1 = QLineF(controlPoints[Right][0], controlPoints[Right][3]).length();
452 const qreal control1 = controlrectLen(getSegment(Right));
453 if ((line1 + control1 / 2) < minlength) {
454 return false;
455 }
456
457 const qreal line2 = QLineF(controlPoints[Left][0], controlPoints[Left][3]).length();
458 const qreal control2 = controlrectLen(getSegment(Left));
459 if ((line2 + control2 / 2) < minlength) {
460 return false;
461 }
462
463 return true;
464}
static qreal controlrectLen(const SvgMeshPath &path)

References controlPoints, controlrectLen(), getSegment(), Left, and Right.

◆ isDivisibleVertically()

bool SvgMeshPatch::isDivisibleVertically ( ) const

Definition at line 424 of file SvgMeshPatch.cpp.

425{
426 // I arrived at this number by the virtue called trial 'n error
427 const qreal minlength = 1.7;
428 const qreal line1 = QLineF(controlPoints[Top][0], controlPoints[Top][3]).length();
429 const qreal control1 = controlrectLen(getSegment(Top));
430
431 // a decent average, thanks to Khronos's forums
432 if ((line1 + control1 / 2) < minlength) {
433 return false;
434 }
435
436 const qreal line2 = QLineF(controlPoints[Bottom][0], controlPoints[Bottom][3]).length();
437 const qreal control2 = controlrectLen(getSegment(Bottom));
438 if ((line2 + control2 / 2) < minlength) {
439 return false;
440 }
441
442 return true;
443}

References Bottom, controlPoints, controlrectLen(), getSegment(), and Top.

◆ lineTo()

void SvgMeshPatch::lineTo ( const QPointF & p)

Helper to convert to a cubic curve internally.

Definition at line 83 of file SvgMeshPatch.cpp.

84{
85 controlPoints[counter][1] = lerp(controlPoints[counter][0], p, 1.0 / 3);
86 controlPoints[counter][2] = lerp(controlPoints[counter][0], p, 2.0 / 3);
88 counter++;
89 if (counter < Size)
91}

References controlPoints, counter, lerp(), p, and Size.

◆ modifyCorner()

void SvgMeshPatch::modifyCorner ( SvgMeshPatch::Type type,
const QPointF & delta )

Definition at line 513 of file SvgMeshPatch.cpp.

514{
515 controlPoints[type][0] -= delta;
516 controlPoints[type][1] -= delta;
517 m_nodes[type].point = controlPoints[type][0];
518
519 controlPoints[(Size + type - 1) % Size][3] -= delta;
520 controlPoints[(Size + type - 1) % Size][2] -= delta;
521}

References controlPoints, m_nodes, and Size.

◆ modifyPath()

void SvgMeshPatch::modifyPath ( SvgMeshPatch::Type type,
std::array< QPointF, 4 > newPath )

Definition at line 507 of file SvgMeshPatch.cpp.

508{
509 controlPoints[type] = newPath;
510 m_nodes[type].point = newPath[0];
511}

References controlPoints, and m_nodes.

◆ moveTo()

void SvgMeshPatch::moveTo ( const QPointF & p)

Definition at line 78 of file SvgMeshPatch.cpp.

79{
81}

References controlPoints, counter, and p.

◆ parseMeshPath()

QPointF SvgMeshPatch::parseMeshPath ( const QString & path,
bool pathIncomplete = false,
const QPointF lastPoint = QPointF() )
private

Definition at line 545 of file SvgMeshPatch.cpp.

546{
547 // bits and pieces from KoPathShapeLoader, see the copyright above
548 if (!s.isEmpty()) {
549 QString d = s;
550 d.replace(',', ' ');
551 d = d.simplified();
552
553 const QByteArray buffer = d.toLatin1();
554 const char *ptr = buffer.constData();
555 qreal curx = m_startingPoint.x();
556 qreal cury = m_startingPoint.y();
557 qreal tox, toy, x1, y1, x2, y2;
558 bool relative = false;
559 char command = *(ptr++);
560
561 if (m_newPath) {
563 m_newPath = false;
564 }
565
566 while (*ptr == ' ')
567 ++ptr;
568
569 switch (command) {
570 case 'l':
571 relative = true;
572 Q_FALLTHROUGH();
573 case 'L': {
574 ptr = getCoord(ptr, tox);
575 ptr = getCoord(ptr, toy);
576
577 if (relative) {
578 tox = curx + tox;
579 toy = cury + toy;
580 }
581
582 if (pathIncomplete) {
583 tox = lastPoint.x();
584 toy = lastPoint.y();
585 }
586
587 // we convert lines to cubic curve
588 lineTo({tox, toy});
589 break;
590 }
591 case 'c':
592 relative = true;
593 Q_FALLTHROUGH();
594 case 'C': {
595 ptr = getCoord(ptr, x1);
596 ptr = getCoord(ptr, y1);
597 ptr = getCoord(ptr, x2);
598 ptr = getCoord(ptr, y2);
599 ptr = getCoord(ptr, tox);
600 ptr = getCoord(ptr, toy);
601
602 if (relative) {
603 x1 = curx + x1;
604 y1 = cury + y1;
605 x2 = curx + x2;
606 y2 = cury + y2;
607 tox = curx + tox;
608 toy = cury + toy;
609 }
610
611 if (pathIncomplete) {
612 tox = lastPoint.x();
613 toy = lastPoint.y();
614 }
615
616 curveTo(QPointF(x1, y1), QPointF(x2, y2), QPointF(tox, toy));
617 break;
618 }
619
620 default: {
621 qWarning() << "SvgMeshPatch::parseMeshPath: Bad command \"" << command << "\"";
622 return QPointF();
623 }
624 }
625 return {tox, toy};
626 }
627 return QPointF();
628}
const char * getCoord(const char *ptr, qreal &number)

References curveTo(), getCoord(), lineTo(), m_newPath, m_startingPoint, and moveTo().

◆ segmentPointAt()

QPointF SvgMeshPatch::segmentPointAt ( Type type,
qreal t ) const

get the point on a segment using De Casteljau's algorithm

Definition at line 108 of file SvgMeshPatch.cpp.

109{
110 QPointF p;
111 deCasteljau(controlPoints[type], t, 0, 0, &p, 0, 0);
112 return p;
113}
void deCasteljau(const std::array< QPointF, 4 > &points, qreal t, QPointF *p1, QPointF *p2, QPointF *p3, QPointF *p4, QPointF *p5)

References controlPoints, deCasteljau(), and p.

◆ segmentSplitAt()

QPair< std::array< QPointF, 4 >, std::array< QPointF, 4 > > SvgMeshPatch::segmentSplitAt ( Type type,
qreal t ) const

split a segment using De Casteljau's algorithm

Definition at line 115 of file SvgMeshPatch.cpp.

116{
117 return splitAt(controlPoints[type], t);
118}
QPair< std::array< QPointF, 4 >, std::array< QPointF, 4 > > splitAt(const std::array< QPointF, 4 > &points, qreal t)

References controlPoints, and splitAt().

◆ setStopColor()

void SvgMeshPatch::setStopColor ( SvgMeshPatch::Type type,
const QColor & color )

Definition at line 523 of file SvgMeshPatch.cpp.

524{
525 m_nodes[type].color = color;
526}

References m_nodes.

◆ setTransform()

void SvgMeshPatch::setTransform ( const QTransform & matrix)

Definition at line 528 of file SvgMeshPatch.cpp.

529{
530 m_startingPoint = matrix.map(m_startingPoint);
531 for (int i = 0; i < Size; ++i) {
532 m_nodes[i].point = matrix.map(m_nodes[i].point);
533 for (int j = 0; j < 4; ++j) {
534 controlPoints[i][j] = matrix.map(controlPoints[i][j]);
535 }
536 }
537}

References controlPoints, m_nodes, m_startingPoint, and Size.

◆ size()

QSizeF SvgMeshPatch::size ( ) const

Get size swept by mesh in pts.

Definition at line 140 of file SvgMeshPatch.cpp.

141{
142 return boundingRect().size();
143}
QRectF boundingRect() const

References boundingRect().

◆ subdivide()

void SvgMeshPatch::subdivide ( QVector< SvgMeshPatch * > & subdivided,
const QVector< QColor > & colors ) const

Definition at line 295 of file SvgMeshPatch.cpp.

297{
298 KIS_ASSERT(colors.size() == 5);
299
300 // The orientation is left to right and top to bottom, which means
301 // Eg. the first part of splitTop is TopLeft and the second part is TopRight
302 // Similarly the first part of splitRight is RightTop, but the first part of
303 // splitLeft is splitLeft.second (once again, in Top to Bottom convention)
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);
308
309 // The way the curve and the colors at the corners are arranged before and after subdivision
310 //
311 // midc12
312 // c1 + c2
313 // +---------------+
314 // | | |
315 // | | midVer|
316 // | | < |
317 // midc41 +---------------+ midc23
318 // | ^ | |
319 // | midHor| |
320 // | | |
321 // +---------------+
322 // c4 + c3
323 // midc43
324 //
325 //
326 // midHor --> left to right
327 // midVer --> top to bottom
328
329
330 QPair<std::array<QPointF, 4>, std::array<QPointF, 4>> midHor = splitAt(getMidCurve(/*isVertical = */ false), 0.5);
331 QPair<std::array<QPointF, 4>, std::array<QPointF, 4>> midVer = splitAt(getMidCurve(/*isVertical = */ true), 0.5);
332
333 // middle curve is shared among the two, so we need both directions
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());
338
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());
343
344 QColor c1 = getStop(Top).color;
345 QColor c2 = getStop(Right).color;
346 QColor c3 = getStop(Bottom).color;
347 QColor c4 = getStop(Left).color;
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];
353
354 // mid points in parametric space
355 QPointF midTopP = getMidpointParametric(Top);
356 QPointF midRightP = getMidpointParametric(Right);
357 QPointF midBottomP = getMidpointParametric(Bottom);
358 QPointF midLeftP = getMidpointParametric(Left);
359 QPointF centerP = 0.5 * (midTopP + midBottomP);
360
361 // patch 1: TopLeft/NorthWest
362 SvgMeshPatch *patch = new SvgMeshPatch(splitTop.first[0]);
363 patch->addStop(splitTop.first, c1, Top);
364 patch->addStop(midVer.first, midc12, Right);
365 patch->addStop(reversedMidHorFirst, center, Bottom);
366 patch->addStop(splitLeft.second, midc41, Left);
367 patch->m_parametricCoords = {
369 midTopP,
370 centerP,
371 midLeftP
372 };
373 subdivided.append(patch);
374
375 // patch 2: TopRight/NorthRight
376 patch = new SvgMeshPatch(splitTop.second[0]);
377 patch->addStop(splitTop.second, midc12, Top);
378 patch->addStop(splitRight.first, c2, Right);
379 patch->addStop(reversedMidHorSecond, midc23, Bottom);
380 patch->addStop(reversedMidVerFirst, center, Left);
381 patch->m_parametricCoords = {
382 midTopP,
384 midRightP,
385 centerP
386 };
387 subdivided.append(patch);
388
389 // patch 3: BottomLeft/SouthWest
390 patch = new SvgMeshPatch(midHor.first[0]);
391 patch->addStop(midHor.first, midc41, Top);
392 patch->addStop(midVer.second, center, Right);
393 patch->addStop(splitBottom.second, midc34, Bottom);
394 patch->addStop(splitLeft.first, c4, Left);
395 patch->m_parametricCoords = {
396 midLeftP,
397 centerP,
398 midBottomP,
400 };
401 subdivided.append(patch);
402
403 // patch 4: BottomRight/SouthEast
404 patch = new SvgMeshPatch(midHor.second[0]);
405 patch->addStop(midHor.second, center, Top);
406 patch->addStop(splitRight.second, midc23, Right);
407 patch->addStop(splitBottom.first, c3, Bottom);
408 patch->addStop(reversedMidVerSecond, midc34, Left);
409 patch->m_parametricCoords = {
410 centerP,
411 midRightP,
413 midBottomP
414 };
415 subdivided.append(patch);
416}
SvgMeshPatch(QPointF startingPoint)
QPointF getMidpointParametric(Type type) const
returns the midPoint in parametric space
QPair< std::array< QPointF, 4 >, std::array< QPointF, 4 > > segmentSplitAt(Type type, qreal t) const
split a segment using De Casteljau's algorithm
void addStop(const QString &pathStr, QColor color, Type edge, bool pathIncomplete=false, QPointF lastPoint=QPointF())
std::array< QPointF, 4 > getMidCurve(bool isVertical) const
Gets the curve passing through the middle of meshpatch.
SvgMeshStop getStop(Type type) const
returns the starting point of the stop
#define KIS_ASSERT(cond)
Definition kis_assert.h:33

References addStop(), Bottom, SvgMeshStop::color, getMidCurve(), getMidpointParametric(), getStop(), KIS_ASSERT, Left, m_parametricCoords, Right, segmentSplitAt(), splitAt(), SvgMeshPatch(), and Top.

◆ subdivideHorizontally()

void SvgMeshPatch::subdivideHorizontally ( QVector< SvgMeshPatch * > & subdivided,
const QVector< QColor > & colors ) const

Definition at line 201 of file SvgMeshPatch.cpp.

203{
204 const QPair<SvgMeshPath, SvgMeshPath> splitRight = segmentSplitAt(Right, 0.5);
205 const QPair<SvgMeshPath, SvgMeshPath> splitLeft = segmentSplitAt(Left, 0.5);
206
207 SvgMeshPath midHor = getMidCurve(/*isVertical = */ false);
208 SvgMeshPath rMidHor = midHor;
209 std::reverse(rMidHor.begin(), rMidHor.end());
210
211 QColor c1 = getStop(Top).color;
212 QColor c2 = getStop(Right).color;
213 QColor c3 = getStop(Bottom).color;
214 QColor c4 = getStop(Left).color;
215 QColor midc23 = colors[1];
216 QColor midc41 = colors[3];
217
218 QPointF midRightParametric = getMidpointParametric(Right);
219 QPointF midLeftParametric = getMidpointParametric(Left);
220
221 SvgMeshPatch *patch = new SvgMeshPatch(getSegment(Top)[0]);
222 patch->addStop(getSegment(Top), c1, Top);
223 patch->addStop(splitRight.first, c2, Right);
224 patch->addStop(rMidHor, midc23, Bottom);
225 patch->addStop(splitLeft.second, midc41, Left);
226 patch->m_parametricCoords = {
229 midRightParametric,
230 midLeftParametric
231 };
232 subdivided.append(patch);
233
234 patch = new SvgMeshPatch(midHor[0]);
235 patch->addStop(midHor, midc41, Top);
236 patch->addStop(splitRight.second, midc23, Right);
237 patch->addStop(getSegment(Bottom), c3, Bottom);
238 patch->addStop(splitLeft.first,c4, Left);
239 patch->m_parametricCoords = {
240 midLeftParametric,
241 midRightParametric,
244 };
245 subdivided.append(patch);
246}
std::array< QPointF, 4 > SvgMeshPath

References addStop(), Bottom, SvgMeshStop::color, getMidCurve(), getMidpointParametric(), getSegment(), getStop(), Left, m_parametricCoords, Right, segmentSplitAt(), SvgMeshPatch(), and Top.

◆ subdivideVertically()

void SvgMeshPatch::subdivideVertically ( QVector< SvgMeshPatch * > & subdivided,
const QVector< QColor > & colors ) const

Definition at line 248 of file SvgMeshPatch.cpp.

250{
251 const QPair<SvgMeshPath, SvgMeshPath> splitTop = segmentSplitAt(Top, 0.5);
252 const QPair<SvgMeshPath, SvgMeshPath> splitBottom = segmentSplitAt(Bottom, 0.5);
253
254 SvgMeshPath midVer = getMidCurve(/*isVertical = */ true);
255 SvgMeshPath rMidVer = midVer;
256 std::reverse(rMidVer.begin(), rMidVer.end());
257
258 QColor c1 = getStop(Top).color;
259 QColor c2 = getStop(Right).color;
260 QColor c3 = getStop(Bottom).color;
261 QColor c4 = getStop(Left).color;
262 QColor midc12 = colors[0];
263 QColor midc34 = colors[2];
264
265 QPointF midTopParametric = getMidpointParametric(Top);
266 QPointF midBottomParametric = getMidpointParametric(Bottom);
267
268 SvgMeshPatch *patch = new SvgMeshPatch(splitTop.first[0]);
269 patch->addStop(splitTop.first, c1, Top);
270 patch->addStop(midVer, midc12, Right);
271 patch->addStop(splitBottom.second, midc34, Bottom);
272 patch->addStop(getSegment(Left), c4, Left);
273 patch->m_parametricCoords = {
275 midTopParametric,
276 midBottomParametric,
278 };
279 subdivided.append(patch);
280
281 patch = new SvgMeshPatch(splitTop.second[0]);
282 patch->addStop(splitTop.second, midc12, Top);
283 patch->addStop(getSegment(Right), c2, Right);
284 patch->addStop(splitBottom.first, c3, Bottom);
285 patch->addStop(rMidVer, midc34, Left);
286 patch->m_parametricCoords = {
287 midTopParametric,
290 midBottomParametric
291 };
292 subdivided.append(patch);
293}

References addStop(), Bottom, SvgMeshStop::color, getMidCurve(), getMidpointParametric(), getSegment(), getStop(), Left, m_parametricCoords, Right, segmentSplitAt(), SvgMeshPatch(), and Top.

Member Data Documentation

◆ controlPoints

std::array<std::array<QPointF, 4>, 4> SvgMeshPatch::controlPoints
private

Definition at line 134 of file SvgMeshPatch.h.

◆ counter

int SvgMeshPatch::counter {0}
private

Definition at line 128 of file SvgMeshPatch.h.

128{0};

◆ m_newPath

bool SvgMeshPatch::m_newPath
private

Definition at line 127 of file SvgMeshPatch.h.

◆ m_nodes

std::array<SvgMeshStop, Size> SvgMeshPatch::m_nodes
private

Definition at line 133 of file SvgMeshPatch.h.

◆ m_parametricCoords

std::array<QPointF, 4> SvgMeshPatch::m_parametricCoords
private

Coordinates in UV space.

Definition at line 136 of file SvgMeshPatch.h.

◆ m_startingPoint

QPointF SvgMeshPatch::m_startingPoint
private

This is the starting point for each path.

Definition at line 131 of file SvgMeshPatch.h.


The documentation for this class was generated from the following files: