#include "SVG.hpp" #include namespace Kanimaji::SVG { struct Vec2 { double x; double y; friend Vec2 operator+(const Vec2& u, const Vec2& v) { return Vec2 { .x = u.x + v.x, .y = u.y + v.y, }; } }; class Path::Element { public: virtual ~Element() = default; virtual double Length(Vec2 origin) const = 0; virtual Vec2 Endpoint(Vec2 origin) const = 0; }; namespace { class ParseError : public Error { public: ParseError(std::size_t current, std::string_view message) : Error(std::format("[At: {}] {}", current, message)) {} }; class Move : public Path::Element { public: Move(bool relative, Vec2 move) : mRelative(relative), mMove(move) {} double Length(Vec2 origin) const override { return 0; } Vec2 Endpoint(Vec2 origin) const override { return mRelative ? origin + mMove : mMove; } private: bool mRelative; // 7B padding, oof Vec2 mMove; }; class CubicBezier : public Path::Element { public: CubicBezier(bool relative, Vec2 control1, Vec2 control2, Vec2 end) : mRelative(relative), mControl1(control1), mControl2(control2), mEnd(end) {} double Length(Vec2 origin) const override { throw Error("not implemented"); } Vec2 Endpoint(Vec2 origin) const override { return mEnd; } private: bool mRelative; // 7B padding, oof Vec2 mControl1; Vec2 mControl2; Vec2 mEnd; }; using ElementPtr = std::unique_ptr; void Parse(std::string_view definition, std::vector& elements) { std::size_t current = 0; while (current < definition.size()) { switch (definition[current]) { case 'M': [[fallthrough]]; case 'm': // ParseMove break; case 'C': [[fallthrough]]; case 'c': // ParseCubicBezier break; default: throw ParseError(current, "Unrecognized character"); } } } } Path::Path(std::string_view definition) { Parse(definition, mSegments); } Path::~Path() = default; double Path::Length() const { return 0; } }