Back to index

scribus-ng  1.3.4.dfsg+svn20071115
fpointarray.cpp
Go to the documentation of this file.
00001 /*
00002 For general Scribus (>=1.3.2) copyright and licensing information please refer
00003 to the COPYING file provided with the program. Following this notice may exist
00004 a copyright and/or license notice that predates the release of Scribus 1.3.2
00005 for which a new license (GPL+exception) is in place.
00006 */
00007 /***************************************************************************
00008                           fpointarray.cpp  -  description
00009                              -------------------
00010     begin                : Mit Jul 24 2002
00011     copyright            : (C) 2002 by Franz Schmid
00012     email                : Franz.Schmid@altmuehlnet.de
00013  ***************************************************************************/
00014 
00015 /***************************************************************************
00016  *                                                                         *
00017  *   This program is free software; you can redistribute it and/or modify  *
00018  *   it under the terms of the GNU General Public License as published by  *
00019  *   the Free Software Foundation; either version 2 of the License, or     *
00020  *   (at your option) any later version.                                   *
00021  *                                                                         *
00022  ***************************************************************************/
00023 
00024 #include "fpointarray.h"
00025 #include <cstdarg>
00026 #include <math.h>
00027 #include <qregexp.h>
00028 
00029 #include "util.h"
00030 
00031 using namespace std;
00032 
00033 
00034 FPointArray FPointArray::copy() const
00035 { 
00036        FPointArray tmp; 
00037        tmp.duplicate(*this);
00038        tmp.count = count;
00039        tmp.capacity = capacity;
00040        return tmp; 
00041 }
00042 
00043 
00044 FPointArray & FPointArray::operator=( const FPointArray &a )
00045 { 
00046        assign( a );
00047        count = a.count; 
00048        capacity = a.capacity;
00049        svgState = NULL;
00050        return *this; 
00051 }
00052 
00053 
00054 /* optimized for speed:
00055  *   never shrink
00056  *   when growing, try to double size
00057  *   if capacity permits, just increase count
00058  */
00059 bool FPointArray::resize(uint newCount)
00060 {
00061        if (newCount <= capacity) {
00062               count = newCount;
00063               return true;
00064        }
00065        else if (newCount <= 2*capacity && QMemArray<FPoint>::resize(2*capacity)) {
00066               capacity *= 2;
00067               count = newCount;
00068               return true;
00069        }
00070        else if (QMemArray<FPoint>::resize(newCount)) {
00071               capacity = newCount;
00072               count = newCount;
00073               return true;
00074        }
00075        else {
00076               sDebug(QString("Failed resize(): count=%1 capacity=%2 newCount=%3").arg(count).arg(capacity).arg(newCount));
00077               return false;
00078        }
00079 }
00080 
00081 
00082 bool FPointArray::setPoints( int nPoints, double firstx, double firsty, ... )
00083 {
00084        va_list ap;
00085        if ( nPoints < 0 || !FPointArray::resize(nPoints) )
00086               return false;
00087        setPoint( 0, firstx, firsty );
00088        int i = 1;
00089        double x, y;
00090        nPoints--;
00091        va_start( ap, firsty );
00092        while ( nPoints-- )
00093        {
00094               x = static_cast<double>(va_arg( ap, double ));
00095               y = static_cast<double>(va_arg( ap, double ));
00096               setPoint( i++, x, y );
00097     }
00098        va_end( ap );
00099        return true;
00100 }
00101 
00102 bool FPointArray::putPoints( int index, int nPoints, double firstx, double firsty,  ... )
00103 {
00104        va_list ap;
00105        if ( index + nPoints > static_cast<int>(count) )
00106        {
00107               if ( !FPointArray::resize(index + nPoints) )
00108                      return false;
00109        }
00110        if ( nPoints <= 0 )
00111               return true;
00112        setPoint( index, firstx, firsty );        // set first point
00113        int i = index + 1;
00114        double x, y;
00115        nPoints--;
00116        va_start( ap, firsty );
00117        while ( nPoints-- )
00118        {
00119               x = static_cast<double>(va_arg(ap, double));
00120               y = static_cast<double>(va_arg(ap, double));
00121               setPoint( i++, x, y );
00122        }
00123        va_end( ap );
00124        return true;
00125 }
00126 
00127 bool FPointArray::putPoints( int index, int nPoints, const FPointArray & from, int fromIndex )
00128 {
00129        if ( index + nPoints > static_cast<int>(count) )
00130        {      // extend array
00131               if ( !FPointArray::resize(index + nPoints) )
00132                      return false;
00133        }
00134        if ( nPoints <= 0 )
00135               return true;
00136        Iterator p = begin();
00137        p += index;
00138        ConstIterator q = from.begin();
00139        q += fromIndex;
00140        while( --nPoints >= 0 )
00141        {
00142               *p++ = *q++;
00143     }
00144        return true;
00145 }
00146 
00147 void FPointArray::point(uint i, double *x, double *y) const
00148 {
00149 //     FPoint p = QMemArray<FPoint>::at(i);
00150        ConstIterator p = begin();
00151        p += i;
00152        if (x)
00153               *x = p->xp;
00154        if (y)
00155               *y = p->yp;
00156 }
00157 
00158 
00159 QPoint FPointArray::pointQ(uint i) const
00160 {
00161 //     FPoint p = QMemArray<FPoint>::at(i);
00162        ConstIterator p = begin();
00163        p += i;
00164        QPoint r(qRound(p->xp),qRound(p->yp));
00165        return r;
00166 }
00167 
00168 void FPointArray::translate( double dx, double dy )
00169 {
00170        FPoint pt( dx, dy );
00171        Iterator pend = begin();
00172        pend += count;
00173        for (Iterator p = begin(); p != pend; p++)
00174        {
00175               if (p->x() < 900000)
00176                      *p += pt;
00177        }
00178 }
00179 
00180 void FPointArray::scale( double sx, double sy )
00181 {
00182        Iterator pend = begin();
00183        pend += count;
00184        for (Iterator p = begin(); p != pend; p++)
00185        {
00186               if (p->x() < 900000) {
00187                      p->setXY(p->x() * sx, p->y() * sy);
00188               }
00189        }
00190 }
00191 
00192 
00193 FPoint FPointArray::WidthHeight() const
00194 {
00195        if ( count == 0 )
00196               return FPoint( 0.0, 0.0 );         // null rectangle
00197        ConstIterator pd = begin();
00198        ConstIterator pend = begin();
00199        pend += count;
00200        double minx, maxx, miny, maxy;
00201        minx = maxx = pd->xp;
00202        miny = maxy = pd->yp;
00203        for ( ++pd; pd != pend; ++pd )
00204        {      // find min+max x and y
00205               if (pd->xp > 900000)
00206               {
00207                      continue;
00208               }
00209               if ( pd->xp < minx )
00210                      minx = pd->xp;
00211               else
00212                      if ( pd->xp > maxx )
00213                      maxx = pd->xp;
00214               if ( pd->y() < miny )
00215                      miny = pd->yp;
00216               else
00217                      if ( pd->yp > maxy )
00218                      maxy = pd->yp;
00219     }
00220        return FPoint(maxx - minx,maxy - miny);
00221 }
00222 
00223 void FPointArray::map( QWMatrix m )
00224 {
00225        const double m11 = m.m11();
00226        const double m12 = m.m12();
00227        const double m21 = m.m21();
00228        const double m22 = m.m22();
00229        const double dx  = m.dx();
00230        const double dy  = m.dy();
00231        double mx, my;
00232        Iterator pend = begin();
00233        pend += count;
00234        for (Iterator p = begin(); p != pend; p++)
00235        {
00236               if (p->xp > 900000)
00237               {
00238                      mx = p->xp;
00239                      my = p->yp;
00240               }
00241               else
00242               {
00243                      mx = m11 * p->xp + m21 * p->yp + dx;
00244                      my = m22 * p->yp + m12 * p->xp + dy;
00245               }
00246               p->xp = mx;
00247               p->yp = my;
00248        }
00249 }
00250 
00251 void FPointArray::setMarker()
00252 {
00253        addQuadPoint(999999.0, 999999.0,
00254                             999999.0, 999999.0,
00255                             999999.0, 999999.0,
00256                             999999.0, 999999.0);
00257 }
00258 
00259 void FPointArray::addPoint(double x, double y)
00260 {
00261        FPointArray::resize(count+1);
00262        setPoint(count-1, x, y);
00263 }
00264 
00265 void FPointArray::addPoint(FPoint p)
00266 {
00267        FPointArray::resize(count+1);
00268        setPoint(count-1, p);
00269 }
00270 
00271 
00272 bool FPointArray::hasLastQuadPoint(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) const
00273 {
00274        int i = count-4;
00275        if (i < 0)
00276               return false;
00277        ConstIterator p = begin();
00278        p += i;
00279        if (p->xp != x1 || p->yp != y1)
00280               return false;
00281        ++p; 
00282        if (p->xp != x2 || p->yp != y2)
00283               return false;
00284        ++p; 
00285        if (p->xp != x3 || p->yp != y3)
00286               return false;
00287        ++p; 
00288        if (p->xp != x4 || p->yp != y4)
00289               return false;
00290        
00291        return true;
00292 }
00293 
00294 void FPointArray::addQuadPoint(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
00295 {
00296        const int i = count;
00297        FPointArray::resize(count+4);
00298        Iterator p = begin();
00299        p += i;
00300        p->setXY(x1, y1);
00301        ++p;
00302        p->setXY(x2, y2);
00303        ++p;
00304        p->setXY(x3, y3);
00305        ++p;
00306        p->setXY(x4, y4);
00307 }
00308 
00309 void FPointArray::addQuadPoint(FPoint p1, FPoint p2, FPoint p3, FPoint p4)
00310 {
00311        const int i = count;
00312        FPointArray::resize(count+4);
00313        Iterator p = begin();
00314        p += i;
00315        *p++ = p1;
00316        *p++ = p2;
00317        *p++ = p3;
00318        *p = p4;
00319 }
00320 
00321 double FPointArray::lenPathSeg(int seg) const
00322 {
00323        FPoint p1 = point(seg);
00324        FPoint k1 = point(seg+1);
00325        FPoint p2 = point(seg+2);
00326        FPoint k2 = point(seg+3);
00327        FPoint newP, oldP;
00328        double newLen = 1;
00329        double oldLen = 0;
00330        double ts = 0.5;
00331        double t = 0.5;
00332        int iter = 2;
00333        while (true)
00334        {
00335               oldP = p1;
00336               newLen = 0;
00337               for (int dx = 0; dx < iter; ++dx)
00338               {
00339                      double tm = 1.0 - t;
00340                      newP = ((tm * tm * tm) * p1) + (3 * t * (tm * tm) * k1) + (3 * t * t * tm * k2 + t * t * t * p2);
00341                      newLen += sqrt(pow(newP.x()-oldP.x(),2.0)+pow(newP.y()-oldP.y(),2.0));
00342                      oldP = newP;
00343                      t += ts;
00344               }
00345               if (fabs(newLen - oldLen) < 0.01)
00346                      break;
00347               oldLen = newLen;
00348               ts /= 2.0;
00349               iter *= 2;
00350               t = ts;
00351        }
00352        return newLen;
00353 }
00354 
00355 double FPointArray::lenPathDist(int seg, double t1, double t2) const
00356 {
00357        FPoint p1 = point(seg);
00358        FPoint k1 = point(seg+1);
00359        FPoint p2 = point(seg+2);
00360        FPoint k2 = point(seg+3);
00361        FPoint newP, oldP;
00362        double newLen = 0;
00363        double ts, t, tm;
00364        tm = 1.0 - t1;
00365        oldP = ((tm * tm * tm) * p1) + (3 * t1 * (tm * tm) * k1) + (3 * t1 * t1 * tm * k2 + t1 * t1 * t1 * p2);
00366        ts = (t2 - t1) / 100;
00367        t = t1 + ts;
00368        for (int dx = 0; dx < 99; ++dx)
00369        {
00370               tm = 1.0 - t;
00371               newP = ((tm * tm * tm) * p1) + (3 * t * (tm * tm) * k1) + (3 * t * t * tm * k2 + t * t * t * p2);
00372               newLen += sqrt(pow(newP.x()-oldP.x(),2.0)+pow(newP.y()-oldP.y(),2.0));
00373               oldP = newP;
00374               t += ts;
00375        }
00376        return newLen;
00377 }
00378 
00379 void FPointArray::pointTangentNormalAt( int seg, double t, FPoint* p, FPoint* tn, FPoint* n ) const
00380 {
00381        // Calculate derivative if necessary.
00382        FPoint d;
00383        if( tn || n )
00384               pointDerivativesAt( seg, t, p, &d, 0L );
00385        else
00386               pointDerivativesAt( seg, t, p, 0L, 0L );
00387        // Normalize derivative.
00388        if( tn || n )
00389        {
00390               const double norm = sqrt( d.x() * d.x() + d.y() * d.y() );
00391               d = norm ? d * ( 1.0 / norm ) : FPoint( 0.0, 0.0 );
00392        }
00393        // Assign tangent vector.
00394        if( tn )
00395               *tn = d;
00396        // Calculate normal vector.
00397        if( n )
00398        {
00399               // Calculate vector product of "binormal" x tangent
00400               // (0,0,1) x (dx,dy,0), which is simply (dy,-dx,0).
00401               n->setX( d.y() );
00402               n->setY( -d.x() );
00403        }
00404        FPoint p1 = point(seg);
00405        FPoint k1 = point(seg+1);
00406        FPoint p2 = point(seg+2);
00407        FPoint k2 = point(seg+3);
00408        double tm = 1.0 - t;
00409        *p = ((tm * tm * tm) * p1) + (3 * t * (tm * tm) * k1) + (3 * (t * t) * tm * k2 + (t * t * t) * p2);
00410 }
00411 
00412 void FPointArray::pointDerivativesAt( int seg, double t, FPoint* p, FPoint* d1, FPoint* d2 ) const
00413 {
00414        // Copy points.
00415        FPoint* q = new FPoint[ 4 ];
00416        q[ 0 ] = point(seg);
00417        q[ 1 ] = point(seg+1);
00418        q[ 3 ] = point(seg+2);
00419        q[ 2 ] = point(seg+3);
00420        // The De Casteljau algorithm.
00421        for( unsigned short j = 1; j <= 3; j++ )
00422        {
00423               for( unsigned short i = 0; i <= 3 - j; i++ )
00424               {
00425                      q[ i ] = ( 1.0 - t ) * q[ i ] + t * q[ i + 1 ];
00426               }
00427               // Save second derivative now that we have it.
00428               if( j == 1 )
00429               {
00430                      if( d2 )
00431                             *d2 = 6 * ( q[ 2 ] - 2 * q[ 1 ] + q[ 0 ] );
00432               }
00433               // Save first derivative now that we have it.
00434               else if( j == 2 )
00435               {
00436                      if( d1 )
00437                             *d1 = 3 * ( q[ 1 ] - q[ 0 ] );
00438               }
00439        }
00440        // Save point.
00441        if( p )
00442               *p = q[ 0 ];
00443        delete[]( q );
00444        return;
00445 }
00446 
00447 bool FPointArray::operator==(const FPointArray &rhs) const
00448 {
00449        return count == rhs.count && 
00450               capacity == rhs.capacity &&
00451               QMemArray<FPoint>::operator==(rhs);
00452 }
00453 
00454 bool FPointArray::operator!=(const FPointArray &rhs) const
00455 {
00456        if (count != rhs.count)
00457               return true;
00458        if (capacity != rhs.capacity)
00459               return true;
00460        return QMemArray<FPoint>::operator!=(rhs);
00461 }
00462 
00463 
00464 struct SVGState
00465 {
00466        double CurrX, CurrY, StartX, StartY;
00467        bool FirstM, WasM, PathClosed;
00468        int PathLen;
00469        
00470        void reset(double x, double y)
00471        {
00472               CurrX = x;
00473               CurrY = y;
00474               StartX = x;
00475               StartY = y;
00476               PathLen = 0;
00477        }
00478        
00479        void move(double x, double y, int newPoints)
00480        {
00481               CurrX = x;
00482               CurrY = y;
00483               PathLen += newPoints;
00484        }
00485        
00486        bool needsMarker()
00487        {
00488               bool result = (!FirstM) && (WasM);
00489               if (result)
00490                      PathLen += 4;
00491               return result;
00492        }
00493 };
00494 
00495 
00496 QString FPointArray::svgPath() const
00497 {
00498        QString tmp = "";
00499        FPoint np, np1, np2;
00500        bool nPath = true;
00501        if (size() > 3)
00502        {
00503               for (uint poi=0; poi < size()-3; poi += 4)
00504               {
00505                      if (point(poi).x() > 900000)
00506                      {
00507 //                          tmp += "Z ";
00508                             nPath = true;
00509                             continue;
00510                      }
00511                      if (nPath)
00512                      {
00513                             np = point(poi);
00514                             tmp += "M"+QString::number(np.x())+" "+QString::number(np.y())+" ";
00515                             nPath = false;
00516                      }
00517                      np = point(poi+1);
00518                      tmp += "C"+QString::number(np.x())+" "+QString::number(np.y())+" ";
00519                      np1 = point(poi+3);
00520                      tmp += QString::number(np1.x())+" "+QString::number(np1.y())+" ";
00521                      np2 = point(poi+2);
00522                      tmp += QString::number(np2.x())+" "+QString::number(np2.y())+" ";
00523               }
00524        }
00525        return tmp;
00526 /*     Xml_string result;
00527        bool hasPoint = false;
00528        double x, y, x1, y1, x2, y2, xe=0, ye=0; 
00529        uint i=0;
00530        while (i < size())
00531        {
00532               point(i++, &x, &y);
00533               if (x > 900000 && y > 900000)  // marker for closepath
00534               {
00535                      hasPoint = false;
00536                      continue;
00537               }
00538               if (!hasPoint || x != xe || y != ye) // start a subpath
00539               {
00540                      result += "M";
00541                      result += QString::number(x);
00542                      result += " ";
00543                      result += QString::number(y);
00544                      result += "C";
00545                      hasPoint = true;
00546               }
00547               else 
00548                      result += " ";
00549               
00550               point(i++, &x1, &y1);
00551               point(i++, &x2, &y2);
00552               point(i++, &xe, &ye);
00553               result += QString::number(x1);
00554               result += " ";
00555               result += QString::number(y1);
00556               result += " ";
00557               result += QString::number(x2);
00558               result += " ";
00559               result += QString::number(y2);
00560               result += " ";
00561               result += QString::number(xe);
00562               result += " ";
00563               result += QString::number(ye);
00564        }
00565        return result;       */
00566 }
00567 
00568 
00569 FPointArray::~FPointArray()
00570 {
00571        if (svgState)
00572               delete svgState;
00573 }
00574 
00575 
00576 void FPointArray::svgInit()
00577 {
00578        if (!svgState)
00579               svgState = new SVGState;
00580        svgState->reset(0,0);
00581        svgState->FirstM = true;
00582        svgState->WasM = false;
00583 }
00584 
00585 
00586 void FPointArray::svgMoveTo(double x, double y)
00587 {
00588        svgState->reset(x, y);
00589        svgState->WasM = true;
00590 }
00591 
00592 
00593 void FPointArray::svgLineTo(double x1, double y1)
00594 {
00595        if (svgState->needsMarker())
00596        {
00597               setMarker();
00598        }
00599        svgState->FirstM = false;
00600        svgState->WasM = false;
00601        if (size() > 3)
00602        {
00603               FPoint b1 = point(size()-4);
00604               FPoint b2 = point(size()-3);
00605               FPoint b3 = point(size()-2);
00606               FPoint b4 = point(size()-1);
00607               FPoint n1 = FPoint(svgState->CurrX, svgState->CurrY);
00608               FPoint n2 = FPoint(x1, y1);
00609               if ((b1 == n1) && (b2 == n1) && (b3 == n2) && (b4 == n2))
00610                      return;
00611        }
00612        addPoint(FPoint(svgState->CurrX, svgState->CurrY));
00613        addPoint(FPoint(svgState->CurrX, svgState->CurrY));
00614        addPoint(FPoint(x1, y1));
00615        addPoint(FPoint(x1, y1));
00616        svgState->move(x1, y1, 4);
00617 }
00618 
00619 
00620 void FPointArray::svgCurveToCubic(double x1, double y1, double x2, double y2, double x3, double y3)
00621 {
00622        if (svgState->needsMarker())
00623        {
00624               setMarker();
00625        }
00626        svgState->FirstM = false;
00627        svgState->WasM = false;
00628        if (svgState->PathLen > 3)
00629        {
00630               FPoint b1 = point(size()-4);
00631               FPoint b2 = point(size()-3);
00632               FPoint b3 = point(size()-2);
00633               FPoint b4 = point(size()-1);
00634               FPoint n1 = FPoint(svgState->CurrX, svgState->CurrY);
00635               FPoint n2 = FPoint(x1, y1);
00636               FPoint n3 = FPoint(x3, y3);
00637               FPoint n4 = FPoint(x2, y2);
00638               if ((b1 == n1) && (b2 == n2) && (b3 == n3) && (b4 == n4))
00639                      return;
00640        }
00641        addPoint(FPoint(svgState->CurrX, svgState->CurrY));
00642        addPoint(FPoint(x1, y1));
00643        addPoint(FPoint(x3, y3));
00644        addPoint(FPoint(x2, y2));
00645        svgState->move(x3, y3, 4);
00646 }
00647 
00648 
00649 void FPointArray::svgClosePath()
00650 {
00651        if (svgState->PathLen > 2)
00652        {
00653               if ((svgState->PathLen == 4) || (point(size()-2).x() != svgState->StartX) || (point(size()-2).y() != svgState->StartY))
00654               {
00655                      addPoint(point(size()-2));
00656                      addPoint(point(size()-3));
00657                      addPoint(FPoint(svgState->StartX, svgState->StartY));
00658                      addPoint(FPoint(svgState->StartX, svgState->StartY));
00659               }
00660        }
00661 }
00662 
00663 void FPointArray::svgArcTo(double r1, double r2, double angle, bool largeArcFlag, bool sweepFlag, double x1, double y1)
00664 {
00665        calculateArc(false, svgState->CurrX, svgState->CurrY, angle, x1, y1, r1, r2, largeArcFlag, sweepFlag);
00666 }
00667 
00668 void FPointArray::calculateArc(bool relative, double &curx, double &cury, double angle, 
00669                                                     double x, double y, double r1, double r2, bool largeArcFlag, bool sweepFlag)
00670 {
00671        double sin_th, cos_th;
00672        double a00, a01, a10, a11;
00673        double x0, y0, x1, y1, xc, yc;
00674        double d, sfactor, sfactor_sq;
00675        double th0, th1, th_arc;
00676        int i, n_segs;
00677        sin_th = sin(angle * (M_PI / 180.0));
00678        cos_th = cos(angle * (M_PI / 180.0));
00679        double dx;
00680        if(!relative)
00681               dx = (curx - x) / 2.0;
00682        else
00683               dx = -x / 2.0;
00684        double dy;
00685        if(!relative)
00686               dy = (cury - y) / 2.0;
00687        else
00688               dy = -y / 2.0;
00689        double _x1 =  cos_th * dx + sin_th * dy;
00690        double _y1 = -sin_th * dx + cos_th * dy;
00691        double Pr1 = r1 * r1;
00692        double Pr2 = r2 * r2;
00693        double Px = _x1 * _x1;
00694        double Py = _y1 * _y1;
00695        // Spec : check if radii are large enough
00696        double check = Px / Pr1 + Py / Pr2;
00697        if(check > 1)
00698        {
00699               r1 = r1 * sqrt(check);
00700               r2 = r2 * sqrt(check);
00701        }
00702        a00 = cos_th / r1;
00703        a01 = sin_th / r1;
00704        a10 = -sin_th / r2;
00705        a11 = cos_th / r2;
00706        x0 = a00 * curx + a01 * cury;
00707        y0 = a10 * curx + a11 * cury;
00708        if(!relative)
00709               x1 = a00 * x + a01 * y;
00710        else
00711               x1 = a00 * (curx + x) + a01 * (cury + y);
00712        if(!relative)
00713               y1 = a10 * x + a11 * y;
00714        else
00715               y1 = a10 * (curx + x) + a11 * (cury + y);
00716        /* (x0, y0) is current point in transformed coordinate space.
00717               (x1, y1) is new point in transformed coordinate space.
00718               
00719               The arc fits a unit-radius circle in this space.
00720            */
00721        d = (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0);
00722        sfactor_sq = 1.0 / d - 0.25;
00723        if(sfactor_sq < 0)
00724               sfactor_sq = 0;
00725        sfactor = sqrt(sfactor_sq);
00726        if(sweepFlag == largeArcFlag)
00727               sfactor = -sfactor;
00728        xc = 0.5 * (x0 + x1) - sfactor * (y1 - y0);
00729        yc = 0.5 * (y0 + y1) + sfactor * (x1 - x0);
00730        
00731        /* (xc, yc) is center of the circle. */
00732        th0 = atan2(y0 - yc, x0 - xc);
00733        th1 = atan2(y1 - yc, x1 - xc);
00734        th_arc = th1 - th0;
00735        if(th_arc < 0 && sweepFlag)
00736               th_arc += 2 * M_PI;
00737        else if(th_arc > 0 && !sweepFlag)
00738               th_arc -= 2 * M_PI;
00739        n_segs = static_cast<int>(ceil(fabs(th_arc / (M_PI * 0.5 + 0.001))));
00740        for(i = 0; i < n_segs; i++)
00741        {
00742        {
00743               double sin_th, cos_th;
00744               double a00, a01, a10, a11;
00745               double x1, y1, x2, y2, x3, y3;
00746               double t;
00747               double th_half;
00748               double _th0 = th0 + i * th_arc / n_segs;
00749               double _th1 = th0 + (i + 1) * th_arc / n_segs;
00750               sin_th = sin(angle * (M_PI / 180.0));
00751               cos_th = cos(angle * (M_PI / 180.0));
00752               /* inverse transform compared with rsvg_path_arc */
00753               a00 = cos_th * r1;
00754               a01 = -sin_th * r2;
00755               a10 = sin_th * r1;
00756               a11 = cos_th * r2;
00757               th_half = 0.5 * (_th1 - _th0);
00758               t = (8.0 / 3.0) * sin(th_half * 0.5) * sin(th_half * 0.5) / sin(th_half);
00759               x1 = xc + cos(_th0) - t * sin(_th0);
00760               y1 = yc + sin(_th0) + t * cos(_th0);
00761               x3 = xc + cos(_th1);
00762               y3 = yc + sin(_th1);
00763               x2 = x3 + t * sin(_th1);
00764               y2 = y3 - t * cos(_th1);
00765               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 );
00766        }
00767        }
00768        if(!relative)
00769               curx = x;
00770        else
00771               curx += x;
00772        if(!relative)
00773               cury = y;
00774        else
00775               cury += y;
00776 }
00777 
00778 
00779 static const char * getCoord( const char *ptr, double &number )
00780 {
00781        int integer, exponent;
00782        double decimal, frac;
00783        int sign, expsign;
00784        
00785        exponent = 0;
00786        integer = 0;
00787        frac = 1.0;
00788        decimal = 0;
00789        sign = 1;
00790        expsign = 1;
00791        
00792        // read the sign
00793        if(*ptr == '+')
00794               ptr++;
00795        else if(*ptr == '-')
00796        {
00797               ptr++;
00798               sign = -1;
00799        }
00800        
00801        // read the integer part
00802        while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9')
00803               integer = (integer * 10) + *(ptr++) - '0';
00804        if(*ptr == '.') // read the decimals
00805        {
00806               ptr++;
00807               while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9')
00808                      decimal += (*(ptr++) - '0') * (frac *= 0.1);
00809        }
00810        
00811        if(*ptr == 'e' || *ptr == 'E') // read the exponent part
00812        {
00813               ptr++;
00814               
00815               // read the sign of the exponent
00816               if(*ptr == '+')
00817                      ptr++;
00818               else if(*ptr == '-')
00819               {
00820                      ptr++;
00821                      expsign = -1;
00822               }
00823               
00824               exponent = 0;
00825               while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9')
00826               {
00827                      exponent *= 10;
00828                      exponent += *ptr - '0';
00829                      ptr++;
00830               }
00831        }
00832        number = integer + decimal;
00833        number *= sign * pow( static_cast<double>(10), static_cast<double>( expsign * exponent ) );
00834        // skip the following space
00835        if(*ptr == ' ')
00836               ptr++;
00837        
00838        return ptr;
00839 }
00840 
00841 
00842 bool FPointArray::parseSVG(const QString& svgPath)
00843 {
00844        QString d = svgPath;
00845        d = d.replace( QRegExp( "," ), " ");
00846        bool ret = false;
00847        if( !d.isEmpty() )
00848        {
00849               d = d.simplifyWhiteSpace();
00850               const char *ptr = d.latin1();
00851               const char *end = d.latin1() + d.length() + 1;
00852               double contrlx, contrly, curx, cury, subpathx, subpathy, tox, toy, x1, y1, x2, y2, xc, yc;
00853               double px1, py1, px2, py2, px3, py3;
00854               bool relative;
00855               svgInit();
00856               char command = *(ptr++), lastCommand = ' ';
00857               subpathx = subpathy = curx = cury = contrlx = contrly = 0.0;
00858               while( ptr < end )
00859               {
00860                      if( *ptr == ' ' )
00861                             ptr++;
00862                      relative = false;
00863                      switch( command )
00864                      {
00865                      case 'm':
00866                             relative = true;
00867                      case 'M':
00868                             {
00869                                    ptr = getCoord( ptr, tox );
00870                                    ptr = getCoord( ptr, toy );
00871                                    svgState->WasM = true;
00872                                    subpathx = curx = relative ? curx + tox : tox;
00873                                    subpathy = cury = relative ? cury + toy : toy;
00874                                    svgMoveTo(curx, cury );
00875                                    break;
00876                             }
00877                      case 'l':
00878                             relative = true;
00879                      case 'L':
00880                             {
00881                                    ptr = getCoord( ptr, tox );
00882                                    ptr = getCoord( ptr, toy );
00883                                    curx = relative ? curx + tox : tox;
00884                                    cury = relative ? cury + toy : toy;
00885                                    svgLineTo( curx, cury );
00886                                    break;
00887                             }
00888                      case 'h':
00889                             {
00890                                    ptr = getCoord( ptr, tox );
00891                                    curx = curx + tox;
00892                                    svgLineTo( curx, cury );
00893                                    break;
00894                             }
00895                      case 'H':
00896                             {
00897                                    ptr = getCoord( ptr, tox );
00898                                    curx = tox;
00899                                    svgLineTo( curx, cury );
00900                                    break;
00901                             }
00902                      case 'v':
00903                             {
00904                                    ptr = getCoord( ptr, toy );
00905                                    cury = cury + toy;
00906                                    svgLineTo( curx, cury );
00907                                    break;
00908                             }
00909                      case 'V':
00910                             {
00911                                    ptr = getCoord( ptr, toy );
00912                                    cury = toy;
00913                                    svgLineTo(  curx, cury );
00914                                    break;
00915                             }
00916                      case 'z':
00917                      case 'Z':
00918                             {
00919                                    curx = subpathx;
00920                                    cury = subpathy;
00921                                    svgClosePath();
00922                                    break;
00923                             }
00924                      case 'c':
00925                             relative = true;
00926                      case 'C':
00927                             {
00928                                    ptr = getCoord( ptr, x1 );
00929                                    ptr = getCoord( ptr, y1 );
00930                                    ptr = getCoord( ptr, x2 );
00931                                    ptr = getCoord( ptr, y2 );
00932                                    ptr = getCoord( ptr, tox );
00933                                    ptr = getCoord( ptr, toy );
00934                                    px1 = relative ? curx + x1 : x1;
00935                                    py1 = relative ? cury + y1 : y1;
00936                                    px2 = relative ? curx + x2 : x2;
00937                                    py2 = relative ? cury + y2 : y2;
00938                                    px3 = relative ? curx + tox : tox;
00939                                    py3 = relative ? cury + toy : toy;
00940                                    svgCurveToCubic( px1, py1, px2, py2, px3, py3 );
00941                                    contrlx = relative ? curx + x2 : x2;
00942                                    contrly = relative ? cury + y2 : y2;
00943                                    curx = relative ? curx + tox : tox;
00944                                    cury = relative ? cury + toy : toy;
00945                                    break;
00946                             }
00947                      case 's':
00948                             relative = true;
00949                      case 'S':
00950                             {
00951                                    ptr = getCoord( ptr, x2 );
00952                                    ptr = getCoord( ptr, y2 );
00953                                    ptr = getCoord( ptr, tox );
00954                                    ptr = getCoord( ptr, toy );
00955                                    px1 = 2 * curx - contrlx;
00956                                    py1 = 2 * cury - contrly;
00957                                    px2 = relative ? curx + x2 : x2;
00958                                    py2 = relative ? cury + y2 : y2;
00959                                    px3 = relative ? curx + tox : tox;
00960                                    py3 = relative ? cury + toy : toy;
00961                                    svgCurveToCubic( px1, py1, px2, py2, px3, py3 );
00962                                    contrlx = relative ? curx + x2 : x2;
00963                                    contrly = relative ? cury + y2 : y2;
00964                                    curx = relative ? curx + tox : tox;
00965                                    cury = relative ? cury + toy : toy;
00966                                    break;
00967                             }
00968                      case 'q':
00969                             relative = true;
00970                      case 'Q':
00971                             {
00972                                    ptr = getCoord( ptr, x1 );
00973                                    ptr = getCoord( ptr, y1 );
00974                                    ptr = getCoord( ptr, tox );
00975                                    ptr = getCoord( ptr, toy );
00976                                    px1 = relative ? (curx + 2 * (x1 + curx)) * (1.0 / 3.0) : (curx + 2 * x1) * (1.0 / 3.0);
00977                                    py1 = relative ? (cury + 2 * (y1 + cury)) * (1.0 / 3.0) : (cury + 2 * y1) * (1.0 / 3.0);
00978                                    px2 = relative ? ((curx + tox) + 2 * (x1 + curx)) * (1.0 / 3.0) : (tox + 2 * x1) * (1.0 / 3.0);
00979                                    py2 = relative ? ((cury + toy) + 2 * (y1 + cury)) * (1.0 / 3.0) : (toy + 2 * y1) * (1.0 / 3.0);
00980                                    px3 = relative ? curx + tox : tox;
00981                                    py3 = relative ? cury + toy : toy;
00982                                    svgCurveToCubic( px1, py1, px2, py2, px3, py3 );
00983                                    contrlx = relative ? curx + x1 : (tox + 2 * x1) * (1.0 / 3.0);
00984                                    contrly = relative ? cury + y1 : (toy + 2 * y1) * (1.0 / 3.0);
00985                                    curx = relative ? curx + tox : tox;
00986                                    cury = relative ? cury + toy : toy;
00987                                    break;
00988                             }
00989                      case 't':
00990                             relative = true;
00991                      case 'T':
00992                             {
00993                                    ptr = getCoord(ptr, tox);
00994                                    ptr = getCoord(ptr, toy);
00995                                    xc = 2 * curx - contrlx;
00996                                    yc = 2 * cury - contrly;
00997                                    px1 = relative ? (curx + 2 * xc) * (1.0 / 3.0) : (curx + 2 * xc) * (1.0 / 3.0);
00998                                    py1 = relative ? (cury + 2 * yc) * (1.0 / 3.0) : (cury + 2 * yc) * (1.0 / 3.0);
00999                                    px2 = relative ? ((curx + tox) + 2 * xc) * (1.0 / 3.0) : (tox + 2 * xc) * (1.0 / 3.0);
01000                                    py2 = relative ? ((cury + toy) + 2 * yc) * (1.0 / 3.0) : (toy + 2 * yc) * (1.0 / 3.0);
01001                                    px3 = relative ? curx + tox : tox;
01002                                    py3 = relative ? cury + toy : toy;
01003                                    svgCurveToCubic( px1, py1, px2, py2, px3, py3 );
01004                                    contrlx = xc;
01005                                    contrly = yc;
01006                                    curx = relative ? curx + tox : tox;
01007                                    cury = relative ? cury + toy : toy;
01008                                    break;
01009                             }
01010                      case 'a':
01011                             relative = true;
01012                      case 'A':
01013                             {
01014                                    bool largeArc, sweep;
01015                                    double angle, rx, ry;
01016                                    ptr = getCoord( ptr, rx );
01017                                    ptr = getCoord( ptr, ry );
01018                                    ptr = getCoord( ptr, angle );
01019                                    ptr = getCoord( ptr, tox );
01020                                    largeArc = tox == 1;
01021                                    ptr = getCoord( ptr, tox );
01022                                    sweep = tox == 1;
01023                                    ptr = getCoord( ptr, tox );
01024                                    ptr = getCoord( ptr, toy );
01025                                    calculateArc( relative, curx, cury, angle, tox, toy, rx, ry, largeArc, sweep );
01026                             }
01027                      }
01028                      lastCommand = command;
01029                      if(*ptr == '+' || *ptr == '-' || (*ptr >= '0' && *ptr <= '9'))
01030                      {
01031                             // there are still coords in this command
01032                             if(command == 'M')
01033                                    command = 'L';
01034                             else if(command == 'm')
01035                                    command = 'l';
01036                      }
01037                      else
01038                             command = *(ptr++);
01039 
01040                      if( lastCommand != 'C' && lastCommand != 'c' &&
01041                              lastCommand != 'S' && lastCommand != 's' &&
01042                              lastCommand != 'Q' && lastCommand != 'q' &&
01043                              lastCommand != 'T' && lastCommand != 't')
01044                      {
01045                             contrlx = curx;
01046                             contrly = cury;
01047                      }
01048               }
01049               if ((lastCommand != 'z') && (lastCommand != 'Z'))
01050                      ret = true;
01051               if (size() > 2)
01052               {
01053                      if ((point(0).x() == point(size()-2).x()) && (point(0).y() == point(size()-2).y()))
01054                             ret = false;
01055               }
01056        }
01057        return ret;
01058 
01059 }
01060