void SVGAnalyzer::on_exit_element() { m_elements_in_process.pop_back(); }
+void SVGAnalyzer::path_cubic_bezier_to(double x1, double y1, double x2,
+ double y2, double x, double y) {
+ auto &path_points = current_element().path_points;
+ path_points.emplace_back(x1, y1);
+ path_points.emplace_back(x2, y2);
+ path_points.emplace_back(x, y);
+}
+
+void SVGAnalyzer::path_move_to(double x, double y) {
+ auto &paths = current_element().path_points;
+ paths.emplace_back(x, y);
+}
+
+void SVGAnalyzer::path_exit() {}
+
SVG::SVGElement &SVGAnalyzer::grandparent_element() {
if (m_elements_in_process.empty()) {
throw std::runtime_error{"No current element to get grandparent of"};
void on_enter_element_text() override;
void on_enter_element_title() override;
void on_exit_element() override;
+ void path_cubic_bezier_to(double x1, double y1, double x2, double y2,
+ double x, double y) override;
+ void path_move_to(double x, double y) override;
+ void path_exit() override;
void set_cx(double cx) override;
void set_cy(double cy) override;
void set_font_family(std::string_view font_family) override;
virtual void on_enter_element_text() = 0;
virtual void on_enter_element_title() = 0;
virtual void on_exit_element() = 0;
+ virtual void path_exit() = 0;
+ virtual void path_move_to(double x, double y) = 0;
+ virtual void path_cubic_bezier_to(double x1, double y1, double x2, double y2,
+ double x, double y) = 0;
virtual void set_class(std::string_view) = 0;
virtual void set_cx(double cx) = 0;
virtual void set_cy(double cy) = 0;
transform->a, transform->d, transform->c, transform->e, transform->f);
}
break;
- case SVG::SVGElementType::Path:
+ case SVG::SVGElementType::Path: {
append_attribute(attributes_str, fill_attribute_to_string());
append_attribute(attributes_str, stroke_attribute_to_string());
+ attributes_str += R"|( d=")|";
+ auto command = 'M';
+ for (const auto &point : path_points) {
+ attributes_str += fmt::format("{}{},{}", command, point.x, point.y);
+ switch (command) {
+ case 'M':
+ command = 'C';
+ break;
+ case 'C':
+ command = ' ';
+ break;
+ case ' ':
+ break;
+ default:
+ UNREACHABLE();
+ }
+ }
+ attributes_str += '"';
break;
+ }
case SVG::SVGElementType::Polygon:
append_attribute(attributes_str, fill_attribute_to_string());
append_attribute(attributes_str, stroke_attribute_to_string());
std::string graphviz_id;
/// The Graphviz release version
std::string graphviz_version;
+ /// The points given by the `d` attribute of a path element
+ std::vector<SVGPoint> path_points;
/// The SVG element text node contents. Not to be confused with an SVG `text`
/// element
std::string text;
void SvgppContext::path_move_to(double x, double y,
svgpp::tag::coordinate::absolute c) {
- (void)x;
- (void)y;
- (void)c;
+ if (!c.is_absolute) {
+ throw std::runtime_error{
+ "'path_move_to' using relative coordinates is not yet implemented"};
+ }
+ m_svgAnalyzer->path_move_to(x, y);
}
-void SvgppContext::path_line_to(double x, double y,
- svgpp::tag::coordinate::absolute c) {
- (void)x;
- (void)y;
- (void)c;
+void SvgppContext::path_line_to(double, double,
+ svgpp::tag::coordinate::absolute) {
+ throw std::runtime_error{"'path_line_to' is not yet implemented"};
}
void SvgppContext::path_cubic_bezier_to(double x1, double y1, double x2,
double y2, double x, double y,
svgpp::tag::coordinate::absolute c) {
- (void)x1;
- (void)y1;
- (void)x2;
- (void)y2;
- (void)x;
- (void)y;
- (void)c;
-}
-
-void SvgppContext::path_quadratic_bezier_to(
- double x1, double y1, double x, double y,
- svgpp::tag::coordinate::absolute c) {
- (void)x1;
- (void)y1;
- (void)x;
- (void)y;
- (void)c;
-}
-
-void SvgppContext::path_elliptical_arc_to(double rx, double ry,
- double x_axis_rotation,
- bool large_arc_flag, bool sweep_flag,
- double x, double y,
- svgpp::tag::coordinate::absolute c) {
- (void)rx;
- (void)ry;
- (void)x_axis_rotation;
- (void)large_arc_flag;
- (void)sweep_flag;
- (void)x;
- (void)y;
- (void)c;
-}
-
-void SvgppContext::path_close_subpath() {}
-
-void SvgppContext::path_exit() {}
+ if (!c.is_absolute) {
+ throw std::runtime_error{
+ "'path_cubic_bezier_to' using relative coordinates "
+ "is not yet implemented"};
+ }
+ m_svgAnalyzer->path_cubic_bezier_to(x1, y1, x2, y2, x, y);
+}
+
+void SvgppContext::path_quadratic_bezier_to(double, double, double, double,
+ svgpp::tag::coordinate::absolute) {
+ throw std::runtime_error{"'path_quadratic_bezier_to' is not yet implemented"};
+}
+
+void SvgppContext::path_elliptical_arc_to(double, double, double, bool, bool,
+ double, double,
+ svgpp::tag::coordinate::absolute) {
+ throw std::runtime_error{"'path_elliptical_arc_to' is not yet implemented"};
+}
+
+void SvgppContext::path_close_subpath() {
+ throw std::runtime_error{"'path_close_subpath' is not yet implemented"};
+}
+
+void SvgppContext::path_exit() { m_svgAnalyzer->path_exit(); }
void SvgppContext::set(svgpp::tag::attribute::cy, const double v) {
m_svgAnalyzer->set_cy(v);
svgpp::tag::attribute::class_, //
svgpp::tag::attribute::cx, //
svgpp::tag::attribute::cy, //
+ svgpp::tag::attribute::d, //
svgpp::tag::attribute::fill, //
svgpp::tag::attribute::font_family, //
svgpp::tag::attribute::font_size, //
const auto indent_size = 0;
auto recreated_svg = svgAnalyzer.svg_string(indent_size);
- // compare the initial lines of the recreated SVG that we can fully recreate
- // with the original SVG
- std::vector<std::string> original_svg_lines;
- boost::split(original_svg_lines, original_svg, boost::is_any_of("\n"));
- std::vector<std::string> recreated_svg_lines;
- boost::split(recreated_svg_lines, recreated_svg, boost::is_any_of("\n"));
- for (std::size_t i = 0; i < original_svg_lines.size(); i++) {
- REQUIRE(i < recreated_svg_lines.size());
- if (recreated_svg_lines[i] ==
- ("<path fill=\"none\" stroke=\"black\"/>")) {
- // stop comparison here for the 'cylinder' node shape since we do not
- // yet handle all attributes on the 'path' element
- break;
+ // compare the recreated SVG with the original SVG
+ if (recreated_svg != original_svg) {
+ std::vector<std::string> original_svg_lines;
+ boost::split(original_svg_lines, original_svg, boost::is_any_of("\n"));
+ std::vector<std::string> recreated_svg_lines;
+ boost::split(recreated_svg_lines, recreated_svg, boost::is_any_of("\n"));
+ for (std::size_t i = 0; i < original_svg_lines.size(); i++) {
+ REQUIRE(i < recreated_svg_lines.size());
+ REQUIRE(recreated_svg_lines[i] == original_svg_lines[i]);
}
- REQUIRE(recreated_svg_lines[i] == original_svg_lines[i]);
+ REQUIRE(recreated_svg_lines.size() == original_svg_lines.size());
}
-
- // do some sanity checks of the parts of the recreated SVG that we cannot
- // yet compare with the original SVG
- CHECK(recreated_svg.find("<title>g1</title>") != std::string::npos);
- CHECK(recreated_svg.find("<title>a</title>") != std::string::npos);
- CHECK(recreated_svg.find("<title>b</title>") != std::string::npos);
- CHECK(recreated_svg.find("<path fill=\"none\" stroke=\"black\"/>") !=
- std::string::npos);
- CHECK(recreated_svg.find("<!-- a -->") != std::string::npos);
- CHECK(recreated_svg.find("<!-- b -->") != std::string::npos);
- CHECK(recreated_svg.find("<!-- a->b -->") != std::string::npos);
}
}