49 const QByteArray buffer = d.toLatin1();
50 const char *ptr = buffer.constData();
51 const char *end = buffer.constData() + buffer.length() + 1;
55 qreal contrlx, contrly, subpathx, subpathy, tox, toy, x1, y1, x2, y2, xc, yc;
56 qreal px1, py1, px2, py2, px3, py3;
58 char command = *(ptr++), lastCommand =
' ';
60 subpathx = subpathy = curx = cury = contrlx = contrly = 0.0;
76 subpathx = curx = relative ? curx + tox : tox;
77 subpathy = cury = relative ? cury + toy : toy;
92 curx = relative ? curx + tox : tox;
93 cury = relative ? cury + toy : toy;
159 px1 = relative ? curx + x1 : x1;
160 py1 = relative ? cury + y1 : y1;
161 px2 = relative ? curx + x2 : x2;
162 py2 = relative ? cury + y2 : y2;
163 px3 = relative ? curx + tox : tox;
164 py3 = relative ? cury + toy : toy;
168 contrlx = relative ? curx + x2 : x2;
169 contrly = relative ? cury + y2 : y2;
170 curx = relative ? curx + tox : tox;
171 cury = relative ? cury + toy : toy;
185 if (!(lastCommand ==
'c' || lastCommand ==
'C' ||
186 lastCommand ==
's' || lastCommand ==
'S')) {
192 px1 = 2 * curx - contrlx;
193 py1 = 2 * cury - contrly;
194 px2 = relative ? curx + x2 : x2;
195 py2 = relative ? cury + y2 : y2;
196 px3 = relative ? curx + tox : tox;
197 py3 = relative ? cury + toy : toy;
201 contrlx = relative ? curx + x2 : x2;
202 contrly = relative ? cury + y2 : y2;
203 curx = relative ? curx + tox : tox;
204 cury = relative ? cury + toy : toy;
219 px1 = relative ? (curx + 2 * (x1 + curx)) * (1.0 / 3.0) : (curx + 2 * x1) * (1.0 / 3.0);
220 py1 = relative ? (cury + 2 * (y1 + cury)) * (1.0 / 3.0) : (cury + 2 * y1) * (1.0 / 3.0);
221 px2 = relative ? ((curx + tox) + 2 * (x1 + curx)) * (1.0 / 3.0) : (tox + 2 * x1) * (1.0 / 3.0);
222 py2 = relative ? ((cury + toy) + 2 * (y1 + cury)) * (1.0 / 3.0) : (toy + 2 * y1) * (1.0 / 3.0);
223 px3 = relative ? curx + tox : tox;
224 py3 = relative ? cury + toy : toy;
228 contrlx = relative ? curx + x1 : x1;
229 contrly = relative ? cury + y1 : y1;
230 curx = relative ? curx + tox : tox;
231 cury = relative ? cury + toy : toy;
242 if (!(lastCommand ==
'q' || lastCommand ==
'Q' ||
243 lastCommand ==
't' || lastCommand ==
'T')) {
249 xc = 2 * curx - contrlx;
250 yc = 2 * cury - contrly;
252 px1 = (curx + 2 * xc) * (1.0 / 3.0);
253 py1 = (cury + 2 * yc) * (1.0 / 3.0);
254 px2 = relative ? ((curx + tox) + 2 * xc) * (1.0 / 3.0) : (tox + 2 * xc) * (1.0 / 3.0);
255 py2 = relative ? ((cury + toy) + 2 * yc) * (1.0 / 3.0) : (toy + 2 * yc) * (1.0 / 3.0);
256 px3 = relative ? curx + tox : tox;
257 py3 = relative ? cury + toy : toy;
263 curx = relative ? curx + tox : tox;
264 cury = relative ? cury + toy : toy;
273 bool largeArc =
false;
289 calculateArc(relative, curx, cury, angle, tox, toy, rx, ry, largeArc, sweep);
291 svgArcTo(tox, toy, rx, ry, angle, largeArc, sweep, !relative);
297 debugFlake <<
"KoSvgPathParser::parseSVG(): unknown command \"" << command <<
"\"";
302 lastCommand = command;
304 if (*ptr ==
'+' || *ptr ==
'-' || *ptr ==
'.' || (*ptr >=
'0' && *ptr <=
'9')) {
308 else if (command ==
'm')
313 if (lastCommand !=
'C' && lastCommand !=
'c' &&
314 lastCommand !=
'S' && lastCommand !=
's' &&
315 lastCommand !=
'Q' && lastCommand !=
'q' &&
316 lastCommand !=
'T' && lastCommand !=
't') {
418 const qreal angleRadians = angle * (
M_PI / 180.0);
419 const qreal sin_th = sin(angleRadians);
420 const qreal cos_th = cos(angleRadians);
425 dx = (curx - x) / 2.0;
434 dy = (cury - y) / 2.0;
443 const qreal x1Prime = cos_th * dx + sin_th * dy;
444 const qreal y1Prime = -sin_th * dx + cos_th * dy;
447 const qreal x1PrimeSq = x1Prime * x1Prime;
448 const qreal y1PrimeSq = y1Prime * y1Prime;
451 qreal rxSq = rx * rx;
452 qreal rySq = ry * ry;
456 const qreal check = x1PrimeSq / rxSq + y1PrimeSq / rySq;
459 rx = rx * sqrt(check);
460 ry = ry * sqrt(check);
467 const qreal radiiSq = rxSq * rySq;
468 const qreal ellipseValue = rxSq * y1PrimeSq + rySq * x1PrimeSq;
470 qreal coef = sqrt(std::fabs((radiiSq - ellipseValue) / ellipseValue));
471 if (sweepFlag == largeArcFlag) {
475 const qreal cxPrime = coef * (rx * y1Prime) / ry;
476 const qreal cyPrime = coef * -(ry * x1Prime) / rx;
480 const qreal cx = cos_th * cxPrime - sin_th * cyPrime + (curx + x2) * 0.5;
481 const qreal cy = sin_th * cxPrime + cos_th * cyPrime + (cury + y2) * 0.5;
484 const QPointF
v = {(x1Prime - cxPrime) / rx, (y1Prime - cyPrime) / ry};
488 qreal delta = std::fmod(
492 if (sweepFlag && delta < 0) {
494 }
else if (!sweepFlag && delta > 0) {
498 int n_segs = (int)ceil(fabs(delta / (
M_PI * 0.25)));
501 for (
int i = 0; i < n_segs; ++i) {
502 const qreal eta1 = theta + i * delta / n_segs;
503 const qreal eta2 = theta + (i + 1) * delta / n_segs;
505 const qreal etaHalf = 0.5 * (eta2 - eta1);
507 const qreal cosAngle = cos(angleRadians);
508 const qreal sinAngle = sin(angleRadians);
510 auto ellipseArcToPoint = [sinAngle, cosAngle](qreal cx, qreal cy, qreal eta, qreal rx, qreal ry) {
511 qreal x = cx + (rx * cosAngle * cos(eta)) - (ry * sinAngle * sin(eta));
512 qreal y = cy + (rx * sinAngle * cos(eta)) + (ry * cosAngle * sin(eta));
513 return QPointF(x, y);
515 auto ellipseDerivativeArcToPoint = [sinAngle, cosAngle](qreal eta, qreal rx, qreal ry) {
516 qreal x = -(rx * cosAngle * sin(eta)) - (ry * sinAngle * cos(eta));
517 qreal y = -(rx * sinAngle * sin(eta)) + (ry * cosAngle * cos(eta));
518 return QPointF(x, y);
522 const QPointF
p1 = ellipseArcToPoint(cx, cy, eta1, rx, ry);
523 const QPointF
p2 = ellipseArcToPoint(cx, cy, eta2, rx, ry);
525 const qreal alpha = sin(eta2 - eta1) * (sqrt(4 + 3 * tan(etaHalf) * tan(etaHalf)) - 1) / 3;
527 const QPointF
q1 =
p1 + alpha * ellipseDerivativeArcToPoint(eta1, rx, ry);
528 const QPointF
q2 =
p2 - alpha * ellipseDerivativeArcToPoint(eta2, rx, ry);