/* For general Scribus (>=1.3.2) copyright and licensing information please refer to the COPYING file provided with the program. Following this notice may exist a copyright and/or license notice that predates the release of Scribus 1.3.2 for which a new license (GPL+exception) is in place. */ /*************************************************************************** fpointarray.cpp - description ------------------- begin : Mit Jul 24 2002 copyright : (C) 2002 by Franz Schmid email : Franz.Schmid@altmuehlnet.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "fpointarray.h" #include #if defined(_MSC_VER) #define _USE_MATH_DEFINES #endif #include #include #include #include "util.h" using namespace std; FPointArray FPointArray::copy() const { FPointArray tmp; tmp << *this; tmp.count = count; tmp.capacity = capacity; return tmp; } FPointArray & FPointArray::operator=( const FPointArray &a ) { QVector::operator=(a); count = a.count; capacity = a.capacity; svgState = NULL; return *this; } bool FPointArray::resize(uint newCount) { if (newCount == 0) { QVector::resize(0); QVector::squeeze(); } else QVector::resize(newCount); capacity = newCount; count = newCount; return true; } bool FPointArray::setPoints( int nPoints, double firstx, double firsty, ... ) { va_list ap; if ( nPoints < 0 || !FPointArray::resize(nPoints) ) return false; setPoint( 0, firstx, firsty ); int i = 1; double x, y; nPoints--; va_start( ap, firsty ); while ( nPoints-- ) { x = static_cast(va_arg( ap, double )); y = static_cast(va_arg( ap, double )); setPoint( i++, x, y ); } va_end( ap ); return true; } bool FPointArray::putPoints( int index, int nPoints, double firstx, double firsty, ... ) { va_list ap; if ( index + nPoints > static_cast(count) ) { if ( !FPointArray::resize(index + nPoints) ) return false; } if ( nPoints <= 0 ) return true; setPoint( index, firstx, firsty ); // set first point int i = index + 1; double x, y; nPoints--; va_start( ap, firsty ); while ( nPoints-- ) { x = static_cast(va_arg(ap, double)); y = static_cast(va_arg(ap, double)); setPoint( i++, x, y ); } va_end( ap ); return true; } bool FPointArray::putPoints( int index, int nPoints, const FPointArray & from, int fromIndex ) { if ( index + nPoints > static_cast(count) ) { // extend array if ( !FPointArray::resize(index + nPoints) ) return false; } if ( nPoints <= 0 ) return true; Iterator p = begin(); p += index; ConstIterator q = from.begin(); q += fromIndex; while( --nPoints >= 0 ) { *p++ = *q++; } return true; } void FPointArray::point(uint i, double *x, double *y) const { // FPoint p = QMemArray::at(i); ConstIterator p = begin(); p += i; if (x) *x = p->xp; if (y) *y = p->yp; } QPoint FPointArray::pointQ(uint i) const { // FPoint p = QMemArray::at(i); ConstIterator p = begin(); p += i; QPoint r(qRound(p->xp),qRound(p->yp)); return r; } QPointF FPointArray::pointQF(uint i) const { // FPoint p = QMemArray::at(i); ConstIterator p = begin(); p += i; QPointF r(p->xp,p->yp); return r; } void FPointArray::translate( double dx, double dy ) { FPoint pt( dx, dy ); Iterator pend = begin(); pend += count; for (Iterator p = begin(); p != pend; p++) { if (p->x() < 900000) *p += pt; } } void FPointArray::scale( double sx, double sy ) { Iterator pend = begin(); pend += count; for (Iterator p = begin(); p != pend; p++) { if (p->x() < 900000) { p->setXY(p->x() * sx, p->y() * sy); } } } FPoint FPointArray::WidthHeight() const { if ( count == 0 ) return FPoint( 0.0, 0.0 ); // null rectangle ConstIterator pd = begin(); ConstIterator pend = begin(); pend += count; double minx, maxx, miny, maxy; minx = maxx = pd->xp; miny = maxy = pd->yp; for ( ++pd; pd != pend; ++pd ) { // find min+max x and y if (pd->xp > 900000) { continue; } if ( pd->xp < minx ) minx = pd->xp; else if ( pd->xp > maxx ) maxx = pd->xp; if ( pd->y() < miny ) miny = pd->yp; else if ( pd->yp > maxy ) maxy = pd->yp; } return FPoint(maxx - minx,maxy - miny); } void FPointArray::map( QMatrix m ) { const double m11 = m.m11(); const double m12 = m.m12(); const double m21 = m.m21(); const double m22 = m.m22(); const double dx = m.dx(); const double dy = m.dy(); double mx, my; Iterator pend = begin(); pend += count; for (Iterator p = begin(); p != pend; p++) { if (p->xp > 900000) { mx = p->xp; my = p->yp; } else { mx = m11 * p->xp + m21 * p->yp + dx; my = m22 * p->yp + m12 * p->xp + dy; } p->xp = mx; p->yp = my; } } void FPointArray::setMarker() { addQuadPoint(999999.0, 999999.0, 999999.0, 999999.0, 999999.0, 999999.0, 999999.0, 999999.0); } void FPointArray::addPoint(double x, double y) { FPointArray::resize(count+1); setPoint(count-1, x, y); } void FPointArray::addPoint(FPoint p) { FPointArray::resize(count+1); setPoint(count-1, p); } bool FPointArray::hasLastQuadPoint(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) const { int i = count-4; if (i < 0) return false; ConstIterator p = begin(); p += i; if (p->xp != x1 || p->yp != y1) return false; ++p; if (p->xp != x2 || p->yp != y2) return false; ++p; if (p->xp != x3 || p->yp != y3) return false; ++p; if (p->xp != x4 || p->yp != y4) return false; return true; } void FPointArray::addQuadPoint(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) { const int i = count; FPointArray::resize(count+4); Iterator p = begin(); p += i; p->setXY(x1, y1); ++p; p->setXY(x2, y2); ++p; p->setXY(x3, y3); ++p; p->setXY(x4, y4); } void FPointArray::addQuadPoint(FPoint p1, FPoint p2, FPoint p3, FPoint p4) { const int i = count; FPointArray::resize(count+4); Iterator p = begin(); p += i; *p++ = p1; *p++ = p2; *p++ = p3; *p = p4; } double FPointArray::lenPathSeg(int seg) const { FPoint p1 = point(seg); FPoint k1 = point(seg+1); FPoint p2 = point(seg+2); FPoint k2 = point(seg+3); FPoint newP, oldP; double newLen = 1; double oldLen = 0; double ts = 0.5; double t = 0.5; int iter = 2; while (true) { oldP = p1; newLen = 0; for (int dx = 0; dx < iter; ++dx) { double tm = 1.0 - t; newP = ((tm * tm * tm) * p1) + (3 * t * (tm * tm) * k1) + (3 * t * t * tm * k2 + t * t * t * p2); newLen += sqrt(pow(newP.x()-oldP.x(),2.0)+pow(newP.y()-oldP.y(),2.0)); oldP = newP; t += ts; } if (fabs(newLen - oldLen) < 0.01) break; oldLen = newLen; ts /= 2.0; iter *= 2; t = ts; } return newLen; } double FPointArray::lenPathDist(int seg, double t1, double t2) const { FPoint p1 = point(seg); FPoint k1 = point(seg+1); FPoint p2 = point(seg+2); FPoint k2 = point(seg+3); FPoint newP, oldP; double newLen = 0; double ts, t, tm; tm = 1.0 - t1; oldP = ((tm * tm * tm) * p1) + (3 * t1 * (tm * tm) * k1) + (3 * t1 * t1 * tm * k2 + t1 * t1 * t1 * p2); ts = (t2 - t1) / 100; t = t1 + ts; for (int dx = 0; dx < 99; ++dx) { tm = 1.0 - t; newP = ((tm * tm * tm) * p1) + (3 * t * (tm * tm) * k1) + (3 * t * t * tm * k2 + t * t * t * p2); newLen += sqrt(pow(newP.x()-oldP.x(),2.0)+pow(newP.y()-oldP.y(),2.0)); oldP = newP; t += ts; } return newLen; } void FPointArray::pointTangentNormalAt( int seg, double t, FPoint* p, FPoint* tn, FPoint* n ) const { // Calculate derivative if necessary. FPoint d; if( tn || n ) pointDerivativesAt( seg, t, p, &d, 0L ); else pointDerivativesAt( seg, t, p, 0L, 0L ); // Normalize derivative. if( tn || n ) { const double norm = sqrt( d.x() * d.x() + d.y() * d.y() ); d = norm ? d * ( 1.0 / norm ) : FPoint( 0.0, 0.0 ); } // Assign tangent vector. if( tn ) *tn = d; // Calculate normal vector. if( n ) { // Calculate vector product of "binormal" x tangent // (0,0,1) x (dx,dy,0), which is simply (dy,-dx,0). n->setX( d.y() ); n->setY( -d.x() ); } FPoint p1 = point(seg); FPoint k1 = point(seg+1); FPoint p2 = point(seg+2); FPoint k2 = point(seg+3); double tm = 1.0 - t; *p = ((tm * tm * tm) * p1) + (3 * t * (tm * tm) * k1) + (3 * (t * t) * tm * k2 + (t * t * t) * p2); } void FPointArray::pointDerivativesAt( int seg, double t, FPoint* p, FPoint* d1, FPoint* d2 ) const { // Copy points. FPoint* q = new FPoint[ 4 ]; q[ 0 ] = point(seg); q[ 1 ] = point(seg+1); q[ 3 ] = point(seg+2); q[ 2 ] = point(seg+3); // The De Casteljau algorithm. for( unsigned short j = 1; j <= 3; j++ ) { for( unsigned short i = 0; i <= 3 - j; i++ ) { q[ i ] = ( 1.0 - t ) * q[ i ] + t * q[ i + 1 ]; } // Save second derivative now that we have it. if( j == 1 ) { if( d2 ) *d2 = 6 * ( q[ 2 ] - 2 * q[ 1 ] + q[ 0 ] ); } // Save first derivative now that we have it. else if( j == 2 ) { if( d1 ) *d1 = 3 * ( q[ 1 ] - q[ 0 ] ); } } // Save point. if( p ) *p = q[ 0 ]; delete[]( q ); return; } bool FPointArray::operator==(const FPointArray &rhs) const { return count == rhs.count && capacity == rhs.capacity && QVector::operator==(rhs); } bool FPointArray::operator!=(const FPointArray &rhs) const { if (count != rhs.count) return true; if (capacity != rhs.capacity) return true; return QVector::operator!=(rhs); } struct SVGState { double CurrX, CurrY, StartX, StartY; bool FirstM, WasM, PathClosed; int PathLen; void reset(double x, double y) { CurrX = x; CurrY = y; StartX = x; StartY = y; PathLen = 0; } void move(double x, double y, int newPoints) { CurrX = x; CurrY = y; PathLen += newPoints; } bool needsMarker() { bool result = (!FirstM) && (WasM); if (result) PathLen += 4; return result; } }; QString FPointArray::svgPath() const { QString tmp = ""; FPoint np, np1, np2; bool nPath = true; if (size() > 3) { for (uint poi=0; poi < size()-3; poi += 4) { if (point(poi).x() > 900000) { // tmp += "Z "; nPath = true; continue; } if (nPath) { np = point(poi); tmp += "M"+QString::number(np.x())+" "+QString::number(np.y())+" "; nPath = false; } np = point(poi+1); tmp += "C"+QString::number(np.x())+" "+QString::number(np.y())+" "; np1 = point(poi+3); tmp += QString::number(np1.x())+" "+QString::number(np1.y())+" "; np2 = point(poi+2); tmp += QString::number(np2.x())+" "+QString::number(np2.y())+" "; } } return tmp; /* Xml_string result; bool hasPoint = false; double x, y, x1, y1, x2, y2, xe=0, ye=0; uint i=0; while (i < size()) { point(i++, &x, &y); if (x > 900000 && y > 900000) // marker for closepath { hasPoint = false; continue; } if (!hasPoint || x != xe || y != ye) // start a subpath { result += "M"; result += QString::number(x); result += " "; result += QString::number(y); result += "C"; hasPoint = true; } else result += " "; point(i++, &x1, &y1); point(i++, &x2, &y2); point(i++, &xe, &ye); result += QString::number(x1); result += " "; result += QString::number(y1); result += " "; result += QString::number(x2); result += " "; result += QString::number(y2); result += " "; result += QString::number(xe); result += " "; result += QString::number(ye); } return result; */ } QPainterPath FPointArray::toQPainterPath(bool closed) { QPainterPath m_path = QPainterPath(); bool nPath = true; bool first = true; FPoint np, np1, np2, np3; if (size() > 3) { for (uint poi = 0; poi < size()-3; poi += 4) { if (point(poi).x() > 900000) { nPath = true; continue; } if (nPath) { np = point(poi); if ((!first) && (closed)) m_path.closeSubpath(); m_path.moveTo(np.x(), np.y()); nPath = false; first = false; } np = point(poi); np1 = point(poi+1); np2 = point(poi+3); np3 = point(poi+2); if ((np == np1) && (np2 == np3)) m_path.lineTo(np3.x(), np3.y()); else m_path.cubicTo(np1.x(), np1.y(), np2.x(), np2.y(), np3.x(), np3.y()); } if (closed) m_path.closeSubpath(); } return m_path; } void FPointArray::fromQPainterPath(QPainterPath &path) { resize(0); svgInit(); for (int i = 0; i < path.elementCount(); ++i) { const QPainterPath::Element &elm = path.elementAt(i); switch (elm.type) { case QPainterPath::MoveToElement: if (svgState->WasM) svgClosePath(); svgState->WasM = true; svgMoveTo(elm.x, elm.y); break; case QPainterPath::LineToElement: svgLineTo(elm.x, elm.y); break; case QPainterPath::CurveToElement: svgCurveToCubic(elm.x, elm.y, path.elementAt(i+1).x, path.elementAt(i+1).y, path.elementAt(i+2).x, path.elementAt(i+2).y ); break; default: break; } } } FPointArray::~FPointArray() { if (svgState) delete svgState; } void FPointArray::svgInit() { if (!svgState) svgState = new SVGState; svgState->reset(0,0); svgState->FirstM = true; svgState->WasM = false; } void FPointArray::svgMoveTo(double x, double y) { svgState->reset(x, y); svgState->WasM = true; } void FPointArray::svgLineTo(double x1, double y1) { if (svgState->needsMarker()) { setMarker(); } svgState->FirstM = false; svgState->WasM = false; if (size() > 3) { FPoint b1 = point(size()-4); FPoint b2 = point(size()-3); FPoint b3 = point(size()-2); FPoint b4 = point(size()-1); FPoint n1 = FPoint(svgState->CurrX, svgState->CurrY); FPoint n2 = FPoint(x1, y1); if ((b1 == n1) && (b2 == n1) && (b3 == n2) && (b4 == n2)) return; } addPoint(FPoint(svgState->CurrX, svgState->CurrY)); addPoint(FPoint(svgState->CurrX, svgState->CurrY)); addPoint(FPoint(x1, y1)); addPoint(FPoint(x1, y1)); svgState->move(x1, y1, 4); } void FPointArray::svgCurveToCubic(double x1, double y1, double x2, double y2, double x3, double y3) { if (svgState->needsMarker()) { setMarker(); } svgState->FirstM = false; svgState->WasM = false; if (svgState->PathLen > 3) { FPoint b1 = point(size()-4); FPoint b2 = point(size()-3); FPoint b3 = point(size()-2); FPoint b4 = point(size()-1); FPoint n1 = FPoint(svgState->CurrX, svgState->CurrY); FPoint n2 = FPoint(x1, y1); FPoint n3 = FPoint(x3, y3); FPoint n4 = FPoint(x2, y2); if ((b1 == n1) && (b2 == n2) && (b3 == n3) && (b4 == n4)) return; } addPoint(FPoint(svgState->CurrX, svgState->CurrY)); addPoint(FPoint(x1, y1)); addPoint(FPoint(x3, y3)); addPoint(FPoint(x2, y2)); svgState->move(x3, y3, 4); } void FPointArray::svgClosePath() { if (svgState->PathLen > 2) { if ((svgState->PathLen == 4) || (point(size()-2).x() != svgState->StartX) || (point(size()-2).y() != svgState->StartY)) { addPoint(point(size()-2)); addPoint(point(size()-3)); addPoint(FPoint(svgState->StartX, svgState->StartY)); addPoint(FPoint(svgState->StartX, svgState->StartY)); } } } void FPointArray::svgArcTo(double r1, double r2, double angle, bool largeArcFlag, bool sweepFlag, double x1, double y1) { calculateArc(false, svgState->CurrX, svgState->CurrY, angle, x1, y1, r1, r2, largeArcFlag, sweepFlag); } void FPointArray::calculateArc(bool relative, double &curx, double &cury, double angle, double x, double y, double r1, double r2, bool largeArcFlag, bool sweepFlag) { double sin_th, cos_th; double a00, a01, a10, a11; double x0, y0, x1, y1, xc, yc; double d, sfactor, sfactor_sq; double th0, th1, th_arc; int i, n_segs; sin_th = sin(angle * (M_PI / 180.0)); cos_th = cos(angle * (M_PI / 180.0)); double dx; if(!relative) dx = (curx - x) / 2.0; else dx = -x / 2.0; double dy; if(!relative) dy = (cury - y) / 2.0; else dy = -y / 2.0; double _x1 = cos_th * dx + sin_th * dy; double _y1 = -sin_th * dx + cos_th * dy; double Pr1 = r1 * r1; double Pr2 = r2 * r2; double Px = _x1 * _x1; double Py = _y1 * _y1; // Spec : check if radii are large enough double check = Px / Pr1 + Py / Pr2; if(check > 1) { r1 = r1 * sqrt(check); r2 = r2 * sqrt(check); } a00 = cos_th / r1; a01 = sin_th / r1; a10 = -sin_th / r2; a11 = cos_th / r2; x0 = a00 * curx + a01 * cury; y0 = a10 * curx + a11 * cury; if(!relative) x1 = a00 * x + a01 * y; else x1 = a00 * (curx + x) + a01 * (cury + y); if(!relative) y1 = a10 * x + a11 * y; else y1 = a10 * (curx + x) + a11 * (cury + y); /* (x0, y0) is current point in transformed coordinate space. (x1, y1) is new point in transformed coordinate space. The arc fits a unit-radius circle in this space. */ d = (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0); sfactor_sq = 1.0 / d - 0.25; if(sfactor_sq < 0) sfactor_sq = 0; sfactor = sqrt(sfactor_sq); if(sweepFlag == largeArcFlag) sfactor = -sfactor; xc = 0.5 * (x0 + x1) - sfactor * (y1 - y0); yc = 0.5 * (y0 + y1) + sfactor * (x1 - x0); /* (xc, yc) is center of the circle. */ th0 = atan2(y0 - yc, x0 - xc); th1 = atan2(y1 - yc, x1 - xc); th_arc = th1 - th0; if(th_arc < 0 && sweepFlag) th_arc += 2 * M_PI; else if(th_arc > 0 && !sweepFlag) th_arc -= 2 * M_PI; n_segs = static_cast(ceil(fabs(th_arc / (M_PI * 0.5 + 0.001)))); for(i = 0; i < n_segs; i++) { { double sin_th, cos_th; double a00, a01, a10, a11; double x1, y1, x2, y2, x3, y3; double t; double th_half; double _th0 = th0 + i * th_arc / n_segs; double _th1 = th0 + (i + 1) * th_arc / n_segs; sin_th = sin(angle * (M_PI / 180.0)); cos_th = cos(angle * (M_PI / 180.0)); /* inverse transform compared with rsvg_path_arc */ a00 = cos_th * r1; a01 = -sin_th * r2; a10 = sin_th * r1; a11 = cos_th * r2; th_half = 0.5 * (_th1 - _th0); t = (8.0 / 3.0) * sin(th_half * 0.5) * sin(th_half * 0.5) / sin(th_half); x1 = xc + cos(_th0) - t * sin(_th0); y1 = yc + sin(_th0) + t * cos(_th0); x3 = xc + cos(_th1); y3 = yc + sin(_th1); x2 = x3 + t * sin(_th1); y2 = y3 - t * cos(_th1); svgCurveToCubic(a00 * x1 + a01 * y1, a10 * x1 + a11 * y1, a00 * x2 + a01 * y2, a10 * x2 + a11 * y2, a00 * x3 + a01 * y3, a10 * x3 + a11 * y3 ); } } if(!relative) curx = x; else curx += x; if(!relative) cury = y; else cury += y; } static const char * getCoord( const char *ptr, double &number ) { int integer, exponent; double decimal, frac; int sign, expsign; exponent = 0; integer = 0; frac = 1.0; decimal = 0; sign = 1; expsign = 1; // read the sign if(*ptr == '+') ptr++; else if(*ptr == '-') { ptr++; sign = -1; } // read the integer part while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9') integer = (integer * 10) + *(ptr++) - '0'; if(*ptr == '.') // read the decimals { ptr++; while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9') decimal += (*(ptr++) - '0') * (frac *= 0.1); } if(*ptr == 'e' || *ptr == 'E') // read the exponent part { ptr++; // read the sign of the exponent if(*ptr == '+') ptr++; else if(*ptr == '-') { ptr++; expsign = -1; } exponent = 0; while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9') { exponent *= 10; exponent += *ptr - '0'; ptr++; } } number = integer + decimal; number *= sign * pow( static_cast(10), static_cast( expsign * exponent ) ); // skip the following space if(*ptr == ' ') ptr++; return ptr; } bool FPointArray::parseSVG(const QString& svgPath) { QString d = svgPath; d = d.replace( QRegExp( "," ), " "); bool ret = false; if( !d.isEmpty() ) { d = d.simplified(); QByteArray pathData = d.toLatin1(); const char *ptr = pathData.constData(); const char *end = pathData.constData() + pathData.length() + 1; double contrlx, contrly, curx, cury, subpathx, subpathy, tox, toy, x1, y1, x2, y2, xc, yc; double px1, py1, px2, py2, px3, py3; bool relative; svgInit(); char command = *(ptr++), lastCommand = ' '; subpathx = subpathy = curx = cury = contrlx = contrly = 0.0; while( ptr < end ) { if( *ptr == ' ' ) ptr++; relative = false; switch( command ) { case 'm': relative = true; case 'M': { ptr = getCoord( ptr, tox ); ptr = getCoord( ptr, toy ); svgState->WasM = true; subpathx = curx = relative ? curx + tox : tox; subpathy = cury = relative ? cury + toy : toy; svgMoveTo(curx, cury ); break; } case 'l': relative = true; case 'L': { ptr = getCoord( ptr, tox ); ptr = getCoord( ptr, toy ); curx = relative ? curx + tox : tox; cury = relative ? cury + toy : toy; svgLineTo( curx, cury ); break; } case 'h': { ptr = getCoord( ptr, tox ); curx = curx + tox; svgLineTo( curx, cury ); break; } case 'H': { ptr = getCoord( ptr, tox ); curx = tox; svgLineTo( curx, cury ); break; } case 'v': { ptr = getCoord( ptr, toy ); cury = cury + toy; svgLineTo( curx, cury ); break; } case 'V': { ptr = getCoord( ptr, toy ); cury = toy; svgLineTo( curx, cury ); break; } case 'z': case 'Z': { curx = subpathx; cury = subpathy; svgClosePath(); break; } case 'c': relative = true; case 'C': { ptr = getCoord( ptr, x1 ); ptr = getCoord( ptr, y1 ); ptr = getCoord( ptr, x2 ); ptr = getCoord( ptr, y2 ); ptr = getCoord( ptr, tox ); ptr = getCoord( ptr, toy ); px1 = relative ? curx + x1 : x1; py1 = relative ? cury + y1 : y1; px2 = relative ? curx + x2 : x2; py2 = relative ? cury + y2 : y2; px3 = relative ? curx + tox : tox; py3 = relative ? cury + toy : toy; svgCurveToCubic( px1, py1, px2, py2, px3, py3 ); contrlx = relative ? curx + x2 : x2; contrly = relative ? cury + y2 : y2; curx = relative ? curx + tox : tox; cury = relative ? cury + toy : toy; break; } case 's': relative = true; case 'S': { ptr = getCoord( ptr, x2 ); ptr = getCoord( ptr, y2 ); ptr = getCoord( ptr, tox ); ptr = getCoord( ptr, toy ); px1 = 2 * curx - contrlx; py1 = 2 * cury - contrly; px2 = relative ? curx + x2 : x2; py2 = relative ? cury + y2 : y2; px3 = relative ? curx + tox : tox; py3 = relative ? cury + toy : toy; svgCurveToCubic( px1, py1, px2, py2, px3, py3 ); contrlx = relative ? curx + x2 : x2; contrly = relative ? cury + y2 : y2; curx = relative ? curx + tox : tox; cury = relative ? cury + toy : toy; break; } case 'q': relative = true; case 'Q': { ptr = getCoord( ptr, x1 ); ptr = getCoord( ptr, y1 ); ptr = getCoord( ptr, tox ); ptr = getCoord( ptr, toy ); px1 = relative ? (curx + 2 * (x1 + curx)) * (1.0 / 3.0) : (curx + 2 * x1) * (1.0 / 3.0); py1 = relative ? (cury + 2 * (y1 + cury)) * (1.0 / 3.0) : (cury + 2 * y1) * (1.0 / 3.0); px2 = relative ? ((curx + tox) + 2 * (x1 + curx)) * (1.0 / 3.0) : (tox + 2 * x1) * (1.0 / 3.0); py2 = relative ? ((cury + toy) + 2 * (y1 + cury)) * (1.0 / 3.0) : (toy + 2 * y1) * (1.0 / 3.0); px3 = relative ? curx + tox : tox; py3 = relative ? cury + toy : toy; svgCurveToCubic( px1, py1, px2, py2, px3, py3 ); contrlx = relative ? curx + x1 : (tox + 2 * x1) * (1.0 / 3.0); contrly = relative ? cury + y1 : (toy + 2 * y1) * (1.0 / 3.0); curx = relative ? curx + tox : tox; cury = relative ? cury + toy : toy; break; } case 't': relative = true; case 'T': { ptr = getCoord(ptr, tox); ptr = getCoord(ptr, toy); xc = 2 * curx - contrlx; yc = 2 * cury - contrly; px1 = relative ? (curx + 2 * xc) * (1.0 / 3.0) : (curx + 2 * xc) * (1.0 / 3.0); py1 = relative ? (cury + 2 * yc) * (1.0 / 3.0) : (cury + 2 * yc) * (1.0 / 3.0); px2 = relative ? ((curx + tox) + 2 * xc) * (1.0 / 3.0) : (tox + 2 * xc) * (1.0 / 3.0); py2 = relative ? ((cury + toy) + 2 * yc) * (1.0 / 3.0) : (toy + 2 * yc) * (1.0 / 3.0); px3 = relative ? curx + tox : tox; py3 = relative ? cury + toy : toy; svgCurveToCubic( px1, py1, px2, py2, px3, py3 ); contrlx = xc; contrly = yc; curx = relative ? curx + tox : tox; cury = relative ? cury + toy : toy; break; } case 'a': relative = true; case 'A': { bool largeArc, sweep; double angle, rx, ry; ptr = getCoord( ptr, rx ); ptr = getCoord( ptr, ry ); ptr = getCoord( ptr, angle ); ptr = getCoord( ptr, tox ); largeArc = tox == 1; ptr = getCoord( ptr, tox ); sweep = tox == 1; ptr = getCoord( ptr, tox ); ptr = getCoord( ptr, toy ); calculateArc( relative, curx, cury, angle, tox, toy, rx, ry, largeArc, sweep ); } } lastCommand = command; if(*ptr == '+' || *ptr == '-' || (*ptr >= '0' && *ptr <= '9')) { // there are still coords in this command if(command == 'M') command = 'L'; else if(command == 'm') command = 'l'; } else command = *(ptr++); if( lastCommand != 'C' && lastCommand != 'c' && lastCommand != 'S' && lastCommand != 's' && lastCommand != 'Q' && lastCommand != 'q' && lastCommand != 'T' && lastCommand != 't') { contrlx = curx; contrly = cury; } } if ((lastCommand != 'z') && (lastCommand != 'Z')) ret = true; if (size() > 2) { if ((point(0).x() == point(size()-2).x()) && (point(0).y() == point(size()-2).y())) ret = false; } } return ret; }