Scribus Developer Documentation - API
logo-pen

Scribus Developer Documentation - API

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