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