diff --git a/include/graaflib/io/dot.h b/include/graaflib/io/dot.h index e0a7c746..f8790195 100644 --- a/include/graaflib/io/dot.h +++ b/include/graaflib/io/dot.h @@ -43,6 +43,8 @@ const auto default_edge_writer{ * edge_id_t and a graph::edge_t and serialize it to a string. Default * implementations are provided for primitive numeric types. * @param path Path to the output dot file. + * @param horizontal If true, lays out the graph horizontally, otherwise lays it + * out vertically. Defaults to false. */ template ), @@ -55,8 +57,9 @@ template & graph, const std::filesystem::path& path, const VERTEX_WRITER_T& vertex_writer = detail::default_vertex_writer, - const EDGE_WRITER_T& edge_writer = detail::default_edge_writer); + const EDGE_WRITER_T& edge_writer = detail::default_edge_writer, + bool horizontal = false); } // namespace graaf::io -#include "dot.tpp" \ No newline at end of file +#include "dot.tpp" diff --git a/include/graaflib/io/dot.tpp b/include/graaflib/io/dot.tpp index f0a4dbe7..ccd22175 100644 --- a/include/graaflib/io/dot.tpp +++ b/include/graaflib/io/dot.tpp @@ -72,7 +72,7 @@ template ::edge_t&> void to_dot(const graph& graph, const std::filesystem::path& path, const VERTEX_WRITER_T& vertex_writer, - const EDGE_WRITER_T& edge_writer) { + const EDGE_WRITER_T& edge_writer, bool horizontal) { std::ofstream dot_file{path}; const auto append_line{ @@ -81,6 +81,10 @@ void to_dot(const graph& graph, const std::filesystem::path& path, // TODO(bluppes): replace with std::format once Clang supports it append_line(std::string(detail::graph_type_to_string(T)) + " {"); + if (horizontal) { + append_line("rankdir=\"LR\";"); + } + for (const auto& [vertex_id, vertex] : graph.get_vertices()) { append_line("\t" + std::to_string(vertex_id) + " [" + vertex_writer(vertex_id, vertex) + "];"); diff --git a/test/graaflib/io/dot_test.cpp b/test/graaflib/io/dot_test.cpp index 0d8d7098..571db2af 100644 --- a/test/graaflib/io/dot_test.cpp +++ b/test/graaflib/io/dot_test.cpp @@ -256,4 +256,40 @@ TEST(DotTest, DefaultWriters) { vertex_2)) != std::string::npos); } -} // namespace graaf::io \ No newline at end of file +TEST(DotTest, HorizontalGraph) { + // GIVEN + struct vertex_t { + int numeric_data{}; + std::string string_data{}; + }; + + struct edge_t { + int numeric_data{}; + std::string string_data{}; + }; + + const std::filesystem::path path{std::filesystem::temp_directory_path() / + "DotTest_HorizontalGraph.dot"}; + directed_graph graph{}; + + const auto vertex_1{graph.add_vertex(vertex_t{10, "vertex 1"})}; + const auto vertex_2{graph.add_vertex(vertex_t{20, "vertex 2"})}; + graph.add_edge(vertex_1, vertex_2, edge_t{100, "edge 1"}); + + const auto vertex_writer{ + [](vertex_id_t /*vertex_id*/, const vertex_t& vertex) { + return fmt::format("{}, {}", vertex.numeric_data, vertex.string_data); + }}; + const auto edge_writer{[](const edge_id_t& /*edge_id*/, const auto& edge) { + return fmt::format("{}, {}", edge.numeric_data, edge.string_data); + }}; + + // WHEN + to_dot(graph, path, vertex_writer, edge_writer, true); + + // THEN + const auto dot_content{read_to_string(path)}; + ASSERT_TRUE(dot_content.find("rankdir=\"LR\"") != std::string::npos); +} + +} // namespace graaf::io