Blender  V2.93
dot_export.cc
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
17 #include <iomanip>
18 
19 #include "BLI_dot_export.hh"
20 
21 namespace blender::dot {
22 
23 /* Graph Building
24  ************************************************/
25 
27 {
28  Node *node = new Node(*this);
29  nodes_.append(std::unique_ptr<Node>(node));
30  top_level_nodes_.add_new(node);
31  node->attributes.set("label", label);
32  return *node;
33 }
34 
36 {
37  Cluster *cluster = new Cluster(*this);
38  clusters_.append(std::unique_ptr<Cluster>(cluster));
39  top_level_clusters_.add_new(cluster);
40  cluster->attributes.set("label", label);
41  return *cluster;
42 }
43 
45 {
46  UndirectedEdge *edge = new UndirectedEdge(a, b);
47  edges_.append(std::unique_ptr<UndirectedEdge>(edge));
48  return *edge;
49 }
50 
52 {
53  DirectedEdge *edge = new DirectedEdge(from, to);
54  edges_.append(std::unique_ptr<DirectedEdge>(edge));
55  return *edge;
56 }
57 
59 {
60  if (parent_ == new_parent) {
61  return;
62  }
63  if (parent_ == nullptr) {
64  graph_.top_level_clusters_.remove(this);
65  new_parent->children_.add_new(this);
66  }
67  else if (new_parent == nullptr) {
68  parent_->children_.remove(this);
69  graph_.top_level_clusters_.add_new(this);
70  }
71  else {
72  parent_->children_.remove(this);
73  new_parent->children_.add_new(this);
74  }
75  parent_ = new_parent;
76 }
77 
79 {
80  if (cluster_ == cluster) {
81  return;
82  }
83  if (cluster_ == nullptr) {
84  graph_.top_level_nodes_.remove(this);
85  cluster->nodes_.add_new(this);
86  }
87  else if (cluster == nullptr) {
88  cluster_->nodes_.remove(this);
89  graph_.top_level_nodes_.add_new(this);
90  }
91  else {
92  cluster_->nodes_.remove(this);
93  cluster->nodes_.add_new(this);
94  }
95  cluster_ = cluster;
96 }
97 
98 /* Utility methods
99  **********************************************/
100 
102 {
103  for (Cluster *cluster : top_level_clusters_) {
104  cluster->set_random_cluster_bgcolors();
105  }
106 }
107 
109 {
110  float hue = rand() / (float)RAND_MAX;
111  float staturation = 0.3f;
112  float value = 0.8f;
113  this->attributes.set("bgcolor", color_attr_from_hsv(hue, staturation, value));
114 
115  for (Cluster *cluster : children_) {
116  cluster->set_random_cluster_bgcolors();
117  }
118 }
119 
121 {
122  Cluster *current = node.parent_cluster();
123  while (current != nullptr) {
124  if (current == this) {
125  return true;
126  }
127  current = current->parent_;
128  }
129  return false;
130 }
131 
132 /* Dot Generation
133  **********************************************/
134 
135 std::string DirectedGraph::to_dot_string() const
136 {
137  std::stringstream ss;
138  ss << "digraph {\n";
140  ss << "\n";
141 
142  for (const std::unique_ptr<DirectedEdge> &edge : edges_) {
143  edge->export__as_edge_statement(ss);
144  ss << "\n";
145  }
146 
147  ss << "}\n";
148  return ss.str();
149 }
150 
152 {
153  std::stringstream ss;
154  ss << "graph {\n";
156  ss << "\n";
157 
158  for (const std::unique_ptr<UndirectedEdge> &edge : edges_) {
159  edge->export__as_edge_statement(ss);
160  ss << "\n";
161  }
162 
163  ss << "}\n";
164  return ss.str();
165 }
166 
167 void Graph::export__declare_nodes_and_clusters(std::stringstream &ss) const
168 {
169  ss << "graph ";
171  ss << "\n\n";
172 
173  for (Node *node : top_level_nodes_) {
174  node->export__as_declaration(ss);
175  }
176 
177  for (Cluster *cluster : top_level_clusters_) {
178  cluster->export__declare_nodes_and_clusters(ss);
179  }
180 }
181 
182 void Cluster::export__declare_nodes_and_clusters(std::stringstream &ss) const
183 {
184  ss << "subgraph " << this->name() << " {\n";
185 
186  ss << "graph ";
188  ss << "\n\n";
189 
190  for (Node *node : nodes_) {
191  node->export__as_declaration(ss);
192  }
193 
194  for (Cluster *cluster : children_) {
195  cluster->export__declare_nodes_and_clusters(ss);
196  }
197 
198  ss << "}\n";
199 }
200 
201 void DirectedEdge::export__as_edge_statement(std::stringstream &ss) const
202 {
203  a_.to_dot_string(ss);
204  ss << " -> ";
205  b_.to_dot_string(ss);
206  ss << " ";
208 }
209 
210 void UndirectedEdge::export__as_edge_statement(std::stringstream &ss) const
211 {
212  a_.to_dot_string(ss);
213  ss << " -- ";
214  b_.to_dot_string(ss);
215  ss << " ";
217 }
218 
219 void Attributes::export__as_bracket_list(std::stringstream &ss) const
220 {
221  ss << "[";
222  attributes_.foreach_item([&](StringRef key, StringRef value) {
223  if (StringRef(value).startswith("<")) {
224  /* Don't draw the quotes, this is an HTML-like value. */
225  ss << key << "=" << value << ", ";
226  }
227  else {
228  ss << key << "=\"";
229  for (char c : value) {
230  if (c == '\"') {
231  /* Escape double quotes. */
232  ss << '\\';
233  }
234  ss << c;
235  }
236  ss << "\", ";
237  }
238  });
239  ss << "]";
240 }
241 
242 void Node::export__as_id(std::stringstream &ss) const
243 {
244  ss << '"' << (uintptr_t)this << '"';
245 }
246 
247 void Node::export__as_declaration(std::stringstream &ss) const
248 {
249  this->export__as_id(ss);
250  ss << " ";
252  ss << "\n";
253 }
254 
255 void NodePort::to_dot_string(std::stringstream &ss) const
256 {
257  node_->export__as_id(ss);
258  if (port_name_.has_value()) {
259  ss << ":" << *port_name_;
260  }
261 }
262 
263 std::string color_attr_from_hsv(float h, float s, float v)
264 {
265  std::stringstream ss;
266  ss << std::setprecision(4) << h << ' ' << s << ' ' << v;
267  return ss.str();
268 }
269 
271  StringRef name,
272  Span<std::string> input_names,
273  Span<std::string> output_names)
274  : node_(&node)
275 {
276  std::stringstream ss;
277 
278  ss << R"(<<table border="0" cellspacing="3">)";
279 
280  /* Header */
281  ss << R"(<tr><td colspan="3" align="center"><b>)";
282  ss << ((name.size() == 0) ? "No Name" : name);
283  ss << "</b></td></tr>";
284 
285  /* Sockets */
286  int socket_max_amount = std::max(input_names.size(), output_names.size());
287  for (int i = 0; i < socket_max_amount; i++) {
288  ss << "<tr>";
289  if (i < input_names.size()) {
290  StringRef name = input_names[i];
291  if (name.size() == 0) {
292  name = "No Name";
293  }
294  ss << R"(<td align="left" port="in)" << i << "\">";
295  ss << name;
296  ss << "</td>";
297  }
298  else {
299  ss << "<td></td>";
300  }
301  ss << "<td></td>";
302  if (i < output_names.size()) {
303  StringRef name = output_names[i];
304  if (name.size() == 0) {
305  name = "No Name";
306  }
307  ss << R"(<td align="right" port="out)" << i << "\">";
308  ss << name;
309  ss << "</td>";
310  }
311  else {
312  ss << "<td></td>";
313  }
314  ss << "</tr>";
315  }
316 
317  ss << "</table>>";
318 
319  node_->attributes.set("label", ss.str());
320  node_->set_shape(Attr_shape::Rectangle);
321 }
322 
323 } // namespace blender::dot
typedef float(TangentPoint)[2]
ATTR_WARN_UNUSED_RESULT const BMVert * v
void foreach_item(const FuncT &func) const
Definition: BLI_map.hh:611
constexpr int64_t size() const
Definition: BLI_span.hh:254
constexpr int64_t size() const
void export__as_bracket_list(std::stringstream &ss) const
Definition: dot_export.cc:219
void set(StringRef key, StringRef value)
void set_parent_cluster(Cluster *new_parent)
Definition: dot_export.cc:58
bool contains(Node &node) const
Definition: dot_export.cc:120
std::string name() const
void export__declare_nodes_and_clusters(std::stringstream &ss) const
Definition: dot_export.cc:182
void set_random_cluster_bgcolors()
Definition: dot_export.cc:108
void export__as_edge_statement(std::stringstream &ss) const
Definition: dot_export.cc:201
DirectedEdge & new_edge(NodePort from, NodePort to)
Definition: dot_export.cc:51
std::string to_dot_string() const
Definition: dot_export.cc:135
Cluster & new_cluster(StringRef label="")
Definition: dot_export.cc:35
void set_random_cluster_bgcolors()
Definition: dot_export.cc:101
Node & new_node(StringRef label)
Definition: dot_export.cc:26
void export__declare_nodes_and_clusters(std::stringstream &ss) const
Definition: dot_export.cc:167
void to_dot_string(std::stringstream &ss) const
Definition: dot_export.cc:255
NodeWithSocketsRef(Node &node, StringRef name, Span< std::string > input_names, Span< std::string > output_names)
Definition: dot_export.cc:270
void set_shape(Attr_shape shape)
void export__as_declaration(std::stringstream &ss) const
Definition: dot_export.cc:247
void export__as_id(std::stringstream &ss) const
Definition: dot_export.cc:242
void set_parent_cluster(Cluster *cluster)
Definition: dot_export.cc:78
void export__as_edge_statement(std::stringstream &ss) const
Definition: dot_export.cc:210
UndirectedEdge & new_edge(NodePort a, NodePort b)
Definition: dot_export.cc:44
std::string to_dot_string() const
Definition: dot_export.cc:151
OperationNode * node
StackEntry * from
const char * label
static unsigned c
Definition: RandGen.cpp:97
static unsigned a[3]
Definition: RandGen.cpp:92
std::string color_attr_from_hsv(float h, float s, float v)
Definition: dot_export.cc:263
_W64 unsigned int uintptr_t
Definition: stdint.h:122
float max