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