]> granicus.if.org Git - graphviz/commitdiff
tests: SvgAnalyzer: add handling of the 'd' attribute
authorMagnus Jacobsson <Magnus.Jacobsson@berotec.se>
Thu, 28 Jul 2022 10:58:49 +0000 (12:58 +0200)
committerMagnus Jacobsson <Magnus.Jacobsson@berotec.se>
Tue, 16 Aug 2022 10:21:45 +0000 (12:21 +0200)
tests/svg_analyzer.cpp
tests/svg_analyzer.h
tests/svg_analyzer_interface.h
tests/svg_element.cpp
tests/svg_element.h
tests/svgpp_context.cpp
tests/svgpp_document_traverser.cpp
tests/test_svg_analyzer.cpp

index be7b3bc2953562cb900529b1b47cbe3da4f8e722..23ffd9d374d046881653edc66a402ff225a8716b 100644 (file)
@@ -69,6 +69,21 @@ void SVGAnalyzer::on_enter_element_title() {
 
 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"};
index 861c36f6349ae047189531604fefa66c7d99187d..f4a418dea7786fb5c14237ce87f8fc005763b8b1 100644 (file)
@@ -27,6 +27,10 @@ public:
   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;
index 295f82f933f28bbd0b0fc5b2a630c9907aa65d73..2d147bcf3ade403d3998c5a6731abe578af223f8 100644 (file)
@@ -26,6 +26,10 @@ public:
   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;
index ff07e5f80e558b8559f7f0496e059fca072e2346..2566870385f0bead106c26c90cdecaaffeb3133f 100644 (file)
@@ -156,10 +156,29 @@ void SVG::SVGElement::to_string_impl(std::string &output,
           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());
index 9288347004f709fc1262179fbb457c55b64cbd63..c8864c3554e063e44da969c1521dc948b50267b6 100644 (file)
@@ -87,6 +87,8 @@ public:
   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;
index db4cf826f8b401fa28ed130c00666ad90552f3f6..d7127cbed630e03b52b46a43ab67f0b4c9a4ee07 100644 (file)
@@ -63,58 +63,45 @@ void SvgppContext::on_exit_element() { m_svgAnalyzer->on_exit_element(); }
 
 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);
index 8ee6a9ee7a45003ef868fab7745debdeb2553cd8..62e4d6e5bfb536567b6af94db61dd9ec3839aed7 100644 (file)
@@ -29,6 +29,7 @@ void traverseDocumentWithSvgpp(SvgppContext &context, char *text) {
                         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,   //
index e84f5d8ac50f6ab2c9aa564f00751eec4ca1986a..6b1b6b888040fc86d9b1d69bde730411f14b41b7 100644 (file)
@@ -115,32 +115,17 @@ TEST_CASE(
     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&#45;&gt;b -->") != std::string::npos);
   }
 }