@@ -869,7 +869,7 @@ bool ofxSvg::_addElementFromXmlNode( ofXml& tnode, vector< shared_ptr<ofxSvgElem
869869 return true ;
870870}
871871
872- std::vector<glm::vec3> parsePoints (const std::string& input) {
872+ std::vector<float > parseToFloats (const std::string& input) {
873873 std::vector<glm::vec3> points;
874874 std::regex regex (" [-]?\\ d*\\ .?\\ d+" ); // Matches positive/negative floats
875875 std::sregex_iterator begin (input.begin (), input.end (), regex), end;
@@ -885,7 +885,29 @@ std::vector<glm::vec3> parsePoints(const std::string& input) {
885885 }
886886 }
887887
888- // Create vec2 pairs from the values
888+ return values;
889+ }
890+
891+ std::vector<glm::vec3> parsePoints (const std::string& input) {
892+ // std::vector<glm::vec3> points;
893+ // std::regex regex("[-]?\\d*\\.?\\d+"); // Matches positive/negative floats
894+ // std::sregex_iterator begin(input.begin(), input.end(), regex), end;
895+ //
896+ // std::vector<float> values;
897+ //
898+ // // Extract all floating-point values using regex
899+ // for (std::sregex_iterator i = begin; i != end; ++i) {
900+ // try {
901+ // values.push_back(std::stof((*i).str()));
902+ // } catch (const std::invalid_argument&) {
903+ // std::cerr << "Invalid number found: " << (*i).str() << std::endl;
904+ // }
905+ // }
906+
907+ std::vector<glm::vec3> points;
908+ auto values = parseToFloats ( input );
909+
910+ // Create vec3 pairs from the values
889911 for (size_t i = 0 ; i < values.size (); i += 2 ) {
890912 if (i + 1 < values.size ()) {
891913 glm::vec3 point (values[i], values[i + 1 ], 0 .f );
@@ -902,6 +924,44 @@ std::vector<glm::vec3> parsePoints(const std::string& input) {
902924}
903925
904926
927+ std::vector<glm::vec3> parsePointsDefaultY (const std::string& input, float aYpos ) {
928+ std::vector<glm::vec3> points;
929+ auto values = parseToFloats ( input );
930+
931+ // Create vec3 pairs from the values
932+ for (size_t i = 0 ; i < values.size (); i++) {
933+ glm::vec3 point (values[i], aYpos, 0 .f );
934+ points.push_back (point);
935+ }
936+
937+ if ( values.size () == 1 && points.size () < 1 ) {
938+ glm::vec3 point (values[0 ], aYpos, 0 .f );
939+ points.push_back (point);
940+ }
941+
942+ return points;
943+ }
944+
945+ std::vector<glm::vec3> parsePointsDefaultX (const std::string& input, float aXpos ) {
946+ std::vector<glm::vec3> points;
947+ auto values = parseToFloats ( input );
948+
949+ // Create vec3 pairs from the values
950+ for (size_t i = 0 ; i < values.size (); i++) {
951+ glm::vec3 point (aXpos, values[i], 0 .f );
952+ points.push_back (point);
953+ }
954+
955+ if ( values.size () == 1 && points.size () < 1 ) {
956+ glm::vec3 point (aXpos, values[0 ], 0 .f );
957+ points.push_back (point);
958+ }
959+
960+ return points;
961+ }
962+
963+
964+
905965// ----------------------------------------------------
906966std::vector<double > _parseSvgArc (const std::string& arcStr) {
907967 std::vector<double > result;
@@ -1027,8 +1087,7 @@ void ofxSvg::_parsePolylinePolygon( ofXml& tnode, std::shared_ptr<ofxSvgPath> aS
10271087// reference: https://www.w3.org/TR/SVG2/paths.html#PathData
10281088// --------------------------------------------------------------
10291089void ofxSvg::_parsePath ( ofXml& tnode, std::shared_ptr<ofxSvgPath> aSvgPath ) {
1030- // path4160
1031-
1090+ // path27340-8
10321091
10331092 aSvgPath->path .clear ();
10341093
@@ -1107,14 +1166,13 @@ void ofxSvg::_parsePath( ofXml& tnode, std::shared_ptr<ofxSvgPath> aSvgPath ) {
11071166 return aCurrentPos;
11081167 };
11091168
1110- auto lineToRelativeRecursive = [](glm::vec3& aStartPos, glm::vec3& acurrentPos, std::vector<glm::vec3>& aposes, std::shared_ptr<ofxSvgPath> aPath ) {
1111- // int ncounter = 0;
1169+ auto lineToRelativeFromAbsoluteRecursive = [](glm::vec3& aStartPos, glm::vec3& acurrentPos, std::vector<glm::vec3>& aposes, std::shared_ptr<ofxSvgPath> aPath ) {
1170+ // int ncounter = 0;
11121171 auto cp = aStartPos;
11131172 for ( auto & np : aposes ) {
11141173 auto relativePos = np-aStartPos;
1174+ // auto relativePos = np;
11151175 auto newPos = relativePos + cp;
1116- // ofLogNotice("ofxSvg::_parsePath") << ncounter << " - l: " << prevPos << " cp: " << cp << " np: " << np;
1117- // ofLogVerbose("ofxSvg::_parsePath") << ncounter << " - l: " << prevPos << " np: " << np << " relative: " << relativePos << " newPos: " << newPos << " currentPos: " << currentPos;
11181176 aPath->path .lineTo (newPos);
11191177 cp = newPos;// relativePos+prevPos;
11201178// ncounter++;
@@ -1131,6 +1189,8 @@ void ofxSvg::_parsePath( ofXml& tnode, std::shared_ptr<ofxSvgPath> aSvgPath ) {
11311189
11321190 aSvgPath->path .clear ();
11331191
1192+ // auto prevCmd = ofPath::Command::close;
1193+
11341194 unsigned int justInCase = 0 ;
11351195// std::vector<ofPath::Command> commands;
11361196 bool breakMe = false ;
@@ -1212,31 +1272,37 @@ void ofxSvg::_parsePath( ofXml& tnode, std::shared_ptr<ofxSvgPath> aSvgPath ) {
12121272 }
12131273 npositions = parsePoints (currentString);
12141274 for ( int ni = 0 ; ni < npositions.size (); ni++ ) {
1215- ofLogVerbose (" ofxSvg::_parsePath" ) << ni << " -" << npositions[ni];
1275+ ofLogVerbose (" ofxSvg::_parsePath" ) << ni << " -> " << npositions[ni];
12161276 }
12171277// if( npositions.size() > 0 && bRelative ) {
12181278// mCurrentPathPos = npositions[0];
12191279// }
12201280 ctype = ofPath::Command::moveTo;
12211281 } else if ( cchar == ' v' || cchar == ' V' ) {
1282+
1283+ float xvalue = 0 .f ;
12221284 if ( cchar == ' v' ) {
12231285 bRelative = true ;
1224- npositions[0 ].x = 0 .f ;
1286+ // npositions[0].x = 0.f;
12251287 } else {
1226- npositions[0 ].x = currentPos.x ;
1288+ // npositions[0].x = currentPos.x;
1289+ xvalue = currentPos.x ;
12271290 }
1228-
1229- npositions[0 ].y = ofToFloat (currentString);
1291+ npositions = parsePointsDefaultX (currentString,xvalue);
1292+ // npositions[0].y = ofToFloat(currentString);
12301293 // ofLogVerbose("ofxSvg") << cchar << " line to: " << npositions[0] << " current pos: " << currentPos;
12311294 ctype = ofPath::Command::lineTo;
12321295 } else if ( cchar == ' H' || cchar == ' h' ) {
1296+ float yvalue = 0 .f ;
12331297 if ( cchar == ' h' ) {
12341298 bRelative = true ;
1235- npositions[0 ].y = 0 .f ;
1299+ // npositions[0].y = 0.f;
12361300 } else {
1237- npositions[0 ].y = currentPos.y ;
1301+ // npositions[0].y = currentPos.y;
1302+ yvalue = currentPos.y ;
12381303 }
1239- npositions[0 ].x = ofToFloat (currentString);
1304+ npositions = parsePointsDefaultY (currentString,yvalue);
1305+ // npositions[0].x = ofToFloat(currentString);
12401306
12411307 ctype = ofPath::Command::lineTo;
12421308 } else if ( cchar == ' L' || cchar == ' l' ) {
@@ -1300,12 +1366,7 @@ void ofxSvg::_parsePath( ofXml& tnode, std::shared_ptr<ofxSvgPath> aSvgPath ) {
13001366
13011367 if ( ctype.has_value () ) {
13021368
1303- // for( auto& np : npositions ) {
1304- // ofLogNotice("ofxSvg") << cchar << " position: " << np;
1305- // }
1306-
13071369 auto prevPos = currentPos;
1308-
13091370 auto commandT = ctype.value ();
13101371
13111372 if ( commandT == ofPath::Command::arc ) {
@@ -1326,84 +1387,99 @@ void ofxSvg::_parsePath( ofXml& tnode, std::shared_ptr<ofxSvgPath> aSvgPath ) {
13261387 // TODO: Check quad bezier for poly bezier like cubic bezier
13271388
13281389 } else {
1329- // if( commandT == ofPath::Command::moveTo ) {
1330- // ofLogNotice("ofxSvg") << "before current pos is altered: move to: " << npositions[0] << " current Pos: " << currentPos << " relative: " << bRelative;
1331- // }
13321390 if ( npositions.size () > 0 && commandT != ofPath::Command::close ) {
1333- if ( commandT != ofPath::Command::moveTo ) {
1334- // currentPos = {0.f, 0.f, 0.f};
1335- }
1391+ if ( commandT == ofPath::Command::moveTo ) {
1392+ // going to handle this below;
1393+ // inside the if( commandT == ofPath::Command::moveTo ) { check.
1394+ } else {
13361395// currentPos = convertToAbsolute(bRelative, currentPos, npositions );
1337- currentPos = convertToAbsolute (bRelative, currentPos, npositions );
1396+ currentPos = convertToAbsolute (bRelative, currentPos, npositions );
1397+ }
13381398 }
13391399 }
13401400
1341- // if( npositions.size() > 0 ) {
1342- // ofLogNotice("ofxSvg") << "before current pos is altered: move to: " << npositions[0] << " current Pos: " << currentPos << " relative: " << bRelative;
1343- // }
1344-
13451401 if ( commandT != ofPath::Command::bezierTo ) {
13461402 secondControlPoint = currentPos;
13471403 }
13481404 if ( commandT != ofPath::Command::quadBezierTo ) {
13491405 qControlPoint = currentPos;
13501406 }
1351-
1407+
13521408 if ( commandT == ofPath::Command::moveTo ) {
1353- aSvgPath->path .moveTo (currentPos);
1409+
1410+ if ( cchar == ' m' ) {
1411+ if (npositions.size () > 0 ) {
1412+ if (cindex == 0 ) {
1413+ // this is the first m, so the moveTo is absolute but the subsequent points are relative
1414+ currentPos = npositions[0 ];
1415+ } else {
1416+ currentPos += npositions[0 ];
1417+ }
1418+ }
1419+ } else {
1420+ if (npositions.size () > 0 ) {
1421+ currentPos = npositions[0 ];
1422+ }
1423+ }
1424+
1425+ if ( npositions.size () > 0 ) {
1426+ ofLogVerbose (" ofxSvg::moveTo" ) << npositions[0 ] << " currentPos: " << currentPos;// << " path pos: " << aSvgPath->pos;
1427+ aSvgPath->path .moveTo (currentPos);
1428+ // mCenterPoints.push_back(npositions[0] + pathOffset);
1429+ }
1430+
13541431 if (npositions.size () > 1 ) {
1355-
13561432 bool bLineToRelative = bRelative;
13571433 // determine if these points started with m and is the first character
1358- if ( cchar == ' m' && cindex == 0 ) {
1434+ if ( cchar == ' m' ) {
13591435 bLineToRelative = true ;
13601436 }
13611437
13621438 if ( bLineToRelative ) {
1363- auto newPoses = npositions;
1364- newPoses.erase (newPoses.begin ());
1365- lineToRelativeRecursive (prevPos, currentPos, newPoses, aSvgPath);
1439+ for ( int ki = 1 ; ki < npositions.size (); ki++ ) {
1440+ // auto newPos = npositions[ki] + cp;
1441+ currentPos += npositions[ki];
1442+ aSvgPath->path .lineTo (currentPos);
1443+ // cp = newPos;
1444+ }
1445+ // currentPos = cp;
1446+
13661447 } else {
13671448 for ( int ki = 1 ; ki < npositions.size (); ki++ ) {
1449+ // mCPoints.push_back(npositions[ki]);
1450+ // ofLogVerbose("ofxSvg::lineTo") << ki << "--->" << npositions[ki];
13681451 aSvgPath->path .lineTo (npositions[ki]);
1452+ // mCenterPoints.push_back(npositions[ki] + pathOffset);
1453+ }
1454+ if (npositions.size () > 0 ) {
1455+ currentPos = npositions.back ();
13691456 }
13701457 }
13711458 }
1459+
1460+ secondControlPoint = currentPos;
1461+ qControlPoint = currentPos;
1462+
13721463 } else if ( commandT == ofPath::Command::lineTo ) {
13731464 if ( npositions.size () > 0 ) {
13741465 // current pos is already set above
13751466 // so just worry about adding paths
13761467 if ( bRelative ) {
1377-
1378- lineToRelativeRecursive (prevPos, currentPos, npositions, aSvgPath );
1379- // mCenterPoints.clear();
1380- // int ncounter = 0;
1381- // auto cp = prevPos;
1382- // for( auto& np : npositions ) {
1383- // auto relativePos = np-prevPos;
1384- // auto newPos = relativePos + cp;
1385- // // ofLogNotice("ofxSvg::_parsePath") << ncounter << " - l: " << prevPos << " cp: " << cp << " np: " << np;
1386- // // ofLogVerbose("ofxSvg::_parsePath") << ncounter << " - l: " << prevPos << " np: " << np << " relative: " << relativePos << " newPos: " << newPos << " currentPos: " << currentPos;
1387- // aSvgPath->path.lineTo(newPos);
1388- // mCenterPoints.push_back(newPos);
1389- // cp = newPos;//relativePos+prevPos;
1390- // ncounter++;
1391- // }
1392- // currentPos = cp;
1393- // // }
1468+ lineToRelativeFromAbsoluteRecursive (prevPos, currentPos, npositions, aSvgPath );
13941469 } else {
1395- // int ncounter = 0;
1470+ int ncounter = 0 ;
13961471 for ( auto & np : npositions ) {
1397- // ofLogVerbose("ofxSvg::_parsePath ") << ncounter << " - l: " << prevPos << " np: " << np ;
1472+ ofLogVerbose (" ofxSvg::lineTo " ) << ncounter << " ---> " << np << " prevPos: " << prevPos ;
13981473 aSvgPath->path .lineTo (np);
1399- // ncounter++;
1474+ ncounter++;
14001475 }
14011476 }
14021477 }
14031478// aSvgPath->path.moveTo(currentPos);
14041479// aSvgPath->path.lineTo(currentPos);
14051480 } else if ( commandT == ofPath::Command::close ) {
14061481// ofLogNotice("ofxSvg") << "Closing the path";
1482+ // TODO: Not sure if we need to draw a line to the start point here
14071483 aSvgPath->path .close ();
14081484 } else if ( commandT == ofPath::Command::bezierTo ) {
14091485
@@ -1595,6 +1671,7 @@ void ofxSvg::_parsePath( ofXml& tnode, std::shared_ptr<ofxSvgPath> aSvgPath ) {
15951671 }
15961672 }
15971673
1674+ // prevCmd = commandT;
15981675// mCenterPoints.push_back(currentPos);
15991676// mCPoints.insert( mCPoints.end(), npositions.begin(), npositions.end() );
16001677 }
@@ -1859,21 +1936,33 @@ glm::mat4 ofxSvg::setTransformFromSvgMatrixString( string aStr, std::shared_ptr<
18591936 vector<float > matrixF;
18601937 for (std::size_t i = 0 ; i < matrixNum.size (); i++){
18611938 matrixF.push_back (ofToFloat (matrixNum[i]));
1862- std::cout << aele->getCleanName () << " matrix[" << i << " ] = " << matrixF[i] << " string version is " << matrixNum[i] << std::endl ;
1939+ ofLogVerbose ( " ofxSvg::setTransformFromSvgMatrixString " ) << aele->getCleanName () << " matrix[" << i << " ] = " << matrixF[i] << " string version is " << matrixNum[i];
18631940 }
18641941
18651942 if ( matrixNum.size () == 6 ) {
18661943
18671944 mat = glm::translate (glm::mat4 (1 .0f ), glm::vec3 (matrixF[4 ], matrixF[5 ], 0 .0f ));
18681945
18691946 aele->rotation = glm::degrees ( atan2f (matrixF[1 ],matrixF[0 ]) );
1947+
1948+
1949+ aele->scale .x = glm::sqrt (matrixF[0 ] * matrixF[0 ] + matrixF[1 ] * matrixF[1 ]);
1950+ aele->scale .y = glm::sqrt (matrixF[2 ] * matrixF[2 ] + matrixF[3 ] * matrixF[3 ]);
1951+
1952+ if (matrixF[0 ] < 0 ) aele->scale .x *= -1 .f ;
1953+ if (matrixF[3 ] < 0 ) aele->scale .y *= -1 .f ;
1954+
1955+ // Avoid double-rotating when both scale = -1 and rotation = 180
1956+ if (aele->scale .x < 0 && aele->scale .y < 0 && glm::abs (aele->rotation - 180 .0f ) < 0 .01f ) {
1957+ aele->rotation = 0 .f ;
1958+ }
1959+
18701960 if ( aele->rotation != 0 .f ) {
18711961// mat = mat * glm::toMat4((const glm::quat&)glm::angleAxis(glm::radians(aele->rotation), glm::vec3(0.f, 0.f, 1.f)));
18721962 mat = glm::rotate (mat, glm::radians (aele->rotation ), glm::vec3 (0 .f , 0 .f , 1 .f ));
18731963 }
18741964
1875- aele->scale .x = glm::sqrt (matrixF[0 ] * matrixF[0 ] + matrixF[1 ] * matrixF[1 ]);
1876- aele->scale .y = glm::sqrt (matrixF[2 ] * matrixF[2 ] + matrixF[3 ] * matrixF[3 ]);
1965+
18771966
18781967 mat = glm::scale (mat, glm::vec3 (aele->scale .x , aele->scale .y , 1 .f ));
18791968
@@ -1882,6 +1971,8 @@ glm::mat4 ofxSvg::setTransformFromSvgMatrixString( string aStr, std::shared_ptr<
18821971 aele->pos .x = pos3.x ;
18831972 aele->pos .y = pos3.y ;
18841973
1974+ ofLogNotice (" ofxSvg::setTransformFromSvgMatrixString" ) << " pos: " << aele->pos << " rotation: " << aele->rotation << " scale: " << aele->scale ;
1975+
18851976// apos.x = matrixF[4];
18861977// apos.y = matrixF[5];
18871978//
@@ -2383,7 +2474,7 @@ void ofxSvg::drawDebug() {
23832474// cindex ++;
23842475// }
23852476// ofFill();
2386-
2477+
23872478 for ( std::size_t k = 0 ; k < mCPoints .size (); k += 3 ) {
23882479 ofSetColor ( ofColor::orange );
23892480 ofDrawCircle ( mCPoints [k+0 ], 6 .f );
0 commit comments