CREATE_TEST(AGraph_construction)
CREATE_TEST(clusters)
+CREATE_TEST(edge_penwidth)
CREATE_TEST(engines)
CREATE_TEST(GVContext_construction)
CREATE_TEST(GVContext_render_svg)
SVG::SVGRect GraphvizEdge::bbox() const { return m_svg_g_element.bbox(); }
SVG::SVGPoint GraphvizEdge::center() const { return bbox().center(); }
+
+double GraphvizEdge::penwidth() const {
+ return m_svg_g_element.attribute_from_subtree<double>(
+ &SVG::SVGAttributes::stroke_width, &SVG::SVGElement::is_shape_element, 1);
+}
/// Return the 'edgeop' according to the DOT language specification. Note that
/// this is not the same as the 'id' attribute of an edge.
std::string_view edgeop() const;
+ /// Return the edge's `penwidth` attribute
+ double penwidth() const;
/// Return a non-mutable reference to the SVG `g` element corresponding to the
/// edge
const SVG::SVGElement &svg_g_element() const;
--- /dev/null
+#include <catch2/catch.hpp>
+#include <fmt/format.h>
+
+#include "svg_analyzer.h"
+#include "test_utilities.h"
+
+TEST_CASE("Edge penwidth",
+ "Test that the Graphviz 'penwidth' attribute is used to set the "
+ "'stroke-width' attribute correctly for edges in the generated SVG") {
+
+ const auto primitive_arrow_shape =
+ GENERATE(from_range(all_primitive_arrow_shapes));
+ INFO(fmt::format("Primitive arrow shape: {}", primitive_arrow_shape));
+
+ const auto edge_penwidth = GENERATE(0.5, 1.0, 2.0);
+ INFO(fmt::format("Edge penwidth: {}", edge_penwidth));
+
+ auto dot =
+ fmt::format("digraph g1 {{edge [arrowhead={} penwidth={}]; a -> b}}",
+ primitive_arrow_shape, edge_penwidth);
+
+ const auto engine = "dot";
+ auto svg_analyzer = SVGAnalyzer::make_from_dot(dot, engine);
+
+ for (const auto &graph : svg_analyzer.graphs()) {
+ for (const auto &edge : graph.edges()) {
+ CHECK(edge.penwidth() == edge_penwidth);
+ }
+ }
+}
node_shapes_consisting_of_ellipse_and_polyline.contains(shape);
}
+const std::unordered_set<std::string_view> primitive_polygon_arrow_shapes = {
+ "crow", "diamond", "inv", "normal", "vee"};
+
+const std::unordered_set<std::string_view>
+ primitive_polygon_and_polyline_arrow_shapes = {"box", "tee"};
+
+const std::unordered_set<std::string_view> all_primitive_arrow_shapes = {
+ "box", "crow", "curve", "diamond", "dot", "icurve",
+ "inv", "none", "normal", "tee", "vee"};
+
const std::unordered_set<std::string_view> all_rank_directions = {"TB", "BT",
"LR", "RL"};
bool contains_ellipse_shape(std::string_view shape);
bool contains_polygon_shape(std::string_view shape);
+/// arrow shapes
+extern const std::unordered_set<std::string_view>
+ primitive_polygon_arrow_shapes;
+extern const std::unordered_set<std::string_view>
+ primitive_polygon_and_polyline_arrow_shapes;
+extern const std::unordered_set<std::string_view> all_primitive_arrow_shapes;
+
/// rank directions
extern const std::unordered_set<std::string_view> all_rank_directions;