1
+ #pragma once
2
+
3
+ #include " interval_types.hpp"
4
+
5
+ #include < iostream>
6
+ #include < string>
7
+ #include < optional>
8
+ #include < vector>
9
+ #include < utility>
10
+
11
+ namespace lib_interval_tree
12
+ {
13
+ struct dot_graph_draw_settings
14
+ {
15
+ bool digraph = true ;
16
+ std::string name = " G" ;
17
+ std::vector<std::string> extra_node_attributes = {};
18
+ std::vector<std::string> extra_statements = {};
19
+ bool space_after_comma = false ;
20
+ std::optional<char > left_brace = std::nullopt;
21
+ std::optional<char > right_brace = std::nullopt;
22
+ std::vector<std::string> edge_attributes = {};
23
+ std::string indent = " \t " ;
24
+ };
25
+
26
+ namespace detail
27
+ {
28
+ template <typename TreeT>
29
+ class graph_painter
30
+ {
31
+ public:
32
+ graph_painter (std::ostream& stream, TreeT const & tree, dot_graph_draw_settings settings)
33
+ : stream_{stream}
34
+ , tree_{tree}
35
+ , settings_{std::move (settings)}
36
+ , node_id_{" a" }
37
+ , left_brace_{}
38
+ , right_brace_{}
39
+ {
40
+ using ival_type = typename TreeT::interval_type;
41
+
42
+ const auto determine_brace = []() {
43
+ if (std::is_same_v<typename ival_type::interval_kind, closed>)
44
+ return " []" ;
45
+ else if (std::is_same_v<typename ival_type::interval_kind, left_open>)
46
+ return " (]" ;
47
+ else if (std::is_same_v<typename ival_type::interval_kind, right_open>)
48
+ return " [)" ;
49
+ else if (std::is_same_v<typename ival_type::interval_kind, open >)
50
+ return " ()" ;
51
+ else if (std::is_same_v<typename ival_type::interval_kind, closed_adjacent>)
52
+ return " []" ;
53
+ else
54
+ return " []" ;
55
+ };
56
+
57
+ if (settings_.left_brace )
58
+ left_brace_ = *settings_.left_brace ;
59
+ else
60
+ left_brace_ = determine_brace ()[0 ];
61
+
62
+ if (settings_.right_brace )
63
+ right_brace_ = *settings_.right_brace ;
64
+ else
65
+ right_brace_ = determine_brace ()[1 ];
66
+ }
67
+
68
+ void make_header ()
69
+ {
70
+ stream_ << (settings_.digraph ? " digraph" : " graph" ) << " " << settings_.name << " {\n " ;
71
+ for (auto const & statement : settings_.extra_statements )
72
+ {
73
+ stream_ << settings_.indent << statement << " ;\n " ;
74
+ }
75
+ }
76
+
77
+ template <typename T>
78
+ void make_label (T const & ival)
79
+ {
80
+ #if __cplusplus >= 201703L
81
+ if constexpr (std::is_same_v<typename T::interval_kind, dynamic>)
82
+ {
83
+ stream_ << (ival.left_border () == interval_border::open ? ' (' : ' [' ) << ival.low ()
84
+ << (settings_.space_after_comma ? " , " : " ," ) << ival.high ()
85
+ << (ival.right_border () == interval_border::open ? ' )' : ' ]' );
86
+ }
87
+ else
88
+ {
89
+ stream_ << left_brace_ << ival.low () << (settings_.space_after_comma ? " , " : " ," ) << ival.high ()
90
+ << right_brace_;
91
+ }
92
+ #else
93
+ stream_ << left_brace_ << ival.low () << (settings_.space_after_comma ? " , " : " ," ) << ival.high ()
94
+ << right_brace_;
95
+ #endif
96
+ }
97
+
98
+ template <typename interval_type>
99
+ void specify_node (interval_type const & ival)
100
+ {
101
+ stream_ << settings_.indent << node_id_ << " [label=\" " ;
102
+ increment_node_id ();
103
+ make_label (ival);
104
+ stream_ << " \" " ;
105
+ if (!settings_.extra_node_attributes .empty ())
106
+ {
107
+ for (auto const & attr : settings_.extra_node_attributes )
108
+ {
109
+ stream_ << " , " << attr;
110
+ }
111
+ }
112
+ stream_ << " ];\n " ;
113
+ }
114
+
115
+ template <typename iterator_type>
116
+ void specify_all_nodes (iterator_type const & node)
117
+ {
118
+ specify_node (*node);
119
+ if (node.left () != tree_.end ())
120
+ specify_all_nodes (node.left ());
121
+ if (node.right () != tree_.end ())
122
+ specify_all_nodes (node.right ());
123
+ }
124
+
125
+ void specify_edge (std::string const & from, std::string const & to)
126
+ {
127
+ stream_ << settings_.indent << from << (settings_.digraph ? " -> " : " -- " ) << to;
128
+ if (!settings_.edge_attributes .empty ())
129
+ {
130
+ stream_ << " [" ;
131
+ for (auto iter = settings_.edge_attributes .begin (); iter != settings_.edge_attributes .end (); ++iter)
132
+ {
133
+ stream_ << *iter;
134
+ if (iter + 1 != settings_.edge_attributes .end ())
135
+ stream_ << " , " ;
136
+ }
137
+ stream_ << " ]" ;
138
+ }
139
+ stream_ << " ;\n " ;
140
+ }
141
+
142
+ template <typename iterator_type>
143
+ void specify_all_edges (iterator_type const & node)
144
+ {
145
+ auto previous_id = node_id_;
146
+ if (node.left () != tree_.end ())
147
+ {
148
+ increment_node_id ();
149
+ specify_edge (previous_id, node_id_);
150
+ specify_all_edges (node.left ());
151
+ }
152
+ if (node.right () != tree_.end ())
153
+ {
154
+ increment_node_id ();
155
+ specify_edge (previous_id, node_id_);
156
+ specify_all_edges (node.right ());
157
+ }
158
+ }
159
+
160
+ void close ()
161
+ {
162
+ stream_ << " }" ;
163
+ }
164
+
165
+ void reset_node_id ()
166
+ {
167
+ node_id_ = " a" ;
168
+ }
169
+
170
+ private:
171
+ void increment_node_id ()
172
+ {
173
+ const auto character = node_id_.begin ();
174
+ for (auto iter = character; iter != node_id_.end (); ++iter)
175
+ {
176
+ if (*iter == ' z' )
177
+ {
178
+ *iter = ' a' ;
179
+ if (iter + 1 == node_id_.end ())
180
+ {
181
+ node_id_ += ' a' ;
182
+ break ;
183
+ }
184
+ }
185
+ else
186
+ {
187
+ ++*iter;
188
+ break ;
189
+ }
190
+ }
191
+ }
192
+
193
+ private:
194
+ std::ostream& stream_;
195
+ TreeT const & tree_;
196
+ dot_graph_draw_settings settings_;
197
+ std::string node_id_;
198
+ char left_brace_;
199
+ char right_brace_;
200
+ };
201
+ }
202
+
203
+ template <typename TreeT>
204
+ void draw_dot_graph (std::ostream& stream, TreeT const & tree, dot_graph_draw_settings const & settings = {})
205
+ {
206
+ detail::graph_painter painter{stream, tree, settings};
207
+ painter.make_header ();
208
+ if (tree.empty ())
209
+ {
210
+ painter.close ();
211
+ return ;
212
+ }
213
+ painter.specify_all_nodes (tree.root ());
214
+ painter.reset_node_id ();
215
+ painter.specify_all_edges (tree.root ());
216
+ painter.close ();
217
+ }
218
+ }
0 commit comments