Graphviz 16.1.1~dev.20260926.2046
Loading...
Searching...
No Matches
dotinit.c
Go to the documentation of this file.
1/*************************************************************************
2 * Copyright (c) 2011 AT&T Intellectual Property
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v2.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
7 *
8 * Contributors: Details at https://graphviz.org
9 *************************************************************************/
10
11#include "config.h"
12
13#include <assert.h>
14#include <limits.h>
15#include <time.h>
16#include <dotgen/dot.h>
17#include <pack/pack.h>
18#include <dotgen/aspect.h>
19#include <stdbool.h>
20#include <stdint.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <util/alloc.h>
24#include <util/debug.h>
25#include <util/itos.h>
26#include <util/streq.h>
27
28static void
30{
31 graph_t* subg;
32
33 if ((g != agroot(g)))
34 agbindrec(g, "Agraphinfo_t", sizeof(Agraphinfo_t), true);
35 if (g == droot)
36 GD_dotroot(agroot(g)) = droot;
37
38 for (subg = agfstsubg(g); subg; subg = agnxtsubg(subg)) {
39 dot_init_subg(subg, droot);
40 }
41}
42
43
44static void
46{
47 agbindrec(n, "Agnodeinfo_t", sizeof(Agnodeinfo_t), true); //graph custom data
50 alloc_elist(4, ND_in(n));
51 alloc_elist(4, ND_out(n));
54 alloc_elist(2, ND_other(n));
55 ND_UF_size(n) = 1;
56}
57
58static void
60{
61 char *tailgroup, *headgroup;
62 agbindrec(e, "Agedgeinfo_t", sizeof(Agedgeinfo_t), true); //graph custom data
64
65 ED_weight(e) = late_int(e, E_weight, 1, 0);
66 tailgroup = late_string(agtail(e), N_group, "");
67 headgroup = late_string(aghead(e), N_group, "");
68 ED_count(e) = ED_xpenalty(e) = 1;
69 if (tailgroup[0] && (tailgroup == headgroup)) {
71 ED_weight(e) *= 100;
72 }
73 if (nonconstraint_edge(e)) {
74 ED_xpenalty(e) = 0;
75 ED_weight(e) = 0;
76 }
77
78 {
79 int showboxes = late_int(e, E_showboxes, 0, 0);
80 if (showboxes > UCHAR_MAX) {
81 showboxes = UCHAR_MAX;
82 }
83 ED_showboxes(e) = (unsigned char)showboxes;
84 }
85 ED_minlen(e) = late_int(e, E_minlen, 1, 0);
86}
87
88void
90{
91 node_t *n;
92 edge_t *e;
93
94 for (n = agfstnode(g); n; n = agnxtnode(g, n))
96 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
97 for (e = agfstout(g, n); e; e = agnxtout(g, e))
99 }
100}
101
102static void
104{
105 free_list(ND_in(n));
106 free_list(ND_out(n));
112 if (ND_shape(n))
113 ND_shape(n)->fns->freefn(n);
114 agdelrec(n, "Agnodeinfo_t");
115}
116
118{
119 edge_t *e;
120
121 for (size_t i = ND_in(n).size - 1; i != SIZE_MAX; i--) {
122 e = ND_in(n).list[i];
124 free(e->base.data);
125 free(e);
126 }
127 for (size_t i = ND_out(n).size - 1; i != SIZE_MAX; i--) {
128 e = ND_out(n).list[i];
130 free(e->base.data);
131 free(e);
132 }
133}
134
136{
137 node_t *next_vn;
138
139 while (vn) {
140 next_vn = ND_next(vn);
142 if (ND_node_type(vn) == VIRTUAL) {
143 free_list(ND_out(vn));
144 free_list(ND_in(vn));
145 free(vn->base.data);
146 free(vn);
147 }
148 vn = next_vn;
149 }
150}
151
152static void
154{
155 int i;
156 graph_t *subg;
157 for (subg = agfstsubg(g); subg; subg = agnxtsubg(subg)) {
158 dot_cleanup_graph(subg);
159 }
160 if (! agbindrec(g, "Agraphinfo_t", 0, true)) return;
161 free(GD_drawing(g));
162 GD_drawing(g) = NULL;
163 free (GD_clust(g));
164 free (GD_rankleader(g));
165
166 free_list(GD_comp(g));
167 if (GD_rank(g)) {
168 for (i = GD_minrank(g); i <= GD_maxrank(g); i++)
169 free(GD_rank(g)[i].av);
170 if (GD_minrank(g) == -1)
171 free(GD_rank(g)-1);
172 else
173 free(GD_rank(g));
174 }
175 if (g != agroot(g)) {
176 free_label (GD_label(g));
177 }
178}
179
180/* delete the layout (but retain the underlying graph) */
182{
183 node_t *n;
184 edge_t *e;
185
187 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
188 for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
190 }
192 }
194}
195
196static void
198{
199 Agnode_t* v = NULL;
200 int j, rk = ND_rank(n);
201
202 for (j = 0; j < GD_rank(g)[rk].n; j++) {
203 v = GD_rank(g)[rk].v[j];
204 if (v == n) {
205 for (j++; j < GD_rank(g)[rk].n; j++) {
206 GD_rank(g)[rk].v[j-1] = GD_rank(g)[rk].v[j];
207 }
208 GD_rank(g)[rk].n--;
209 break;
210 }
211 }
212 assert (v == n); /* if found */
213}
214
215/* removeFill:
216 * This removes all of the fill nodes added in mincross.
217 * It appears to be sufficient to remove them only from the
218 * rank array and fast node list of the root graph.
219 */
220static void
222{
223 Agnode_t* n;
224 Agnode_t* nxt;
225 Agraph_t* sg = agsubg (g, "_new_rank", 0);
226
227 if (!sg) return;
228 for (n = agfstnode(sg); n; n = nxt) {
229 nxt = agnxtnode(sg, n);
230 delete_fast_node (g, n);
231 remove_from_rank (g, n);
233 agdelnode(g, n);
234 }
235 agdelsubg (g, sg);
236
237}
238
239#define agnodeattr(g,n,v) agattr_text(g,AGNODE,n,v)
240
241static void
242attach_phase_attrs (Agraph_t * g, int maxphase)
243{
244 Agsym_t* rk = agnodeattr(g,"rank","");
245 Agsym_t* order = agnodeattr(g,"order","");
246 Agnode_t* n;
247
248 for (n = agfstnode(g); n; n = agnxtnode(g,n)) {
249 if (maxphase >= 1) {
250 agxset(n, rk, ITOS(ND_rank(n)));
251 }
252 if (maxphase >= 2) {
253 agxset(n, order, ITOS(ND_order(n)));
254 }
255 }
256}
257
259static int dotLayout(Agraph_t *g) {
260 int maxphase = late_int(g, agfindgraphattr(g,"phase"), -1, 1);
261
263 setAspect(g);
264
265 dot_init_subg(g,g);
267
268 GV_INFO("Starting phase 1 [dot_rank]");
269 dot_rank(g);
270 if (maxphase == 1) {
271 attach_phase_attrs (g, 1);
272 return 0;
273 }
274 GV_INFO("Starting phase 2 [dot_mincross]");
275 const int rc = dot_mincross(g);
276 if (rc != 0) {
277 return rc;
278 }
279 if (maxphase == 2) {
280 attach_phase_attrs (g, 2);
281 return 0;
282 }
283 GV_INFO("Starting phase 3 [dot_position]");
284 {
285 const int r = dot_position(g);
286 if (r != 0) {
287 return r;
288 }
289 }
290 if (maxphase == 3) {
291 attach_phase_attrs (g, 2); /* positions will be attached on output */
292 return 0;
293 }
294 if (GD_flags(g) & NEW_RANK)
295 removeFill (g);
296 dot_sameports(g);
297 const int r = dot_splines(g);
298 if (r != 0) {
299 return r;
300 }
301 if (mapbool(agget(g, "compound")))
303 return 0;
304}
305
306static void
308{
309 agbindrec(sg, "Agraphinfo_t", sizeof(Agraphinfo_t), true);
310 GD_drawing(sg) = gv_alloc(sizeof(layout_t));
311 GD_drawing(sg)->quantum = GD_drawing(g)->quantum;
312 GD_drawing(sg)->dpi = GD_drawing(g)->dpi;
313 GD_gvc(sg) = GD_gvc (g);
314 GD_charset(sg) = GD_charset (g);
315 GD_rankdir2(sg) = GD_rankdir2 (g);
316 GD_nodesep(sg) = GD_nodesep(g);
317 GD_ranksep(sg) = GD_ranksep(g);
318 GD_fontnames(sg) = GD_fontnames(g);
319}
320
321/* the packing library assumes all units are in inches stored in ND_pos, so we
322 * have to copy the position info there.
323 */
324static void
326{
327 node_t* np;
328
329 for (np = agfstnode(g); np; np = agnxtnode(g, np)) {
330 ND_pos(np) = gv_calloc(2, sizeof(double));
331 ND_pos(np)[0] = PS2INCH(ND_coord(np).x);
332 ND_pos(np)[1] = PS2INCH(ND_coord(np).y);
333 }
334}
335
336/* Store new position info from pack library call, stored in ND_pos in inches,
337 * back to ND_coord in points.
338 */
339static void
341{
342 for (node_t *np = agfstnode(g); np; np = agnxtnode(g, np)) {
343 ND_coord(np).x = INCH2PS(ND_pos(np)[0]);
344 ND_coord(np).y = INCH2PS(ND_pos(np)[1]);
345 free(ND_pos(np));
346 ND_pos(np) = NULL;
347 }
348}
349
350static void
352{
353 int nclust, j;
354 Agraph_t* cg;
355
356 agbindrec(cl, "Agraphinfo_t", sizeof(Agraphinfo_t), true);
357 GD_bb(cl) = GD_bb(scl);
358 GD_label_pos(cl) = GD_label_pos(scl);
359 memcpy(GD_border(cl), GD_border(scl), 4*sizeof(pointf));
360 nclust = GD_n_cluster(cl) = GD_n_cluster(scl);
361 GD_clust(cl) = gv_calloc(nclust + 1, sizeof(Agraph_t*));
362 for (j = 1; j <= nclust; j++) {
363 cg = mapClust(GD_clust(scl)[j]);
364 GD_clust(cl)[j] = cg;
365 copyCluster (GD_clust(scl)[j], cg);
366 }
367 /* transfer cluster label to original cluster */
368 GD_label(cl) = GD_label(scl);
369 GD_label(scl) = NULL;
370}
371
372/* Copy cluster tree and info from components to main graph.
373 * Note that the original clusters have no Agraphinfo_t at this time.
374 */
375static void copyClusterInfo(size_t ncc, Agraph_t **ccs, Agraph_t *root) {
376 int j, nclust = 0;
377 Agraph_t* sg;
378 Agraph_t* cg;
379
380 for (size_t i = 0; i < ncc; i++)
381 nclust += GD_n_cluster(ccs[i]);
382
383 GD_n_cluster(root) = nclust;
384 GD_clust(root) = gv_calloc(nclust + 1, sizeof(Agraph_t*));
385 nclust = 1;
386 for (size_t i = 0; i < ncc; i++) {
387 sg = ccs[i];
388 for (j = 1; j <= GD_n_cluster(sg); j++) {
389 cg = mapClust(GD_clust(sg)[j]);
390 GD_clust(root)[nclust++] = cg;
391 copyCluster (GD_clust(sg)[j], cg);
392 }
393 }
394}
395
396/* Assume g has nodes.
397 *
398 * @return 0 on success
399 */
400static int doDot(Agraph_t *g) {
401 Agraph_t **ccs;
402 Agraph_t *sg;
403 pack_info pinfo;
404 int Pack = getPack(g, -1, CL_OFFSET);
405 pack_mode mode = getPackModeInfo (g, l_undef, &pinfo);
406 getPackInfo(g, l_node, CL_OFFSET, &pinfo);
407
408 if (mode == l_undef && Pack < 0) {
409 /* No pack information; use old dot with components
410 * handled during layout
411 */
412 const int rc = dotLayout(g);
413 if (rc != 0) {
414 return rc;
415 }
416 } else {
417 /* fill in default values */
418 if (mode == l_undef)
419 pinfo.mode = l_graph;
420 else if (Pack < 0)
421 Pack = CL_OFFSET;
422 assert(Pack >= 0);
423 pinfo.margin = (unsigned)Pack;
424 pinfo.fixed = NULL;
425
426 /* components using clusters */
427 size_t ncc;
428 ccs = cccomps(g, &ncc, 0);
429 if (ncc == 1) {
430 const int rc = dotLayout(g);
431 if (rc != 0) {
432 free(ccs);
433 return rc;
434 }
435 } else if (GD_drawing(g)->ratio_kind == R_NONE) {
436 pinfo.doSplines = true;
437
438 for (size_t i = 0; i < ncc; i++) {
439 sg = ccs[i];
440 initSubg (sg, g);
441 const int rc = dotLayout (sg);
442 if (rc != 0) {
443 free(ccs);
444 return rc;
445 }
446 }
447 attachPos (g);
448 packSubgraphs(ncc, ccs, g, &pinfo);
449 resetCoord (g);
450 copyClusterInfo (ncc, ccs, g);
451 } else {
452 /* Not sure what semantics should be for non-trivial ratio
453 * attribute with multiple components.
454 * One possibility is to layout nodes, pack, then apply the ratio
455 * adjustment. We would then have to re-adjust all positions.
456 */
457 const int rc = dotLayout(g);
458 if (rc != 0) {
459 free(ccs);
460 return rc;
461 }
462 }
463
464 for (size_t i = 0; i < ncc; i++) {
465 dot_cleanup_graph(ccs[i]);
466 agdelete(g, ccs[i]);
467 }
468 free(ccs);
469 }
470 return 0;
471}
472
474{
475 if (agnnodes(g)) {
476 if (doDot(g) != 0) { // error?
477 return;
478 }
479 }
481}
482
484{
485 return GD_dotroot(agroot(p));
486}
487
Memory allocation wrappers that exit on failure.
static void * gv_calloc(size_t nmemb, size_t size)
Definition alloc.h:26
static void * gv_alloc(size_t size)
Definition alloc.h:47
void setAspect(Agraph_t *g)
Definition aspect.c:27
bool nonconstraint_edge(edge_t *e)
Definition class1.c:22
bool mapbool(const char *p)
Definition utils.c:341
void setEdgeType(graph_t *g, int defaultValue)
Definition utils.c:1412
char * late_string(void *obj, attrsym_t *attr, char *defaultValue)
Definition utils.c:85
int late_int(void *obj, attrsym_t *attr, int defaultValue, int minimum)
Definition utils.c:40
void common_init_node(node_t *n)
Definition utils.c:416
void common_init_edge(edge_t *e)
Definition utils.c:498
void gv_nodesize(node_t *n, bool flip)
Definition utils.c:1525
void dot_compoundEdges(graph_t *g)
Definition compound.c:434
#define EDGETYPE_SPLINE
Definition const.h:239
#define CL_OFFSET
Definition const.h:142
#define NEW_RANK
Definition const.h:243
#define VIRTUAL
Definition const.h:25
#define CL_CROSS
Definition const.h:144
mode
Definition cvtgxl.c:33
helpers for verbose/debug printing
#define GV_INFO(...)
Definition debug.h:15
static void dot_init_subg(graph_t *g, graph_t *droot)
Definition dotinit.c:29
static int dotLayout(Agraph_t *g)
Definition dotinit.c:259
static void dot_cleanup_node(node_t *n)
Definition dotinit.c:103
Agraph_t * dot_root(void *p)
Definition dotinit.c:483
static void free_virtual_edge_list(node_t *n)
Definition dotinit.c:117
static void attach_phase_attrs(Agraph_t *g, int maxphase)
Definition dotinit.c:242
static void removeFill(Agraph_t *g)
Definition dotinit.c:221
static void dot_init_node(node_t *n)
Definition dotinit.c:45
static void copyClusterInfo(size_t ncc, Agraph_t **ccs, Agraph_t *root)
Definition dotinit.c:375
void dot_layout(Agraph_t *g)
Definition dotinit.c:473
void dot_init_node_edge(graph_t *g)
Definition dotinit.c:89
static void dot_cleanup_graph(graph_t *g)
Definition dotinit.c:153
static void resetCoord(Agraph_t *g)
Definition dotinit.c:340
static void free_virtual_node_list(node_t *vn)
Definition dotinit.c:135
void dot_cleanup(graph_t *g)
Definition dotinit.c:181
static void initSubg(Agraph_t *sg, Agraph_t *g)
Definition dotinit.c:307
static void copyCluster(Agraph_t *scl, Agraph_t *cl)
Definition dotinit.c:351
static int doDot(Agraph_t *g)
Definition dotinit.c:400
#define agnodeattr(g, n, v)
Definition dotinit.c:239
static void attachPos(Agraph_t *g)
Definition dotinit.c:325
static void dot_init_edge(edge_t *e)
Definition dotinit.c:59
static void remove_from_rank(Agraph_t *g, Agnode_t *n)
Definition dotinit.c:197
void delete_fast_node(Agraph_t *, Agnode_t *)
Definition fastgr.c:189
int dot_mincross(Agraph_t *)
Definition mincross.c:332
int dot_splines(Agraph_t *)
Definition dotsplines.c:486
void dot_sameports(Agraph_t *)
void dot_rank(Agraph_t *)
Definition rank.c:528
void delete_fast_edge(Agedge_t *)
Definition fastgr.c:109
WUR int dot_position(Agraph_t *)
Definition position.c:121
#define PS2INCH(a_points)
Definition geom.h:64
#define INCH2PS(a_inches)
Definition geom.h:63
Agsym_t * N_group
Definition globals.h:81
Agsym_t * E_weight
Definition globals.h:83
Agsym_t * E_minlen
Definition globals.h:83
Agsym_t * E_showboxes
Definition globals.h:85
void free(void *)
#define SIZE_MAX
Definition gmlscan.c:347
node NULL
Definition grammar.y:181
int agnnodes(Agraph_t *g)
Definition graph.c:163
int agxset(void *obj, Agsym_t *sym, const char *value)
Definition attr.c:521
char * agget(void *obj, char *name)
Definition attr.c:447
#define ED_minlen(e)
Definition types.h:592
#define ED_showboxes(e)
Definition types.h:594
#define ED_xpenalty(e)
Definition types.h:601
Agedge_t * agfstout(Agraph_t *g, Agnode_t *n)
Definition edge.c:28
#define ED_count(e)
Definition types.h:580
#define agtail(e)
Definition cgraph.h:982
#define ED_weight(e)
Definition types.h:603
#define aghead(e)
Definition cgraph.h:983
Agedge_t * agnxtout(Agraph_t *g, Agedge_t *e)
Definition edge.c:43
#define GD_minrank(g)
Definition types.h:384
#define agfindgraphattr(g, a)
Definition types.h:613
#define GD_rankdir2(g)
Definition types.h:376
#define GD_maxrank(g)
Definition types.h:382
#define GD_fontnames(g)
Definition types.h:402
#define GD_drawing(g)
Definition types.h:353
#define GD_border(g)
Definition types.h:359
#define GD_clust(g)
Definition types.h:360
#define GD_flags(g)
Definition types.h:365
#define GD_rank(g)
Definition types.h:395
#define GD_bb(g)
Definition types.h:354
#define GD_nlist(g)
Definition types.h:393
#define GD_label_pos(g)
Definition types.h:400
#define GD_n_cluster(g)
Definition types.h:389
#define GD_dotroot(g)
Definition types.h:361
#define GD_comp(g)
Definition types.h:362
#define GD_label(g)
Definition types.h:374
#define GD_nodesep(g)
Definition types.h:394
#define GD_charset(g)
Definition types.h:367
#define GD_gvc(g)
Definition types.h:355
#define GD_flip(g)
Definition types.h:378
#define GD_rankleader(g)
Definition types.h:396
#define GD_ranksep(g)
Definition types.h:397
#define ND_rank(n)
Definition types.h:523
Agnode_t * agnxtnode(Agraph_t *g, Agnode_t *n)
Definition node.c:50
Agnode_t * agfstnode(Agraph_t *g)
Definition node.c:43
#define ND_next(n)
Definition types.h:510
#define ND_other(n)
Definition types.h:514
#define ND_label(n)
Definition types.h:502
#define ND_flat_out(n)
Definition types.h:493
#define ND_node_type(n)
Definition types.h:511
int agdelnode(Agraph_t *g, Agnode_t *arg_n)
removes a node from a graph or subgraph.
Definition node.c:192
#define ND_order(n)
Definition types.h:513
#define ND_xlabel(n)
Definition types.h:503
#define ND_UF_size(n)
Definition types.h:487
#define ND_pos(n)
Definition types.h:520
#define ND_flat_in(n)
Definition types.h:492
#define ND_coord(n)
Definition types.h:490
#define ND_in(n)
Definition types.h:501
#define ND_shape(n)
Definition types.h:528
#define ND_out(n)
Definition types.h:515
Agraph_t * agraphof(void *obj)
Definition obj.c:187
int agdelete(Agraph_t *g, void *obj)
deletes object. Equivalent to agclose, agdelnode, and agdeledge for obj being a graph,...
Definition obj.c:22
Agraph_t * agroot(void *obj)
Definition obj.c:170
void * agbindrec(void *obj, const char *name, unsigned int recsize, int move_to_front)
attaches a new record of the given size to the object
Definition rec.c:91
int agdelrec(void *obj, const char *name)
deletes a named record from one object
Definition rec.c:139
Agraph_t * agfstsubg(Agraph_t *g)
Definition subg.c:72
Agraph_t * agnxtsubg(Agraph_t *subg)
Definition subg.c:77
Agraph_t * agsubg(Agraph_t *g, char *name, int cflag)
Definition subg.c:52
int agdelsubg(Agraph_t *g, Agraph_t *sub)
Definition subg.c:93
#define ITOS(i)
Definition itos.h:43
void free_label(textlabel_t *p)
Definition labels.c:204
Agraph_t ** cccomps(Agraph_t *g, size_t *ncc, char *pfx)
Definition ccomps.c:437
Agraph_t * mapClust(Agraph_t *cl)
Definition ccomps.c:364
static int Pack
Definition neatoinit.c:55
pack_mode getPackModeInfo(Agraph_t *g, pack_mode dflt, pack_info *pinfo)
Definition pack.c:1257
int packSubgraphs(size_t ng, Agraph_t **gs, Agraph_t *root, pack_info *info)
Definition pack.c:1108
int getPack(Agraph_t *g, int not_def, int dflt)
Definition pack.c:1270
pack_mode getPackInfo(Agraph_t *g, pack_mode dflt, int dfltMargin, pack_info *pinfo)
Definition pack.c:1285
support for connected components
pack_mode
Definition pack.h:55
@ l_undef
Definition pack.h:55
@ l_graph
Definition pack.h:55
@ l_node
Definition pack.h:55
void dotneato_postprocess(Agraph_t *g)
Definition postproc.c:691
void gv_cleanup_edge(Agedge_t *e)
Definition utils.c:1502
static double cg(SparseMatrix A, const double *precond, size_t n, int dim, double *x0, double *rhs, double tol, double maxit)
Agobj_t base
Definition cgraph.h:269
Agobj_t base
Definition cgraph.h:260
Agrec_t * data
stores programmer-defined data, access with AGDATA
Definition cgraph.h:212
graph or subgraph
Definition cgraph.h:424
string attribute descriptor symbol in Agattr_s.dict
Definition cgraph.h:641
pack_mode mode
Definition pack.h:72
bool doSplines
use splines in constructing graph shape
Definition pack.h:71
bool * fixed
Definition pack.h:73
unsigned int margin
Definition pack.h:70
#define free_list(L)
Definition types.h:272
#define alloc_elist(n, L)
Definition types.h:267
@ R_NONE
Definition types.h:215