00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "svgpathparser.h"
00021 #include <qstring.h>
00022 #include <math.h>
00023
00024
00025 const char *
00026 SVGPathParser::getCoord( const char *ptr, double &number )
00027 {
00028 int integer, exponent;
00029 double decimal, frac;
00030 int sign, expsign;
00031
00032 exponent = 0;
00033 integer = 0;
00034 frac = 1.0;
00035 decimal = 0;
00036 sign = 1;
00037 expsign = 1;
00038
00039
00040 if(*ptr == '+')
00041 ptr++;
00042 else if(*ptr == '-')
00043 {
00044 ptr++;
00045 sign = -1;
00046 }
00047
00048
00049 while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9')
00050 integer = (integer * 10) + *(ptr++) - '0';
00051 if(*ptr == '.')
00052 {
00053 ptr++;
00054 while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9')
00055 decimal += (*(ptr++) - '0') * (frac *= 0.1);
00056 }
00057
00058 if(*ptr == 'e' || *ptr == 'E')
00059 {
00060 ptr++;
00061
00062
00063 if(*ptr == '+')
00064 ptr++;
00065 else if(*ptr == '-')
00066 {
00067 ptr++;
00068 expsign = -1;
00069 }
00070
00071 exponent = 0;
00072 while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9')
00073 {
00074 exponent *= 10;
00075 exponent += *ptr - '0';
00076 ptr++;
00077 }
00078 }
00079 number = integer + decimal;
00080 number *= sign * pow( (double)10, double( expsign * exponent ) );
00081
00082
00083 if(*ptr == ' ')
00084 ptr++;
00085
00086 return ptr;
00087 }
00088
00089 void
00090 SVGPathParser::parseSVG( const QString &s, bool process )
00091 {
00092 if( !s.isEmpty() )
00093 {
00094 QString d = s;
00095 d = d.replace( ',', ' ' );
00096 d = d.simplifyWhiteSpace();
00097
00098 const char *ptr = d.latin1();
00099 const char *end = d.latin1() + d.length() + 1;
00100
00101 double contrlx, contrly, curx, cury, subpathx, subpathy, tox, toy, x1, y1, x2, y2, xc, yc;
00102 double px1, py1, px2, py2, px3, py3;
00103 bool relative;
00104 char command = *(ptr++), lastCommand = ' ';
00105
00106 subpathx = subpathy = curx = cury = contrlx = contrly = 0.0;
00107 while( ptr < end )
00108 {
00109 if( *ptr == ' ' )
00110 ptr++;
00111
00112 relative = false;
00113
00114
00115 switch( command )
00116 {
00117 case 'm':
00118 relative = true;
00119 case 'M':
00120 {
00121 ptr = getCoord( ptr, tox );
00122 ptr = getCoord( ptr, toy );
00123
00124 if( process )
00125 {
00126 subpathx = curx = relative ? curx + tox : tox;
00127 subpathy = cury = relative ? cury + toy : toy;
00128
00129 svgMoveTo( curx, cury );
00130 }
00131 else
00132 svgMoveTo( tox, toy, !relative );
00133 break;
00134 }
00135 case 'l':
00136 relative = true;
00137 case 'L':
00138 {
00139 ptr = getCoord( ptr, tox );
00140 ptr = getCoord( ptr, toy );
00141
00142 if( process )
00143 {
00144 curx = relative ? curx + tox : tox;
00145 cury = relative ? cury + toy : toy;
00146
00147 svgLineTo( curx, cury );
00148 }
00149 else
00150 svgLineTo( tox, toy, !relative );
00151 break;
00152 }
00153 case 'h':
00154 {
00155 ptr = getCoord( ptr, tox );
00156 if( process )
00157 {
00158 curx = curx + tox;
00159 svgLineTo( curx, cury );
00160 }
00161 else
00162 svgLineToHorizontal( tox, false );
00163 break;
00164 }
00165 case 'H':
00166 {
00167 ptr = getCoord( ptr, tox );
00168 if( process )
00169 {
00170 curx = tox;
00171 svgLineTo( curx, cury );
00172 }
00173 else
00174 svgLineToHorizontal( tox );
00175 break;
00176 }
00177 case 'v':
00178 {
00179 ptr = getCoord( ptr, toy );
00180 if( process )
00181 {
00182 cury = cury + toy;
00183 svgLineTo( curx, cury );
00184 }
00185 else
00186 svgLineToVertical( toy, false );
00187 break;
00188 }
00189 case 'V':
00190 {
00191 ptr = getCoord( ptr, toy );
00192 if( process )
00193 {
00194 cury = toy;
00195 svgLineTo( curx, cury );
00196 }
00197 else
00198 svgLineToVertical( toy );
00199 break;
00200 }
00201 case 'z':
00202 case 'Z':
00203 {
00204
00205 if( process )
00206 {
00207 curx = subpathx;
00208 cury = subpathy;
00209 }
00210 svgClosePath();
00211 break;
00212 }
00213 case 'c':
00214 relative = true;
00215 case 'C':
00216 {
00217 ptr = getCoord( ptr, x1 );
00218 ptr = getCoord( ptr, y1 );
00219 ptr = getCoord( ptr, x2 );
00220 ptr = getCoord( ptr, y2 );
00221 ptr = getCoord( ptr, tox );
00222 ptr = getCoord( ptr, toy );
00223
00224 if( process )
00225 {
00226 px1 = relative ? curx + x1 : x1;
00227 py1 = relative ? cury + y1 : y1;
00228 px2 = relative ? curx + x2 : x2;
00229 py2 = relative ? cury + y2 : y2;
00230 px3 = relative ? curx + tox : tox;
00231 py3 = relative ? cury + toy : toy;
00232
00233 svgCurveToCubic( px1, py1, px2, py2, px3, py3 );
00234
00235 contrlx = relative ? curx + x2 : x2;
00236 contrly = relative ? cury + y2 : y2;
00237 curx = relative ? curx + tox : tox;
00238 cury = relative ? cury + toy : toy;
00239 }
00240 else
00241 svgCurveToCubic( x1, y1, x2, y2, tox, toy, !relative );
00242
00243 break;
00244 }
00245 case 's':
00246 relative = true;
00247 case 'S':
00248 {
00249 ptr = getCoord( ptr, x2 );
00250 ptr = getCoord( ptr, y2 );
00251 ptr = getCoord( ptr, tox );
00252 ptr = getCoord( ptr, toy );
00253
00254 if( process )
00255 {
00256 px1 = 2 * curx - contrlx;
00257 py1 = 2 * cury - contrly;
00258 px2 = relative ? curx + x2 : x2;
00259 py2 = relative ? cury + y2 : y2;
00260 px3 = relative ? curx + tox : tox;
00261 py3 = relative ? cury + toy : toy;
00262
00263 svgCurveToCubic( px1, py1, px2, py2, px3, py3 );
00264
00265 contrlx = relative ? curx + x2 : x2;
00266 contrly = relative ? cury + y2 : y2;
00267 curx = relative ? curx + tox : tox;
00268 cury = relative ? cury + toy : toy;
00269 }
00270 else
00271 svgCurveToCubicSmooth( x2, y2, tox, toy, !relative );
00272 break;
00273 }
00274 case 'q':
00275 relative = true;
00276 case 'Q':
00277 {
00278 ptr = getCoord( ptr, x1 );
00279 ptr = getCoord( ptr, y1 );
00280 ptr = getCoord( ptr, tox );
00281 ptr = getCoord( ptr, toy );
00282
00283 if( process )
00284 {
00285 px1 = relative ? (curx + 2 * (x1 + curx)) * (1.0 / 3.0) : (curx + 2 * x1) * (1.0 / 3.0);
00286 py1 = relative ? (cury + 2 * (y1 + cury)) * (1.0 / 3.0) : (cury + 2 * y1) * (1.0 / 3.0);
00287 px2 = relative ? ((curx + tox) + 2 * (x1 + curx)) * (1.0 / 3.0) : (tox + 2 * x1) * (1.0 / 3.0);
00288 py2 = relative ? ((cury + toy) + 2 * (y1 + cury)) * (1.0 / 3.0) : (toy + 2 * y1) * (1.0 / 3.0);
00289 px3 = relative ? curx + tox : tox;
00290 py3 = relative ? cury + toy : toy;
00291
00292 svgCurveToCubic( px1, py1, px2, py2, px3, py3 );
00293
00294 contrlx = relative ? curx + x1 : (tox + 2 * x1) * (1.0 / 3.0);
00295 contrly = relative ? cury + y1 : (toy + 2 * y1) * (1.0 / 3.0);
00296 curx = relative ? curx + tox : tox;
00297 cury = relative ? cury + toy : toy;
00298 }
00299 else
00300 svgCurveToQuadratic( x1, y1, tox, toy, !relative );
00301 break;
00302 }
00303 case 't':
00304 relative = true;
00305 case 'T':
00306 {
00307 ptr = getCoord(ptr, tox);
00308 ptr = getCoord(ptr, toy);
00309
00310 if( process )
00311 {
00312 xc = 2 * curx - contrlx;
00313 yc = 2 * cury - contrly;
00314
00315 px1 = relative ? (curx + 2 * xc) * (1.0 / 3.0) : (curx + 2 * xc) * (1.0 / 3.0);
00316 py1 = relative ? (cury + 2 * yc) * (1.0 / 3.0) : (cury + 2 * yc) * (1.0 / 3.0);
00317 px2 = relative ? ((curx + tox) + 2 * xc) * (1.0 / 3.0) : (tox + 2 * xc) * (1.0 / 3.0);
00318 py2 = relative ? ((cury + toy) + 2 * yc) * (1.0 / 3.0) : (toy + 2 * yc) * (1.0 / 3.0);
00319 px3 = relative ? curx + tox : tox;
00320 py3 = relative ? cury + toy : toy;
00321
00322 svgCurveToCubic( px1, py1, px2, py2, px3, py3 );
00323
00324 contrlx = xc;
00325 contrly = yc;
00326 curx = relative ? curx + tox : tox;
00327 cury = relative ? cury + toy : toy;
00328 }
00329 else
00330 svgCurveToQuadraticSmooth( tox, toy, !relative );
00331 break;
00332 }
00333 case 'a':
00334 relative = true;
00335 case 'A':
00336 {
00337 bool largeArc, sweep;
00338 double angle, rx, ry;
00339 ptr = getCoord( ptr, rx );
00340 ptr = getCoord( ptr, ry );
00341 ptr = getCoord( ptr, angle );
00342 ptr = getCoord( ptr, tox );
00343 largeArc = tox == 1;
00344 ptr = getCoord( ptr, tox );
00345 sweep = tox == 1;
00346 ptr = getCoord( ptr, tox );
00347 ptr = getCoord( ptr, toy );
00348
00349
00350 rx = fabs(rx);
00351 ry = fabs(ry);
00352
00353 if( process )
00354 calculateArc( relative, curx, cury, angle, tox, toy, rx, ry, largeArc, sweep );
00355 else
00356 svgArcTo( tox, toy, rx, ry, angle, largeArc, sweep, !relative );
00357 }
00358 }
00359
00360 lastCommand = command;
00361
00362 if(*ptr == '+' || *ptr == '-' || (*ptr >= '0' && *ptr <= '9'))
00363 {
00364
00365 if(command == 'M')
00366 command = 'L';
00367 else if(command == 'm')
00368 command = 'l';
00369 }
00370 else
00371 command = *(ptr++);
00372
00373 if( lastCommand != 'C' && lastCommand != 'c' &&
00374 lastCommand != 'S' && lastCommand != 's' &&
00375 lastCommand != 'Q' && lastCommand != 'q' &&
00376 lastCommand != 'T' && lastCommand != 't')
00377 {
00378 contrlx = curx;
00379 contrly = cury;
00380 }
00381 }
00382 }
00383 }
00384
00385
00386
00387
00388
00389 void
00390 SVGPathParser::calculateArc(bool relative, double &curx, double &cury, double angle, double x, double y, double r1, double r2, bool largeArcFlag, bool sweepFlag)
00391 {
00392 double sin_th, cos_th;
00393 double a00, a01, a10, a11;
00394 double x0, y0, x1, y1, xc, yc;
00395 double d, sfactor, sfactor_sq;
00396 double th0, th1, th_arc;
00397 int i, n_segs;
00398
00399 sin_th = sin(angle * (M_PI / 180.0));
00400 cos_th = cos(angle * (M_PI / 180.0));
00401
00402 double dx;
00403
00404 if(!relative)
00405 dx = (curx - x) / 2.0;
00406 else
00407 dx = -x / 2.0;
00408
00409 double dy;
00410
00411 if(!relative)
00412 dy = (cury - y) / 2.0;
00413 else
00414 dy = -y / 2.0;
00415
00416 double _x1 = cos_th * dx + sin_th * dy;
00417 double _y1 = -sin_th * dx + cos_th * dy;
00418 double Pr1 = r1 * r1;
00419 double Pr2 = r2 * r2;
00420 double Px = _x1 * _x1;
00421 double Py = _y1 * _y1;
00422
00423
00424 double check = Px / Pr1 + Py / Pr2;
00425 if(check > 1)
00426 {
00427 r1 = r1 * sqrt(check);
00428 r2 = r2 * sqrt(check);
00429 }
00430
00431 a00 = cos_th / r1;
00432 a01 = sin_th / r1;
00433 a10 = -sin_th / r2;
00434 a11 = cos_th / r2;
00435
00436 x0 = a00 * curx + a01 * cury;
00437 y0 = a10 * curx + a11 * cury;
00438
00439 if(!relative)
00440 x1 = a00 * x + a01 * y;
00441 else
00442 x1 = a00 * (curx + x) + a01 * (cury + y);
00443
00444 if(!relative)
00445 y1 = a10 * x + a11 * y;
00446 else
00447 y1 = a10 * (curx + x) + a11 * (cury + y);
00448
00449
00450
00451
00452
00453
00454
00455 d = (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0);
00456
00457 sfactor_sq = 1.0 / d - 0.25;
00458
00459 if(sfactor_sq < 0)
00460 sfactor_sq = 0;
00461
00462 sfactor = sqrt(sfactor_sq);
00463
00464 if(sweepFlag == largeArcFlag)
00465 sfactor = -sfactor;
00466
00467 xc = 0.5 * (x0 + x1) - sfactor * (y1 - y0);
00468 yc = 0.5 * (y0 + y1) + sfactor * (x1 - x0);
00469
00470
00471 th0 = atan2(y0 - yc, x0 - xc);
00472 th1 = atan2(y1 - yc, x1 - xc);
00473
00474 th_arc = th1 - th0;
00475 if(th_arc < 0 && sweepFlag)
00476 th_arc += 2 * M_PI;
00477 else if(th_arc > 0 && !sweepFlag)
00478 th_arc -= 2 * M_PI;
00479
00480 n_segs = (int) (int) ceil(fabs(th_arc / (M_PI * 0.5 + 0.001)));
00481
00482 for(i = 0; i < n_segs; i++)
00483 {
00484 {
00485 double sin_th, cos_th;
00486 double a00, a01, a10, a11;
00487 double x1, y1, x2, y2, x3, y3;
00488 double t;
00489 double th_half;
00490
00491 double _th0 = th0 + i * th_arc / n_segs;
00492 double _th1 = th0 + (i + 1) * th_arc / n_segs;
00493
00494 sin_th = sin(angle * (M_PI / 180.0));
00495 cos_th = cos(angle * (M_PI / 180.0));
00496
00497
00498 a00 = cos_th * r1;
00499 a01 = -sin_th * r2;
00500 a10 = sin_th * r1;
00501 a11 = cos_th * r2;
00502
00503 th_half = 0.5 * (_th1 - _th0);
00504 t = (8.0 / 3.0) * sin(th_half * 0.5) * sin(th_half * 0.5) / sin(th_half);
00505 x1 = xc + cos(_th0) - t * sin(_th0);
00506 y1 = yc + sin(_th0) + t * cos(_th0);
00507 x3 = xc + cos(_th1);
00508 y3 = yc + sin(_th1);
00509 x2 = x3 + t * sin(_th1);
00510 y2 = y3 - t * cos(_th1);
00511
00512 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 );
00513 }
00514 }
00515
00516 if(!relative)
00517 curx = x;
00518 else
00519 curx += x;
00520
00521 if(!relative)
00522 cury = y;
00523 else
00524 cury += y;
00525 }
00526
00527 void
00528 SVGPathParser::svgLineToHorizontal( double, bool )
00529 {
00530 }
00531
00532 void
00533 SVGPathParser::svgLineToVertical( double, bool )
00534 {
00535 }
00536
00537 void
00538 SVGPathParser::svgCurveToCubicSmooth( double, double, double, double, bool )
00539 {
00540 }
00541
00542 void
00543 SVGPathParser::svgCurveToQuadratic( double, double, double, double, bool )
00544 {
00545 }
00546
00547 void
00548 SVGPathParser::svgCurveToQuadraticSmooth( double, double, bool )
00549 {
00550 }
00551
00552 void
00553 SVGPathParser::svgArcTo( double, double, double, double, double, bool, bool, bool )
00554 {
00555 }
00556