diff options
| author | craig <craig@11d20701-8431-0410-a711-e3c959e3b870> | 2012-01-01 11:40:09 +0000 |
|---|---|---|
| committer | craig <craig@11d20701-8431-0410-a711-e3c959e3b870> | 2012-01-01 11:40:09 +0000 |
| commit | 7ed83b6c6666eb8b6b104c211ae7e52907350372 (patch) | |
| tree | 4430b556abac0ad660a0aacf1887d77f85d8be02 /scribus/fpointarray.cpp | |
| download | scribus-7ed83b6c6666eb8b6b104c211ae7e52907350372.tar.gz scribus-7ed83b6c6666eb8b6b104c211ae7e52907350372.tar.xz scribus-7ed83b6c6666eb8b6b104c211ae7e52907350372.zip | |
Branch 1.3.5 tree to 1.4.x tree, goodbye 1.3.x
git-svn-id: svn://scribus.net/branches/Version14x/Scribus@17163 11d20701-8431-0410-a711-e3c959e3b870
Diffstat (limited to 'scribus/fpointarray.cpp')
| -rw-r--r-- | scribus/fpointarray.cpp | 1127 |
1 files changed, 1127 insertions, 0 deletions
diff --git a/scribus/fpointarray.cpp b/scribus/fpointarray.cpp new file mode 100644 index 0000000..f1c3acb --- /dev/null +++ b/scribus/fpointarray.cpp @@ -0,0 +1,1127 @@ +/* +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 <cstdarg> + +#if defined(_MSC_VER) +#define _USE_MATH_DEFINES +#endif +#include <cmath> + +#include <QRegExp> +#include <QVector> + +#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<FPoint>::operator=(a); + count = a.count; + capacity = a.capacity; + svgState = NULL; + return *this; +} + +bool FPointArray::resize(uint newCount) +{ + if (newCount == 0) + { + QVector<FPoint>::resize(0); + QVector<FPoint>::squeeze(); + } + else + QVector<FPoint>::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<double>(va_arg( ap, double )); + y = static_cast<double>(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<int>(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<double>(va_arg(ap, double)); + y = static_cast<double>(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<int>(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<FPoint>::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<FPoint>::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<FPoint>::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<FPoint>::operator==(rhs); +} + +bool FPointArray::operator!=(const FPointArray &rhs) const +{ + if (count != rhs.count) + return true; + if (capacity != rhs.capacity) + return true; + return QVector<FPoint>::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<int>(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<double>(10), static_cast<double>( 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; + +} + |
