void SVGPathParser::parseSVG( const DeprecatedString &s, bool process ) { if(!s.isEmpty()) { DeprecatedString d = s; d = d.replace(',', ' '); d = d.simplifyWhiteSpace(); const char *ptr = d.latin1(); const char *end = d.latin1() + d.length() + 1; double contrlx, contrly, curx, cury, subpathx, subpathy, tox, toy, x1, y1, x2, y2, xc, yc; double px1, py1, px2, py2, px3, py3; bool relative, closed = true; char command = *(ptr++), lastCommand = ' '; subpathx = subpathy = curx = cury = contrlx = contrly = 0.0; while( ptr < end ) { if( *ptr == ' ' ) ptr++; relative = false; //std::cout << "Command : " << command << std::endl; switch( command ) { case 'm': relative = true; case 'M': { ptr = parseCoord( ptr, tox ); ptr = parseCoord( ptr, toy ); if( process ) { subpathx = curx = relative ? curx + tox : tox; subpathy = cury = relative ? cury + toy : toy; svgMoveTo( curx, cury, closed ); } else svgMoveTo( tox, toy, closed, !relative ); closed = false; break; } case 'l': relative = true; case 'L': { ptr = parseCoord( ptr, tox ); ptr = parseCoord( ptr, toy ); if( process ) { curx = relative ? curx + tox : tox; cury = relative ? cury + toy : toy; svgLineTo( curx, cury ); } else svgLineTo( tox, toy, !relative ); break; } case 'h': { ptr = parseCoord( ptr, tox ); if( process ) { curx = curx + tox; svgLineTo( curx, cury ); } else svgLineToHorizontal( tox, false ); break; } case 'H': { ptr = parseCoord( ptr, tox ); if( process ) { curx = tox; svgLineTo( curx, cury ); } else svgLineToHorizontal( tox ); break; } case 'v': { ptr = parseCoord( ptr, toy ); if( process ) { cury = cury + toy; svgLineTo( curx, cury ); } else svgLineToVertical( toy, false ); break; } case 'V': { ptr = parseCoord( ptr, toy ); if( process ) { cury = toy; svgLineTo( curx, cury ); } else svgLineToVertical( toy ); break; } case 'z': case 'Z': { // reset curx, cury for next path if( process ) { curx = subpathx; cury = subpathy; } closed = true; svgClosePath(); break; } case 'c': relative = true; case 'C': { ptr = parseCoord( ptr, x1 ); ptr = parseCoord( ptr, y1 ); ptr = parseCoord( ptr, x2 ); ptr = parseCoord( ptr, y2 ); ptr = parseCoord( ptr, tox ); ptr = parseCoord( ptr, toy ); if( process ) { px1 = relative ? curx + x1 : x1; py1 = relative ? cury + y1 : y1; px2 = relative ? curx + x2 : x2; py2 = relative ? cury + y2 : y2; px3 = relative ? curx + tox : tox; py3 = relative ? cury + toy : toy; svgCurveToCubic( px1, py1, px2, py2, px3, py3 ); contrlx = relative ? curx + x2 : x2; contrly = relative ? cury + y2 : y2; curx = relative ? curx + tox : tox; cury = relative ? cury + toy : toy; } else svgCurveToCubic( x1, y1, x2, y2, tox, toy, !relative ); break; } case 's': relative = true; case 'S': { ptr = parseCoord( ptr, x2 ); ptr = parseCoord( ptr, y2 ); ptr = parseCoord( ptr, tox ); ptr = parseCoord( ptr, toy ); if(!(lastCommand == 'c' || lastCommand == 'C' || lastCommand == 's' || lastCommand == 'S')) { contrlx = curx; contrly = cury; } if( process ) { px1 = 2 * curx - contrlx; py1 = 2 * cury - contrly; px2 = relative ? curx + x2 : x2; py2 = relative ? cury + y2 : y2; px3 = relative ? curx + tox : tox; py3 = relative ? cury + toy : toy; svgCurveToCubic( px1, py1, px2, py2, px3, py3 ); contrlx = relative ? curx + x2 : x2; contrly = relative ? cury + y2 : y2; curx = relative ? curx + tox : tox; cury = relative ? cury + toy : toy; } else svgCurveToCubicSmooth( x2, y2, tox, toy, !relative ); break; } case 'q': relative = true; case 'Q': { ptr = parseCoord( ptr, x1 ); ptr = parseCoord( ptr, y1 ); ptr = parseCoord( ptr, tox ); ptr = parseCoord( ptr, toy ); if( process ) { px1 = relative ? (curx + 2 * (x1 + curx)) * (1.0 / 3.0) : (curx + 2 * x1) * (1.0 / 3.0); py1 = relative ? (cury + 2 * (y1 + cury)) * (1.0 / 3.0) : (cury + 2 * y1) * (1.0 / 3.0); px2 = relative ? ((curx + tox) + 2 * (x1 + curx)) * (1.0 / 3.0) : (tox + 2 * x1) * (1.0 / 3.0); py2 = relative ? ((cury + toy) + 2 * (y1 + cury)) * (1.0 / 3.0) : (toy + 2 * y1) * (1.0 / 3.0); px3 = relative ? curx + tox : tox; py3 = relative ? cury + toy : toy; svgCurveToCubic( px1, py1, px2, py2, px3, py3 ); contrlx = relative ? curx + x1 : x1; contrly = relative ? cury + y1 : y1; curx = relative ? curx + tox : tox; cury = relative ? cury + toy : toy; } else svgCurveToQuadratic( x1, y1, tox, toy, !relative ); break; } case 't': relative = true; case 'T': { ptr = parseCoord(ptr, tox); ptr = parseCoord(ptr, toy); if(!(lastCommand == 'q' || lastCommand == 'Q' || lastCommand == 't' || lastCommand == 'T')) { contrlx = curx; contrly = cury; } if( process ) { xc = 2 * curx - contrlx; yc = 2 * cury - contrly; px1 = relative ? (curx + 2 * xc) * (1.0 / 3.0) : (curx + 2 * xc) * (1.0 / 3.0); py1 = relative ? (cury + 2 * yc) * (1.0 / 3.0) : (cury + 2 * yc) * (1.0 / 3.0); px2 = relative ? ((curx + tox) + 2 * xc) * (1.0 / 3.0) : (tox + 2 * xc) * (1.0 / 3.0); py2 = relative ? ((cury + toy) + 2 * yc) * (1.0 / 3.0) : (toy + 2 * yc) * (1.0 / 3.0); px3 = relative ? curx + tox : tox; py3 = relative ? cury + toy : toy; svgCurveToCubic( px1, py1, px2, py2, px3, py3 ); contrlx = xc; contrly = yc; curx = relative ? curx + tox : tox; cury = relative ? cury + toy : toy; } else svgCurveToQuadraticSmooth( tox, toy, !relative ); break; } case 'a': relative = true; case 'A': { bool largeArc, sweep; double angle, rx, ry; ptr = parseCoord( ptr, rx ); ptr = parseCoord( ptr, ry ); ptr = parseCoord( ptr, angle ); ptr = parseCoord( ptr, tox ); largeArc = tox == 1; ptr = parseCoord( ptr, tox ); sweep = tox == 1; ptr = parseCoord( ptr, tox ); ptr = parseCoord( ptr, toy ); // Spec: radii are nonnegative numbers rx = fabs(rx); ry = fabs(ry); if( process ) calculateArc( relative, curx, cury, angle, tox, toy, rx, ry, largeArc, sweep ); else svgArcTo( tox, toy, rx, ry, angle, largeArc, sweep, !relative ); break; } default: // FIXME: An error should go to the JavaScript console, or the like. return; } lastCommand = command; if(*ptr == '+' || *ptr == '-' || (*ptr >= '0' && *ptr <= '9')) { // there are still coords in this command if(command == 'M') command = 'L'; else if(command == 'm') command = 'l'; } else command = *(ptr++); if( lastCommand != 'C' && lastCommand != 'c' && lastCommand != 'S' && lastCommand != 's' && lastCommand != 'Q' && lastCommand != 'q' && lastCommand != 'T' && lastCommand != 't' ) { contrlx = curx; contrly = cury; } } } }
//********************************************* void CircleToCircle(double Circle1CenterX,double Circle1CenterY,double Circle1StartX,double Circle1StartY, double Circle1EndX,double Circle1EndY,double Circle2CenterX,double Circle2CenterY, double Circle2StartX,double Circle2StartY,double Circle2EndX,double Circle2EndY, int circular1Mode,int circular2Mode,int UpMode) { double R1,R2; double ArcCircle1,ArcCircle2; double ArcCircle1Start,ArcCircle2Start; int Circle1_is_point,Circle2_is_point; int i1,i2,j; int j1,j2; //********************************** R1=sqrt((Circle1StartX-Circle1CenterX)*(Circle1StartX-Circle1CenterX)+(Circle1StartY-Circle1CenterY)*(Circle1StartY-Circle1CenterY)); R2=sqrt((Circle2StartX-Circle2CenterX)*(Circle2StartX-Circle2CenterX)+(Circle2StartY-Circle2CenterY)*(Circle2StartY-Circle2CenterY)); //********************************** //判断圆弧是否为点 if(R1<ZERO)Circle1_is_point=1; else Circle1_is_point=0; if(R2<ZERO)Circle2_is_point=1; else Circle2_is_point=0; //********************************** //如果圆弧为点则对应的ArcCircle、ArcCircleStart直接取0 if(Circle1_is_point) { ArcCircle1=0.0; ArcCircle1Start=0.0; } else { ArcCircle1=calculateArc(Circle1CenterX,Circle1CenterY,Circle1StartX,Circle1StartY,Circle1EndX,Circle1EndY,circular1Mode); ArcCircle1Start=calculateLineArc(Circle1StartX-Circle1CenterX,Circle1StartY-Circle1CenterY); } if(Circle2_is_point) { ArcCircle2=0.0; ArcCircle2Start=0.0; } else { ArcCircle2=calculateArc(Circle2CenterX,Circle2CenterY,Circle2StartX,Circle2StartY,Circle2EndX,Circle2EndY,circular2Mode); ArcCircle2Start=calculateLineArc(Circle2StartX-Circle2CenterX,Circle2StartY-Circle2CenterY); } //********************************** //如果圆弧为点则不进行密化 if(Circle1_is_point)i1=-1; else i1=calculateCircleMode(R1,ArcCircle1); if(Circle2_is_point)i2=-1; else i2=calculateCircleMode(R2,ArcCircle2); //********************************** //存在圆弧为点情况,按点对圆弧进行密化绘图 if(Circle1_is_point||Circle2_is_point) { if(i1==0) { j=calculateNumber; } else if(i1==1) { if(minLength>=2*R1||asin(minLength/(2*R1))>ArcCircle1/2) { j=1; } else { j=asin(minLength/(2*R1))/(ArcCircle1/2); } } else if(i1==2) { j=asin(maxLength/(2*R1))/(ArcCircle1/2); } else if(i2==0) { j=calculateNumber; } else if(i2==1) { if(minLength>=2*R2||asin(minLength/(2*R2))>ArcCircle2/2) { j=1; } else { j=asin(minLength/(2*R2))/(ArcCircle2/2); } } else if(i2==2) { j=asin(maxLength/(2*R2))/(ArcCircle2/2); } if(Circle1_is_point)CirclePoint(ArcCircle2,j,ArcCircle2Start,R2,circular2Mode,UpMode); else if(Circle2_is_point)CirclePoint(ArcCircle1,j,ArcCircle1Start,R1,circular1Mode,UpMode); } else { if(i1==0) { j1=calculateNumber; } else if(i1==1) { if(minLength>=2*R1||asin(minLength/(2*R1))>ArcCircle1/2) { j1=1; } else { j1=asin(minLength/(2*R1))/(ArcCircle1/2); } } else if(i1==2) { j1=asin(maxLength/(2*R1))/(ArcCircle1/2); } if(i2==0) { j2=calculateNumber; } else if(i2==1) { if(minLength>=2*R2||asin(minLength/(2*R2))>ArcCircle2/2) { j2=1; } else { j2=asin(minLength/(2*R2))/(ArcCircle2/2); } } else if(i2==2) { j2=asin(maxLength/(2*R2))/(ArcCircle2/2); } if(j1<j2)j=j2; else j=j1; CircleCircle(ArcCircle1,R1,ArcCircle1Start,circular1Mode,ArcCircle2,ArcCircle2Start,R2,circular2Mode,UpMode,j); } }
void KoPathShapeLoaderPrivate::parseSvg(const QString &s, bool process) { if (!s.isEmpty()) { QString d = s; d = d.replace(',', ' '); d = d.simplified(); const QByteArray buffer = d.toLatin1(); const char *ptr = buffer.constData(); const char *end = buffer.constData() + buffer.length() + 1; qreal curx = 0.0; qreal cury = 0.0; qreal contrlx, contrly, subpathx, subpathy, tox, toy, x1, y1, x2, y2, xc, yc; qreal px1, py1, px2, py2, px3, py3; bool relative; char command = *(ptr++), lastCommand = ' '; subpathx = subpathy = curx = cury = contrlx = contrly = 0.0; while (ptr < end) { if (*ptr == ' ') ++ptr; relative = false; switch (command) { case 'm': relative = true; case 'M': { ptr = getCoord(ptr, tox); ptr = getCoord(ptr, toy); if (process) { subpathx = curx = relative ? curx + tox : tox; subpathy = cury = relative ? cury + toy : toy; svgMoveTo(curx, cury); } else svgMoveTo(tox, toy, !relative); break; } case 'l': relative = true; case 'L': { ptr = getCoord(ptr, tox); ptr = getCoord(ptr, toy); if (process) { curx = relative ? curx + tox : tox; cury = relative ? cury + toy : toy; svgLineTo(curx, cury); } else svgLineTo(tox, toy, !relative); break; } case 'h': { ptr = getCoord(ptr, tox); if (process) { curx = curx + tox; svgLineTo(curx, cury); } else svgLineToHorizontal(tox, false); break; } case 'H': { ptr = getCoord(ptr, tox); if (process) { curx = tox; svgLineTo(curx, cury); } else svgLineToHorizontal(tox); break; } case 'v': { ptr = getCoord(ptr, toy); if (process) { cury = cury + toy; svgLineTo(curx, cury); } else svgLineToVertical(toy, false); break; } case 'V': { ptr = getCoord(ptr, toy); if (process) { cury = toy; svgLineTo(curx, cury); } else svgLineToVertical(toy); break; } case 'z': case 'Z': { // reset curx, cury for next path if (process) { // The "closepath" (Z or z) ends the current subpath and causes an automatic // straight line to be drawn from the current point to the initial point of the // current subpath. If a "closepath" is followed immediately by a "moveto", then // the "moveto" identifies the start point of the next subpath. If a "closepath" // is followed immediately by any other command, then the next subpath starts at // the same initial point as the current subpath. if (*ptr != 'm' && *ptr != 'M') { curx = subpathx; cury = subpathy; } } svgClosePath(); break; } case 'c': relative = true; case 'C': { ptr = getCoord(ptr, x1); ptr = getCoord(ptr, y1); ptr = getCoord(ptr, x2); ptr = getCoord(ptr, y2); ptr = getCoord(ptr, tox); ptr = getCoord(ptr, toy); if (process) { px1 = relative ? curx + x1 : x1; py1 = relative ? cury + y1 : y1; px2 = relative ? curx + x2 : x2; py2 = relative ? cury + y2 : y2; px3 = relative ? curx + tox : tox; py3 = relative ? cury + toy : toy; svgCurveToCubic(px1, py1, px2, py2, px3, py3); contrlx = relative ? curx + x2 : x2; contrly = relative ? cury + y2 : y2; curx = relative ? curx + tox : tox; cury = relative ? cury + toy : toy; } else svgCurveToCubic(x1, y1, x2, y2, tox, toy, !relative); break; } case 's': relative = true; case 'S': { ptr = getCoord(ptr, x2); ptr = getCoord(ptr, y2); ptr = getCoord(ptr, tox); ptr = getCoord(ptr, toy); if (!(lastCommand == 'c' || lastCommand == 'C' || lastCommand == 's' || lastCommand == 'S')) { contrlx = curx; contrly = cury; } if (process) { px1 = 2 * curx - contrlx; py1 = 2 * cury - contrly; px2 = relative ? curx + x2 : x2; py2 = relative ? cury + y2 : y2; px3 = relative ? curx + tox : tox; py3 = relative ? cury + toy : toy; svgCurveToCubic(px1, py1, px2, py2, px3, py3); contrlx = relative ? curx + x2 : x2; contrly = relative ? cury + y2 : y2; curx = relative ? curx + tox : tox; cury = relative ? cury + toy : toy; } else svgCurveToCubicSmooth(x2, y2, tox, toy, !relative); break; } case 'q': relative = true; case 'Q': { ptr = getCoord(ptr, x1); ptr = getCoord(ptr, y1); ptr = getCoord(ptr, tox); ptr = getCoord(ptr, toy); if (process) { px1 = relative ? (curx + 2 * (x1 + curx)) * (1.0 / 3.0) : (curx + 2 * x1) * (1.0 / 3.0); py1 = relative ? (cury + 2 * (y1 + cury)) * (1.0 / 3.0) : (cury + 2 * y1) * (1.0 / 3.0); px2 = relative ? ((curx + tox) + 2 * (x1 + curx)) * (1.0 / 3.0) : (tox + 2 * x1) * (1.0 / 3.0); py2 = relative ? ((cury + toy) + 2 * (y1 + cury)) * (1.0 / 3.0) : (toy + 2 * y1) * (1.0 / 3.0); px3 = relative ? curx + tox : tox; py3 = relative ? cury + toy : toy; svgCurveToCubic(px1, py1, px2, py2, px3, py3); contrlx = relative ? curx + x1 : x1; contrly = relative ? cury + y1 : y1; curx = relative ? curx + tox : tox; cury = relative ? cury + toy : toy; } else svgCurveToQuadratic(x1, y1, tox, toy, !relative); break; } case 't': relative = true; case 'T': { ptr = getCoord(ptr, tox); ptr = getCoord(ptr, toy); if (!(lastCommand == 'q' || lastCommand == 'Q' || lastCommand == 't' || lastCommand == 'T')) { contrlx = curx; contrly = cury; } if (process) { xc = 2 * curx - contrlx; yc = 2 * cury - contrly; px1 = (curx + 2 * xc) * (1.0 / 3.0); py1 = (cury + 2 * yc) * (1.0 / 3.0); px2 = relative ? ((curx + tox) + 2 * xc) * (1.0 / 3.0) : (tox + 2 * xc) * (1.0 / 3.0); py2 = relative ? ((cury + toy) + 2 * yc) * (1.0 / 3.0) : (toy + 2 * yc) * (1.0 / 3.0); px3 = relative ? curx + tox : tox; py3 = relative ? cury + toy : toy; svgCurveToCubic(px1, py1, px2, py2, px3, py3); contrlx = xc; contrly = yc; curx = relative ? curx + tox : tox; cury = relative ? cury + toy : toy; } else svgCurveToQuadraticSmooth(tox, toy, !relative); break; } case 'a': relative = true; case 'A': { bool largeArc, sweep; qreal angle, rx, ry; ptr = getCoord(ptr, rx); ptr = getCoord(ptr, ry); ptr = getCoord(ptr, angle); ptr = getCoord(ptr, tox); largeArc = tox == 1; ptr = getCoord(ptr, tox); sweep = tox == 1; ptr = getCoord(ptr, tox); ptr = getCoord(ptr, toy); // Spec: radii are nonnegative numbers rx = fabs(rx); ry = fabs(ry); if (process) calculateArc(relative, curx, cury, angle, tox, toy, rx, ry, largeArc, sweep); else svgArcTo(tox, toy, rx, ry, angle, largeArc, sweep, !relative); break; } default: { // when svg parser is used for a parsing an odf path an unknown command // can be encountered, so we stop parsing here kDebug(30006) << "KoSvgPathParser::parseSVG(): unknown command \"" << command << "\""; return; } } lastCommand = command; if (*ptr == '+' || *ptr == '-' || (*ptr >= '0' && *ptr <= '9')) { // there are still coords in this command if (command == 'M') command = 'L'; else if (command == 'm') command = 'l'; } else command = *(ptr++); if (lastCommand != 'C' && lastCommand != 'c' && lastCommand != 'S' && lastCommand != 's' && lastCommand != 'Q' && lastCommand != 'q' && lastCommand != 'T' && lastCommand != 't') { contrlx = curx; contrly = cury; } } } }
//********************************************* void CircleToLine(double LineStartX,double LineStartY,double LineEndX,double LineEndY,double CircleCenterX, double CircleCenterY,double CircleStartX,double CircleStartY,double CircleEndX,double CircleEndY, int circularMode,int UpMode) { double R,ArcCircle,LineLength,dArc,ArcCircleStart,ArcLine,dLineLength; double dLineX,dLineY; int i,j; //求得圆半径和直线长 R=sqrt((CircleStartX-CircleCenterX)*(CircleStartX-CircleCenterX)+(CircleStartY-CircleCenterY)*(CircleStartY-CircleCenterY)); LineLength=sqrt((LineEndX-LineStartX)*(LineEndX-LineStartX)+(LineEndY-LineStartY)*(LineEndY-LineStartY)); //圆为点,即为点对直线,直接绘图 if(R<ZERO) { if(UpMode==1) { now_up_X=now_up_X+LineEndX-LineStartX; now_up_Y=now_up_Y+LineEndY-LineStartY; now_down_X=now_down_X; now_down_Y=now_down_Y; } else { now_down_X=now_down_X+LineEndX-LineStartX; now_down_Y=now_down_Y+LineEndY-LineStartY; now_up_X=now_up_X; now_up_Y=now_up_Y; } Draw(); } else { //圆弧中心角 ArcCircle=calculateArc(CircleCenterX,CircleCenterY,CircleStartX,CircleStartY,CircleEndX,CircleEndY,circularMode); //圆弧起始点与圆心连线同X轴夹角 ArcCircleStart=calculateLineArc(CircleStartX-CircleCenterX,CircleStartY-CircleCenterY); //直线与X轴夹角 ArcLine=calculateLineArc(LineEndX-LineStartX,LineEndY-LineStartX); i=calculateCircleMode(R,ArcCircle); if(i==0) { j=calculateNumber; dArc=ArcCircle/j; dLineLength=LineLength/j;//直线密化 dLineX=dLineLength*cos(ArcLine); dLineY=dLineLength*sin(ArcLine); CircleLine(dLineX,dLineY,ArcCircle,ArcCircleStart,j,R,circularMode,UpMode); } else if(i==1) { //圆弧过小,最小弦长大于圆弧至今,或是最小弦长对应的圆心角大于圆弧圆心角,直接绘图 if(minLength>=2*R||asin(minLength/(2*R))>ArcCircle/2) { if(UpMode==1) { now_up_X=now_up_X+LineEndX; now_up_Y=now_up_Y+LineEndY; now_down_X=now_down_X+CircleEndX; now_down_Y=now_down_Y+CircleEndY; } else { now_down_X=now_down_X+LineEndX; now_down_Y=now_down_Y+LineEndY; now_up_X=now_up_X+CircleEndX; now_up_Y=now_up_Y+CircleEndY; } Draw(); } else { //用minLength密化 j=asin(minLength/(2*R))/(ArcCircle/2); dArc=ArcCircle/j; dLineLength=LineLength/j; dLineX=dLineLength*cos(ArcLine); dLineY=dLineLength*sin(ArcLine); CircleLine(dLineX,dLineY,ArcCircle,ArcCircleStart,j,R,circularMode,UpMode); } } else if(i==2) { //用maxLength密化 j=asin(maxLength/(2*R))/(ArcCircle/2); dArc=ArcCircle/j; dLineLength=LineLength/j; dLineX=dLineLength*cos(ArcLine); dLineY=dLineLength*sin(ArcLine); CircleLine(dLineX,dLineY,ArcCircle,ArcCircleStart,j,R,circularMode,UpMode); } } }