Skip to content

Commit 2c6f49c

Browse files
committed
Improved Path handling
1 parent 6c9602c commit 2c6f49c

File tree

4 files changed

+94
-10
lines changed

4 files changed

+94
-10
lines changed

examples/graphics/source/examples/Paths.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,7 @@ class PathsExample : public yup::Component
400400

401401
// Parse SVG path data examples - smaller scale
402402
yup::Path svgHeart;
403-
svgHeart.parsePathData ("M12,21.35l-1.45-1.32C5.4,15.36,2,12.28,2,8.5 C2,5.42,4.42,3,7.5,3c1.74,0,3.41,0.81,4.5,2.09C13.09,3.81,14.76,3,16.5,3 C19.58,3,22,5.42,22,8.5c0,3.78-3.4,6.86-8.55,11.54L12,21.35z");
403+
svgHeart.fromString ("M12,21.35l-1.45-1.32C5.4,15.36,2,12.28,2,8.5 C2,5.42,4.42,3,7.5,3c1.74,0,3.41,0.81,4.5,2.09C13.09,3.81,14.76,3,16.5,3 C19.58,3,22,5.42,22,8.5c0,3.78-3.4,6.86-8.55,11.54L12,21.35z");
404404

405405
// Scale and position the heart - smaller
406406
yup::Rectangle<float> heartBounds = svgHeart.getBounds();
@@ -416,7 +416,7 @@ class PathsExample : public yup::Component
416416

417417
// Simple SVG path - smaller
418418
yup::Path svgTriangle;
419-
svgTriangle.parsePathData ("M100,20 L180,160 L20,160 Z");
419+
svgTriangle.fromString ("M100,20 L180,160 L20,160 Z");
420420
svgTriangle.scaleToFit (x + 60, y, 50, 50, true);
421421

422422
g.setFillColor (yup::Color (150, 255, 150));

modules/yup_graphics/primitives/yup_Path.cpp

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -733,6 +733,79 @@ rive::RiveRenderPath* Path::getRenderPath() const
733733
return path.get();
734734
}
735735

736+
//==============================================================================
737+
String Path::toString() const
738+
{
739+
const auto& rawPath = path->getRawPath();
740+
const auto& points = rawPath.points();
741+
const auto& verbs = rawPath.verbs();
742+
743+
if (points.empty() || verbs.empty())
744+
return String();
745+
746+
String result;
747+
result.preallocateBytes (points.size() * 20); // Rough estimate for performance
748+
749+
size_t pointIndex = 0;
750+
751+
for (size_t i = 0; i < verbs.size(); ++i)
752+
{
753+
auto verb = verbs[i];
754+
755+
switch (verb)
756+
{
757+
case rive::PathVerb::move:
758+
if (pointIndex < points.size())
759+
{
760+
result << "M " << points[pointIndex].x << " " << points[pointIndex].y << " ";
761+
pointIndex++;
762+
}
763+
break;
764+
765+
case rive::PathVerb::line:
766+
if (pointIndex < points.size())
767+
{
768+
result << "L " << points[pointIndex].x << " " << points[pointIndex].y << " ";
769+
pointIndex++;
770+
}
771+
break;
772+
773+
case rive::PathVerb::quad:
774+
// Rive doesn't seem to use quad verbs based on the existing code
775+
// But if it does, we'll handle it
776+
if (pointIndex + 1 < points.size())
777+
{
778+
result << "Q "
779+
<< points[pointIndex].x << " " << points[pointIndex].y << " "
780+
<< points[pointIndex + 1].x << " " << points[pointIndex + 1].y << " ";
781+
pointIndex += 2;
782+
}
783+
break;
784+
785+
case rive::PathVerb::cubic:
786+
if (pointIndex + 2 < points.size())
787+
{
788+
result << "C "
789+
<< points[pointIndex].x << " " << points[pointIndex].y << " "
790+
<< points[pointIndex + 1].x << " " << points[pointIndex + 1].y << " "
791+
<< points[pointIndex + 2].x << " " << points[pointIndex + 2].y << " ";
792+
pointIndex += 3;
793+
}
794+
break;
795+
796+
case rive::PathVerb::close:
797+
result << "Z ";
798+
break;
799+
}
800+
}
801+
802+
// Remove trailing space if present
803+
if (result.endsWithChar (' '))
804+
result = result.trimEnd();
805+
806+
return result;
807+
}
808+
736809
//==============================================================================
737810
namespace
738811
{
@@ -1181,7 +1254,7 @@ void handleEllipticalArc (String::CharPointerType& data, Path& path, float& curr
11811254

11821255
} // namespace
11831256

1184-
bool Path::parsePathData (const String& pathData)
1257+
bool Path::fromString (const String& pathData)
11851258
{
11861259
// https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/
11871260

modules/yup_graphics/primitives/yup_Path.h

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -583,15 +583,24 @@ class YUP_API Path
583583
Point<float> getPointAlongPath (float distance) const;
584584

585585
//==============================================================================
586+
/** Converts the path to an SVG path data string.
587+
588+
This method converts the path to a string representation using SVG path data format.
589+
The resulting string can be used with fromString() to recreate the path.
590+
591+
@return A string containing the SVG path data representation of this path.
592+
*/
593+
String toString() const;
594+
586595
/** Parses the path data from a string.
587596
588-
This method parses the path data from a string and updates the path accordingly.
597+
This method parses the path data from a string in SVG path data format and updates the path accordingly.
589598
590-
@param pathData The string containing the path data.
599+
@param pathData The string containing the SVG path data.
591600
592601
@return True if the path data was parsed successfully, false otherwise.
593602
*/
594-
bool parsePathData (const String& pathData);
603+
bool fromString (const String& pathData);
595604

596605
//==============================================================================
597606
/** Provides an iterator to the beginning of the path data.

tests/yup_graphics/yup_Path.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -276,16 +276,18 @@ TEST (PathTests, WithRoundedCorners)
276276
EXPECT_FALSE (same.getBounds().isEmpty());
277277
}
278278

279-
TEST (PathTests, ParsePathData)
279+
TEST (PathTests, FromString)
280280
{
281281
Path p;
282282
// Simple SVG path: M10 10 H 90 V 90 H 10 Z
283-
bool ok = p.parsePathData ("M10 10 H 90 V 90 H 10 Z");
283+
bool ok = p.fromString ("M 10 10 H 90 V 90 H 10 Z");
284284
EXPECT_TRUE (ok);
285285
EXPECT_FALSE (p.getBounds().isEmpty());
286+
EXPECT_EQ (p.toString(), "M 10 10 L 90 10 L 90 90 L 10 90 Z");
287+
286288
// Edge: malformed path
287289
Path p2;
288-
ok = p2.parsePathData ("M10 10 Q");
290+
ok = p2.fromString ("M 10 10 Q");
289291
EXPECT_TRUE (ok); // Should not throw, but result is empty
290292
}
291293

@@ -455,7 +457,7 @@ TEST (PathTests, AllPublicApiErrorCases)
455457
p.getPointAlongPath (0.0f);
456458
p.createStrokePolygon (0.0f);
457459
p.withRoundedCorners (0.0f);
458-
p.parsePathData ("");
460+
p.fromString ("");
459461
SUCCEED();
460462
}
461463

0 commit comments

Comments
 (0)