Blender  V3.3
dot_export.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include <iomanip>
4 
5 #include "BLI_dot_export.hh"
6 
7 namespace blender::dot {
8 
9 /* Graph Building
10  ************************************************/
11 
13 {
14  Node *node = new Node(*this);
15  nodes_.append(std::unique_ptr<Node>(node));
16  top_level_nodes_.add_new(node);
17  node->attributes.set("label", label);
18  return *node;
19 }
20 
22 {
23  Cluster *cluster = new Cluster(*this);
24  clusters_.append(std::unique_ptr<Cluster>(cluster));
25  top_level_clusters_.add_new(cluster);
26  cluster->attributes.set("label", label);
27  return *cluster;
28 }
29 
31 {
32  UndirectedEdge *edge = new UndirectedEdge(a, b);
33  edges_.append(std::unique_ptr<UndirectedEdge>(edge));
34  return *edge;
35 }
36 
38 {
39  DirectedEdge *edge = new DirectedEdge(from, to);
40  edges_.append(std::unique_ptr<DirectedEdge>(edge));
41  return *edge;
42 }
43 
45 {
46  if (parent_ == new_parent) {
47  return;
48  }
49  if (parent_ == nullptr) {
50  graph_.top_level_clusters_.remove(this);
51  new_parent->children_.add_new(this);
52  }
53  else if (new_parent == nullptr) {
54  parent_->children_.remove(this);
55  graph_.top_level_clusters_.add_new(this);
56  }
57  else {
58  parent_->children_.remove(this);
59  new_parent->children_.add_new(this);
60  }
61  parent_ = new_parent;
62 }
63 
65 {
66  if (cluster_ == cluster) {
67  return;
68  }
69  if (cluster_ == nullptr) {
70  graph_.top_level_nodes_.remove(this);
71  cluster->nodes_.add_new(this);
72  }
73  else if (cluster == nullptr) {
74  cluster_->nodes_.remove(this);
75  graph_.top_level_nodes_.add_new(this);
76  }
77  else {
78  cluster_->nodes_.remove(this);
79  cluster->nodes_.add_new(this);
80  }
81  cluster_ = cluster;
82 }
83 
84 /* Utility methods
85  **********************************************/
86 
88 {
89  for (Cluster *cluster : top_level_clusters_) {
90  cluster->set_random_cluster_bgcolors();
91  }
92 }
93 
95 {
96  float hue = rand() / (float)RAND_MAX;
97  float staturation = 0.3f;
98  float value = 0.8f;
99  this->attributes.set("bgcolor", color_attr_from_hsv(hue, staturation, value));
100 
101  for (Cluster *cluster : children_) {
102  cluster->set_random_cluster_bgcolors();
103  }
104 }
105 
107 {
108  Cluster *current = node.parent_cluster();
109  while (current != nullptr) {
110  if (current == this) {
111  return true;
112  }
113  current = current->parent_;
114  }
115  return false;
116 }
117 
118 /* Dot Generation
119  **********************************************/
120 
121 std::string DirectedGraph::to_dot_string() const
122 {
123  std::stringstream ss;
124  ss << "digraph {\n";
126  ss << "\n";
127 
128  for (const std::unique_ptr<DirectedEdge> &edge : edges_) {
129  edge->export__as_edge_statement(ss);
130  ss << "\n";
131  }
132 
133  ss << "}\n";
134  return ss.str();
135 }
136 
138 {
139  std::stringstream ss;
140  ss << "graph {\n";
142  ss << "\n";
143 
144  for (const std::unique_ptr<UndirectedEdge> &edge : edges_) {
145  edge->export__as_edge_statement(ss);
146  ss << "\n";
147  }
148 
149  ss << "}\n";
150  return ss.str();
151 }
152 
153 void Graph::export__declare_nodes_and_clusters(std::stringstream &ss) const
154 {
155  ss << "graph ";
157  ss << "\n\n";
158 
159  for (Node *node : top_level_nodes_) {
160  node->export__as_declaration(ss);
161  }
162 
163  for (Cluster *cluster : top_level_clusters_) {
164  cluster->export__declare_nodes_and_clusters(ss);
165  }
166 }
167 
168 void Cluster::export__declare_nodes_and_clusters(std::stringstream &ss) const
169 {
170  ss << "subgraph " << this->name() << " {\n";
171 
172  ss << "graph ";
174  ss << "\n\n";
175 
176  for (Node *node : nodes_) {
177  node->export__as_declaration(ss);
178  }
179 
180  for (Cluster *cluster : children_) {
181  cluster->export__declare_nodes_and_clusters(ss);
182  }
183 
184  ss << "}\n";
185 }
186 
187 void DirectedEdge::export__as_edge_statement(std::stringstream &ss) const
188 {
189  a_.to_dot_string(ss);
190  ss << " -> ";
191  b_.to_dot_string(ss);
192  ss << " ";
194 }
195 
196 void UndirectedEdge::export__as_edge_statement(std::stringstream &ss) const
197 {
198  a_.to_dot_string(ss);
199  ss << " -- ";
200  b_.to_dot_string(ss);
201  ss << " ";
203 }
204 
205 void Attributes::export__as_bracket_list(std::stringstream &ss) const
206 {
207  ss << "[";
208  attributes_.foreach_item([&](StringRef key, StringRef value) {
209  if (StringRef(value).startswith("<")) {
210  /* Don't draw the quotes, this is an HTML-like value. */
211  ss << key << "=" << value << ", ";
212  }
213  else {
214  ss << key << "=\"";
215  for (char c : value) {
216  if (c == '\"') {
217  /* Escape double quotes. */
218  ss << '\\';
219  }
220  ss << c;
221  }
222  ss << "\", ";
223  }
224  });
225  ss << "]";
226 }
227 
228 void Node::export__as_id(std::stringstream &ss) const
229 {
230  ss << '"' << (uintptr_t)this << '"';
231 }
232 
233 void Node::export__as_declaration(std::stringstream &ss) const
234 {
235  this->export__as_id(ss);
236  ss << " ";
238  ss << "\n";
239 }
240 
241 void NodePort::to_dot_string(std::stringstream &ss) const
242 {
243  node_->export__as_id(ss);
244  if (port_name_.has_value()) {
245  ss << ":" << *port_name_;
246  }
247 }
248 
249 std::string color_attr_from_hsv(float h, float s, float v)
250 {
251  std::stringstream ss;
252  ss << std::setprecision(4) << h << ' ' << s << ' ' << v;
253  return ss.str();
254 }
255 
257  StringRef name,
258  Span<std::string> input_names,
259  Span<std::string> output_names)
260  : node_(&node)
261 {
262  std::stringstream ss;
263 
264  ss << R"(<<table border="0" cellspacing="3">)";
265 
266  /* Header */
267  ss << R"(<tr><td colspan="3" align="center"><b>)";
268  ss << ((name.size() == 0) ? "No Name" : name);
269  ss << "</b></td></tr>";
270 
271  /* Sockets */
272  int socket_max_amount = std::max(input_names.size(), output_names.size());
273  for (int i = 0; i < socket_max_amount; i++) {
274  ss << "<tr>";
275  if (i < input_names.size()) {
276  StringRef name = input_names[i];
277  if (name.size() == 0) {
278  name = "No Name";
279  }
280  ss << R"(<td align="left" port="in)" << i << "\">";
281  ss << name;
282  ss << "</td>";
283  }
284  else {
285  ss << "<td></td>";
286  }
287  ss << "<td></td>";
288  if (i < output_names.size()) {
289  StringRef name = output_names[i];
290  if (name.size() == 0) {
291  name = "No Name";
292  }
293  ss << R"(<td align="right" port="out)" << i << "\">";
294  ss << name;
295  ss << "</td>";
296  }
297  else {
298  ss << "<td></td>";
299  }
300  ss << "</tr>";
301  }
302 
303  ss << "</table>>";
304 
305  node_->attributes.set("label", ss.str());
306  node_->set_shape(Attr_shape::Rectangle);
307 }
308 
309 } // namespace blender::dot
typedef float(TangentPoint)[2]
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Sky Generate a procedural sky texture Noise Generate fractal Perlin noise Wave Generate procedural bands or rings with noise Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a or normal between and object coordinate space Combine Create a color from its hue
ATTR_WARN_UNUSED_RESULT const BMVert * v
void foreach_item(const FuncT &func) const
Definition: BLI_map.hh:628
constexpr int64_t size() const
Definition: BLI_span.hh:240
constexpr int64_t size() const
void export__as_bracket_list(std::stringstream &ss) const
Definition: dot_export.cc:205
void set(StringRef key, StringRef value)
void set_parent_cluster(Cluster *new_parent)
Definition: dot_export.cc:44
bool contains(Node &node) const
Definition: dot_export.cc:106
std::string name() const
void export__declare_nodes_and_clusters(std::stringstream &ss) const
Definition: dot_export.cc:168
void set_random_cluster_bgcolors()
Definition: dot_export.cc:94
void export__as_edge_statement(std::stringstream &ss) const
Definition: dot_export.cc:187
DirectedEdge & new_edge(NodePort from, NodePort to)
Definition: dot_export.cc:37
std::string to_dot_string() const
Definition: dot_export.cc:121
Cluster & new_cluster(StringRef label="")
Definition: dot_export.cc:21
void set_random_cluster_bgcolors()
Definition: dot_export.cc:87
Node & new_node(StringRef label)
Definition: dot_export.cc:12
void export__declare_nodes_and_clusters(std::stringstream &ss) const
Definition: dot_export.cc:153
void to_dot_string(std::stringstream &ss) const
Definition: dot_export.cc:241
NodeWithSocketsRef(Node &node, StringRef name, Span< std::string > input_names, Span< std::string > output_names)
Definition: dot_export.cc:256
void set_shape(Attr_shape shape)
void export__as_declaration(std::stringstream &ss) const
Definition: dot_export.cc:233
void export__as_id(std::stringstream &ss) const
Definition: dot_export.cc:228
void set_parent_cluster(Cluster *cluster)
Definition: dot_export.cc:64
void export__as_edge_statement(std::stringstream &ss) const
Definition: dot_export.cc:196
UndirectedEdge & new_edge(NodePort a, NodePort b)
Definition: dot_export.cc:30
std::string to_dot_string() const
Definition: dot_export.cc:137
OperationNode * node
StackEntry * from
const char * label
static unsigned c
Definition: RandGen.cpp:83
static unsigned a[3]
Definition: RandGen.cpp:78
std::string color_attr_from_hsv(float h, float s, float v)
Definition: dot_export.cc:249
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
_W64 unsigned int uintptr_t
Definition: stdint.h:119
float max