summaryrefslogtreecommitdiffstats
path: root/scribus/fpointarray.cpp
diff options
context:
space:
mode:
authorcraig <craig@11d20701-8431-0410-a711-e3c959e3b870>2012-01-01 11:40:09 +0000
committercraig <craig@11d20701-8431-0410-a711-e3c959e3b870>2012-01-01 11:40:09 +0000
commit7ed83b6c6666eb8b6b104c211ae7e52907350372 (patch)
tree4430b556abac0ad660a0aacf1887d77f85d8be02 /scribus/fpointarray.cpp
downloadscribus-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.cpp1127
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;
+
+}
+