@@ -1106,6 +1106,15 @@ void ofxSvg::_parsePath( ofXml& tnode, std::shared_ptr<ofxSvgPath> aSvgPath ) {
11061106 return ;
11071107 }
11081108
1109+ // OF_POLY_WINDING_ODD
1110+ // / OF_POLY_WINDING_NONZERO
1111+ // / OF_POLY_WINDING_POSITIVE
1112+ // / OF_POLY_WINDING_NEGATIVE
1113+ // / OF_POLY_WINDING_ABS_GEQ_TWO
1114+ // aSvgPath->path.setPolyWindingMode(OF_POLY_WINDING_POSITIVE);
1115+ // aSvgPath->path.setPolyWindingMode(mDefaultPathWindingMode);
1116+
1117+
11091118 aSvgPath->path .setCircleResolution (mCircleResolution );
11101119 aSvgPath->path .setCurveResolution (mCurveResolution );
11111120
@@ -1137,6 +1146,9 @@ void ofxSvg::_parsePath( ofXml& tnode, std::shared_ptr<ofxSvgPath> aSvgPath ) {
11371146 glm::vec3 secondControlPoint = currentPos;
11381147 glm::vec3 qControlPoint = currentPos;
11391148
1149+ int numSubPathsClosed = 0 ;
1150+ int numSubPaths = 0 ;
1151+
11401152 auto convertToAbsolute = [](bool aBRelative, glm::vec3& aCurrentPos, std::vector<glm::vec3>& aposes) -> glm::vec3 {
11411153 for (auto & apos : aposes ) {
11421154 if ( aBRelative ) {
@@ -1283,36 +1295,27 @@ void ofxSvg::_parsePath( ofXml& tnode, std::shared_ptr<ofxSvgPath> aSvgPath ) {
12831295 for ( int ni = 0 ; ni < npositions.size (); ni++ ) {
12841296 ofLogVerbose (" ofxSvg::_parsePath" ) << ni << " ->" << npositions[ni];
12851297 }
1286- // if( npositions.size() > 0 && bRelative ) {
1287- // mCurrentPathPos = npositions[0];
1288- // }
12891298 ctype = ofPath::Command::moveTo;
1299+ numSubPaths++;
12901300 } else if ( cchar == ' v' || cchar == ' V' ) {
12911301
12921302 float xvalue = 0 .f ;
12931303 if ( cchar == ' v' ) {
12941304 bRelative = true ;
1295- // npositions[0].x = 0.f;
12961305 } else {
1297- // npositions[0].x = currentPos.x;
12981306 xvalue = currentPos.x ;
12991307 }
13001308 npositions = parsePointsDefaultX (currentString,xvalue);
1301- // npositions[0].y = ofToFloat(currentString);
13021309 // ofLogVerbose("ofxSvg") << cchar << " line to: " << npositions[0] << " current pos: " << currentPos;
13031310 ctype = ofPath::Command::lineTo;
13041311 } else if ( cchar == ' H' || cchar == ' h' ) {
13051312 float yvalue = 0 .f ;
13061313 if ( cchar == ' h' ) {
13071314 bRelative = true ;
1308- // npositions[0].y = 0.f;
13091315 } else {
1310- // npositions[0].y = currentPos.y;
13111316 yvalue = currentPos.y ;
13121317 }
13131318 npositions = parsePointsDefaultY (currentString,yvalue);
1314- // npositions[0].x = ofToFloat(currentString);
1315-
13161319 ctype = ofPath::Command::lineTo;
13171320 } else if ( cchar == ' L' || cchar == ' l' ) {
13181321 if ( cchar == ' l' ) {
@@ -1401,7 +1404,6 @@ void ofxSvg::_parsePath( ofXml& tnode, std::shared_ptr<ofxSvgPath> aSvgPath ) {
14011404 // going to handle this below;
14021405 // inside the if( commandT == ofPath::Command::moveTo ) { check.
14031406 } else {
1404- // currentPos = convertToAbsolute(bRelative, currentPos, npositions );
14051407 currentPos = convertToAbsolute (bRelative, currentPos, npositions );
14061408 }
14071409 }
@@ -1434,7 +1436,6 @@ void ofxSvg::_parsePath( ofXml& tnode, std::shared_ptr<ofxSvgPath> aSvgPath ) {
14341436 if ( npositions.size () > 0 ) {
14351437 ofLogVerbose (" ofxSvg::moveTo" ) << npositions[0 ] << " currentPos: " << currentPos;// << " path pos: " << aSvgPath->pos;
14361438 aSvgPath->path .moveTo (currentPos);
1437- // mCenterPoints.push_back(npositions[0] + pathOffset);
14381439 }
14391440
14401441 if (npositions.size () > 1 ) {
@@ -1446,19 +1447,12 @@ void ofxSvg::_parsePath( ofXml& tnode, std::shared_ptr<ofxSvgPath> aSvgPath ) {
14461447
14471448 if ( bLineToRelative ) {
14481449 for ( int ki = 1 ; ki < npositions.size (); ki++ ) {
1449- // auto newPos = npositions[ki] + cp;
14501450 currentPos += npositions[ki];
14511451 aSvgPath->path .lineTo (currentPos);
1452- // cp = newPos;
14531452 }
1454- // currentPos = cp;
1455-
14561453 } else {
14571454 for ( int ki = 1 ; ki < npositions.size (); ki++ ) {
1458- // mCPoints.push_back(npositions[ki]);
1459- // ofLogVerbose("ofxSvg::lineTo") << ki << "--->" << npositions[ki];
14601455 aSvgPath->path .lineTo (npositions[ki]);
1461- // mCenterPoints.push_back(npositions[ki] + pathOffset);
14621456 }
14631457 if (npositions.size () > 0 ) {
14641458 currentPos = npositions.back ();
@@ -1484,12 +1478,11 @@ void ofxSvg::_parsePath( ofXml& tnode, std::shared_ptr<ofxSvgPath> aSvgPath ) {
14841478 }
14851479 }
14861480 }
1487- // aSvgPath->path.moveTo(currentPos);
1488- // aSvgPath->path.lineTo(currentPos);
14891481 } else if ( commandT == ofPath::Command::close ) {
14901482// ofLogNotice("ofxSvg") << "Closing the path";
14911483 // TODO: Not sure if we need to draw a line to the start point here
14921484 aSvgPath->path .close ();
1485+ numSubPathsClosed++;
14931486 } else if ( commandT == ofPath::Command::bezierTo ) {
14941487
14951488 if ( cchar == ' S' || cchar == ' s' ) {
@@ -1507,12 +1500,6 @@ void ofxSvg::_parsePath( ofXml& tnode, std::shared_ptr<ofxSvgPath> aSvgPath ) {
15071500 }
15081501
15091502 npositions = ppositions;
1510-
1511- // if( npositions.size() == 2 ) {
1512- // auto cp2 = (secondControlPoint - prevPos) * -1.f;
1513- // cp2 += prevPos;
1514- // npositions.insert(npositions.begin(), cp2 );
1515- // }
15161503 }
15171504
15181505 auto tcpos = prevPos;
@@ -1525,19 +1512,7 @@ void ofxSvg::_parsePath( ofXml& tnode, std::shared_ptr<ofxSvgPath> aSvgPath ) {
15251512 mCPoints .push_back (npositions[k+0 ]);
15261513 mCPoints .push_back (npositions[k+1 ]);
15271514 tcpos = npositions[k+2 ];
1528-
1529- // mCPoints.push_back(npositions[k+0]);
1530- // mCPoints.push_back(npositions[k+1]);
1531- // mCenterPoints.push_back(npositions[k+2]);
15321515 }
1533-
1534- // mCPoints.insert( mCPoints.end(), npositions.begin(), npositions.end() );
1535-
1536- // if( npositions.size() == 3 ) {
1537- // aSvgPath->path.bezierTo(npositions[0], npositions[1], npositions[2]);
1538- // }
1539- //
1540- // secondControlPoint = npositions[1];
15411516 } else if ( commandT == ofPath::Command::quadBezierTo ) {
15421517 if ( cchar == ' T' || cchar == ' t' ) {
15431518 if ( npositions.size () == 1 ) {
@@ -1564,9 +1539,7 @@ void ofxSvg::_parsePath( ofXml& tnode, std::shared_ptr<ofxSvgPath> aSvgPath ) {
15641539
15651540 glm::vec3 spt = prevPos;
15661541 glm::vec3 ept = npositions[3 ];
1567-
1568-
1569- // glm::vec3 cpt(spt.x, ept.y, 0.0f);
1542+
15701543 auto cpt = glm::vec3 (findArcCenter (spt, ept, radii.x , radii.y , xAxisRotation, largeArcFlag, sweepFlag ), 0 .f );
15711544 auto windingOrder = _getWindingOrderOnArc ( spt, cpt, ept );
15721545
@@ -1629,19 +1602,12 @@ void ofxSvg::_parsePath( ofXml& tnode, std::shared_ptr<ofxSvgPath> aSvgPath ) {
16291602 ofPolyline tline;
16301603
16311604 if ( windingOrder < 0 ) {
1632- // aSvgPath->path.arcNegative(cpt, radii.x, radii.y, glm::degrees(startAngle), glm::degrees(endAngle) );
16331605 tline.arcNegative (cpt, radii.x , radii.y , glm::degrees (startAngle-xrotRad), glm::degrees (endAngle-xrotRad), mCircleResolution );
1634- // tline.arcNegative(cpt, radii.x, radii.y, glm::degrees(startAngle), glm::degrees(endAngle) );
1635- // aSvgPath->path.arcNegative(cpt, radii.x, radii.y, glm::degrees(startAngle-xrotRad), glm::degrees(endAngle-xrotRad) );
16361606 } else {
16371607 tline.arc (cpt, radii.x , radii.y , glm::degrees (startAngle-xrotRad), glm::degrees (endAngle-xrotRad), mCircleResolution );
1638- // tline.arc(cpt, radii.x, radii.y, glm::degrees(startAngle), glm::degrees(endAngle) );
1639- // aSvgPath->path.arc(cpt, radii.x, radii.y, glm::degrees(startAngle-xrotRad), glm::degrees(endAngle-xrotRad) );
1640- // aSvgPath->path.arc(cpt, radii.x, radii.y, glm::degrees(startAngle), glm::degrees(endAngle) );
16411608 }
16421609
16431610 // rotate based on x-axis rotation //
1644-
16451611// aSvgPath->path.rotateRad(xrotRad, glm::vec3(0.0f, 0.0f, 1.f));
16461612
16471613 for ( auto & pv : tline.getVertices () ) {
@@ -1666,11 +1632,6 @@ void ofxSvg::_parsePath( ofXml& tnode, std::shared_ptr<ofxSvgPath> aSvgPath ) {
16661632 }
16671633 }
16681634
1669- // auto centers = findEllipseCenter( spt, ept, radii.x, radii.y );
1670-
1671- // ofLogNotice("centers: ") << std::get<0>(centers) << " and " << std::get<1>(centers) << " spt: " << spt << " ept: " << ept << " radii: " << radii;
1672-
1673-
16741635 mCenterPoints .push_back (cpt);
16751636// mCenterPoints.push_back(cpt);
16761637 npositions.clear ();
@@ -1682,6 +1643,14 @@ void ofxSvg::_parsePath( ofXml& tnode, std::shared_ptr<ofxSvgPath> aSvgPath ) {
16821643 }
16831644
16841645// ofLogNotice("ofxSvg") << "["<<cchar<<"]: " << currentString;
1646+ // ofLogNotice("ofxSvg::_parsepath") << " num closed: " << numSubPathsClosed << " / " << numSubPaths;
1647+
1648+ // If all of the paths are closed, then set the winding mode.
1649+ // We only set it on closed paths because other winding modes can force close the paths
1650+ // which is incorrect with open paths / polylines.
1651+ if ( numSubPaths == numSubPathsClosed ) {
1652+ aSvgPath->path .setPolyWindingMode (mDefaultClosedPathWindingMode );
1653+ }
16851654
16861655 justInCase++;
16871656 }
@@ -1711,6 +1680,7 @@ ofxSvgCssClass ofxSvg::_parseStyle( ofXml& anode ) {
17111680 // now lets try to apply it to the path
17121681 auto & tCss = mSvgCss .getClass (className);
17131682 for ( auto & tprop : tCss.properties ) {
1683+ // ofLogNotice("ofxSvg") << " adding property " << tprop.first << " value: " << tprop.second.srcString;
17141684 css.addProperty (tprop.first , tprop.second );
17151685 }
17161686 }
@@ -1723,7 +1693,7 @@ ofxSvgCssClass ofxSvg::_parseStyle( ofXml& anode ) {
17231693 // avoid the following
17241694 std::vector<std::string> reservedAtts = {
17251695 " d" , " id" , " xlink:href" , " width" , " height" , " rx" , " ry" , " cx" , " cy" , " r" , " style" , " font-family" ,
1726- " x" ," y" ," x1" ," y1" ," x2" ," y2"
1696+ " x" ," y" ," x1" ," y1" ," x2" ," y2" , " transform "
17271697 };
17281698
17291699 // lets try to do this a better way
@@ -1825,7 +1795,6 @@ glm::vec3 ofxSvg::_parseMatrixString(const std::string& input, const std::string
18251795// --------------------------------------------------------------
18261796glm::mat4 ofxSvg::setTransformFromSvgMatrixString ( string aStr, std::shared_ptr<ofxSvgElement> aele ) {
18271797 ofLogVerbose (" -----------ofxSvg::setTransformFromSvgMatrixString" ) << aele->getTypeAsString () << " name: " << aele->getName () +" ----------------" ;
1828- // aele->scale = glm::vec2(1.0f, 1.0f);
18291798// aele->rotation = 0.0;
18301799 aele->setScale (1 .f );
18311800 aele->mModelRotationPoint = glm::vec2 (0 .0f , 0 .0f );
@@ -1834,7 +1803,6 @@ glm::mat4 ofxSvg::setTransformFromSvgMatrixString( string aStr, std::shared_ptr<
18341803
18351804 float trotation = 0 .f ;
18361805 glm::mat4 mat = glm::mat4 (1 .f );
1837- // glm::mat4 gmat = mModelMatrix;
18381806
18391807 if ( ofIsStringInString (aStr, " translate" )) {
18401808 auto transStr = aStr;
@@ -1900,7 +1868,7 @@ glm::mat4 ofxSvg::setTransformFromSvgMatrixString( string aStr, std::shared_ptr<
19001868// gmat = glm::scale(gmat, glm::vec3(aele->getScale().x, aele->getScale().y, 1.f));
19011869 }
19021870
1903- glm::vec3 pos3 = mat * glm::vec4 ( aele->getPosition ().x , aele->getPosition ().y , 0 .0f , 1 .f );
1871+ // glm::vec3 pos3 = mat * glm::vec4( aele->getPosition().x, aele->getPosition().y, 0.0f, 1.f );
19041872// pos3 = gmat * glm::vec4( aele->pos.x, aele->pos.y, 0.0f, 1.f );
19051873// aele->pos.x = pos3.x;
19061874// aele->pos.y = pos3.y;
@@ -1928,10 +1896,8 @@ glm::mat4 ofxSvg::setTransformFromSvgMatrixString( string aStr, std::shared_ptr<
19281896
19291897 aele->setPosition (matrixF[4 ], matrixF[5 ], 0 .f );
19301898
1931-
19321899 float trotation = glm::degrees ( atan2f (matrixF[1 ],matrixF[0 ]) );
19331900
1934-
19351901// aele->scale.x = glm::sqrt(matrixF[0] * matrixF[0] + matrixF[1] * matrixF[1]);
19361902// aele->scale.y = glm::sqrt(matrixF[2] * matrixF[2] + matrixF[3] * matrixF[3]);
19371903 float sx = glm::sqrt (matrixF[0 ] * matrixF[0 ] + matrixF[1 ] * matrixF[1 ]);
@@ -1956,11 +1922,6 @@ glm::mat4 ofxSvg::setTransformFromSvgMatrixString( string aStr, std::shared_ptr<
19561922
19571923 mat = glm::scale (mat, glm::vec3 (aele->getScale ().x , aele->getScale ().y , 1 .f ));
19581924
1959- // pos3 = mat * glm::vec4( aele->getPosition().x, aele->getPosition().y, 0.0f, 1.f );
1960- // aele->setPosition( pos3.x, pos3.y, 0.0f);
1961- // aele->pos.x = pos3.x;
1962- // aele->pos.y = pos3.y;
1963-
19641925 ofLogVerbose (" ofxSvg::setTransformFromSvgMatrixString" ) << " pos: " << aele->getPosition () << " rotation: " << trotation << " scale: " << aele->getScale ();
19651926 }
19661927 }
@@ -2187,6 +2148,16 @@ void ofxSvg::setHasStroke(bool abStroke) {
21872148 }
21882149}
21892150
2151+ // --------------------------------------------------------------
2152+ void ofxSvg::setDefaultClosedPathWindingMode ( ofPolyWindingMode aWindingMode ) {
2153+ mDefaultClosedPathWindingMode = aWindingMode;
2154+ }
2155+
2156+ // --------------------------------------------------------------
2157+ ofPolyWindingMode ofxSvg::getDefaultClosedPathWindingMode () {
2158+ return mDefaultClosedPathWindingMode ;
2159+ }
2160+
21902161// --------------------------------------------------------------
21912162std::shared_ptr<ofxSvgGroup> ofxSvg::addGroup (std::string aname) {
21922163 auto tgroup = std::make_shared<ofxSvgGroup>();
0 commit comments