00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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
00061
00062
00063
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 );
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 {
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
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
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
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 );
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 {
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
00403 FPoint d;
00404 if( tn || n )
00405 pointDerivativesAt( seg, t, p, &d, 0L );
00406 else
00407 pointDerivativesAt( seg, t, p, 0L, 0L );
00408
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
00415 if( tn )
00416 *tn = d;
00417
00418 if( n )
00419 {
00420
00421
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
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
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
00449 if( j == 1 )
00450 {
00451 if( d2 )
00452 *d2 = 6 * ( q[ 2 ] - 2 * q[ 1 ] + q[ 0 ] );
00453 }
00454
00455 else if( j == 2 )
00456 {
00457 if( d1 )
00458 *d1 = 3 * ( q[ 1 ] - q[ 0 ] );
00459 }
00460 }
00461
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
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
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
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
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
00803
00804
00805
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
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
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
00879 if(*ptr == '+')
00880 ptr++;
00881 else if(*ptr == '-')
00882 {
00883 ptr++;
00884 sign = -1;
00885 }
00886
00887
00888 while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9')
00889 integer = (integer * 10) + *(ptr++) - '0';
00890 if(*ptr == '.')
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')
00898 {
00899 ptr++;
00900
00901
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
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
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