lib Library API Documentation

svgpathparser.cc

00001 /* This file is part of the KDE project 00002 Copyright (C) 2002, The Karbon Developers 00003 00004 This library is free software; you can redistribute it and/or 00005 modify it under the terms of the GNU Library General Public 00006 License as published by the Free Software Foundation; either 00007 version 2 of the License, or (at your option) any later version. 00008 00009 This library is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 Library General Public License for more details. 00013 00014 You should have received a copy of the GNU Library General Public License 00015 along with this library; see the file COPYING.LIB. If not, write to 00016 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00017 Boston, MA 02111-1307, USA. 00018 */ 00019 00020 #include "svgpathparser.h" 00021 #include <qstring.h> 00022 #include <math.h> 00023 00024 // parses the coord into number and forwards to the next token 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 // read the sign 00040 if(*ptr == '+') 00041 ptr++; 00042 else if(*ptr == '-') 00043 { 00044 ptr++; 00045 sign = -1; 00046 } 00047 00048 // read the integer part 00049 while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9') 00050 integer = (integer * 10) + *(ptr++) - '0'; 00051 if(*ptr == '.') // read the decimals 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') // read the exponent part 00059 { 00060 ptr++; 00061 00062 // read the sign of the exponent 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 // skip the following space 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 //std::cout << "Command : " << command << std::endl; 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 // reset curx, cury for next path 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 // Spec: radii are nonnegative numbers 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 // there are still coords in this command 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 // This works by converting the SVG arc to "simple" beziers. 00386 // For each bezier found a svgToCurve call is done. 00387 // Adapted from Niko's code in kdelibs/kdecore/svgicons. 00388 // Maybe this can serve in some shared lib? (Rob) 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 // Spec : check if radii are large enough 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 /* (x0, y0) is current point in transformed coordinate space. 00450 (x1, y1) is new point in transformed coordinate space. 00451 00452 The arc fits a unit-radius circle in this space. 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 /* (xc, yc) is center of the circle. */ 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 /* inverse transform compared with rsvg_path_arc */ 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
KDE Logo
This file is part of the documentation for lib Library Version 1.3.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Sep 24 18:22:29 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003