Graphviz 14.1.1~dev.20251209.0353
Loading...
Searching...
No Matches
osageinit.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 v1.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors: Details at https://graphviz.org
9 *************************************************************************/
10
11
12/* FIX: handle cluster labels */
13/*
14 * Written by Emden R. Gansner
15 */
16
17#include <assert.h>
18#include <common/geomprocs.h>
19#include <common/render.h>
20#include <common/utils.h>
21#include <float.h>
22#include <limits.h>
23#include <osage/osage.h>
24#include <neatogen/neatoprocs.h>
25#include <pack/pack.h>
26#include <stdbool.h>
27#include <stddef.h>
28#include <util/alloc.h>
29#include <util/list.h>
30#include <util/startswith.h>
31
32#define DFLT_SZ 18
33#define PARENT(n) ((Agraph_t*)ND_alg(n))
34
35static void
36indent (int i)
37{
38 for (; i > 0; i--)
39 fputs (" ", stderr);
40}
41
42typedef LIST(Agraph_t *) clist_t;
43
44static void cluster_init_graph(graph_t * g)
45{
46 Agnode_t *n;
47 Agedge_t *e;
48
50 Ndim = GD_ndim(g)=2; /* The algorithm only makes sense in 2D */
51
52 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
54 }
55 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
56 for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
57 agbindrec(e, "Agedgeinfo_t", sizeof(Agedgeinfo_t), true); //edge custom data
59 }
60 }
61}
62
63/* layout:
64 */
65static void
66layout (Agraph_t* g, int depth)
67{
68 int nvs = 0; /* no. of nodes in subclusters */
69 pack_info pinfo;
70 Agsym_t* cattr = NULL;
71 Agsym_t* vattr = NULL;
72 Agraph_t* root = g->root;
73
74 if (Verbose > 1) {
75 indent (depth);
76 fprintf (stderr, "layout %s\n", agnameof(g));
77 }
78
79 /* Lay out subclusters */
80 for (int i = 1; i <= GD_n_cluster(g); i++) {
81 Agraph_t *const subg = GD_clust(g)[i];
82 layout (subg, depth+1);
83 nvs += agnnodes (subg);
84 }
85
86 const int nv = agnnodes(g);
87 const int total = nv - nvs + GD_n_cluster(g);
88
89 if (total == 0 && GD_label(g) == NULL) {
90 GD_bb(g) = (boxf){.UR = {.x = DFLT_SZ, .y = DFLT_SZ}};
91 return;
92 }
93
94 const pack_mode pmode = getPackInfo(g, l_array, DFLT_MARGIN, &pinfo);
95 if (pmode < l_graph) pinfo.mode = l_graph;
96
97 /* add user sort values if necessary */
98 if (pinfo.mode == l_array && (pinfo.flags & PK_USER_VALS)) {
99 cattr = agattr_text(root, AGRAPH, "sortv", 0);
100 vattr = agattr_text(root, AGNODE, "sortv", 0);
101 if (cattr || vattr)
102 pinfo.vals = gv_calloc(total+1, sizeof(packval_t));
103 else
104 agwarningf("Graph %s has array packing with user values but no \"sortv\" attributes are defined.",
105 agnameof(g));
106 }
107
108 LIST(boxf) gs = {0};
109 void **children = gv_calloc(total+1, sizeof(void*));
110 int j = 0;
111 for (int i = 1; i <= GD_n_cluster(g); i++) {
112 Agraph_t *const subg = GD_clust(g)[i];
113 LIST_APPEND(&gs, GD_bb(subg));
114 if (pinfo.vals && cattr) {
115 pinfo.vals[j] = (packval_t)late_int(subg, cattr, 0, 0);
116 }
117 children[j++] = subg;
118 }
119
120 if (nv-nvs > 0) {
121 for (Agnode_t *n = agfstnode(g); n; n = agnxtnode(g, n)) {
122 if (ND_alg(n)) continue;
123 ND_alg(n) = g;
124 const boxf bb = {.UR = {.x = ND_xsize(n), .y = ND_ysize(n)}};
125 LIST_APPEND(&gs, bb);
126 if (pinfo.vals && vattr) {
127 pinfo.vals[j] = (packval_t)late_int(n, vattr, 0, 0);
128 }
129 children[j++] = n;
130 }
131 }
132
133 /* pack rectangles */
134 pointf *const pts = putRects(LIST_SIZE(&gs),
135 LIST_IS_EMPTY(&gs) ? NULL : LIST_FRONT(&gs),
136 &pinfo);
137 free (pinfo.vals);
138
139 boxf rootbb = {.LL = {DBL_MAX, DBL_MAX}, .UR = {-DBL_MAX, -DBL_MAX}};
140
141 /* reposition children relative to GD_bb(g) */
142 for (j = 0; (size_t)j < LIST_SIZE(&gs); j++) {
143 const pointf p = pts[j];
144 boxf bb = LIST_GET(&gs, (size_t)j);
145 bb.LL = add_pointf(bb.LL, p);
146 bb.UR = add_pointf(bb.UR, p);
147 EXPANDBB(&rootbb, bb);
148 if (j < GD_n_cluster(g)) {
149 Agraph_t *const subg = children[j];
150 GD_bb(subg) = bb;
151 if (Verbose > 1) {
152 indent (depth);
153 fprintf (stderr, "%s : %f %f %f %f\n", agnameof(subg), bb.LL.x, bb.LL.y, bb.UR.x, bb.UR.y);
154 }
155 }
156 else {
157 Agnode_t *const n = children[j];
158 if (n) {
159 ND_coord(n) = mid_pointf (bb.LL, bb.UR);
160 if (Verbose > 1) {
161 indent (depth);
162 fprintf (stderr, "%s : %f %f\n", agnameof(n), ND_coord(n).x, ND_coord(n).y);
163 }
164 }
165 }
166 }
167
168 if (GD_label(g)) {
169 double d;
170
171 pointf pt = GD_label(g)->dimen;
172 if (total == 0) {
173 rootbb = (boxf){.UR = pt};
174 }
175 d = pt.x - (rootbb.UR.x - rootbb.LL.x);
176 if (d > 0) { /* height of label is added below */
177 d /= 2;
178 rootbb.LL.x -= d;
179 rootbb.UR.x += d;
180 }
181 }
182
183 const double margin = depth > 0 ? pinfo.margin / 2.0 : 0;
184 rootbb.LL.x -= margin;
185 rootbb.UR.x += margin;
186 rootbb.LL.y -= margin + GD_border(g)[BOTTOM_IX].y;
187 rootbb.UR.y += margin + GD_border(g)[TOP_IX].y;
188
189 if (Verbose > 1) {
190 indent (depth);
191 fprintf (stderr, "%s : %f %f %f %f\n", agnameof(g), rootbb.LL.x, rootbb.LL.y, rootbb.UR.x, rootbb.UR.y);
192 }
193
194 /* Translate so that rootbb.LL is origin.
195 * This makes the repositioning simpler; we just translate the clusters and nodes in g by
196 * the final bb.ll of g.
197 */
198 for (j = 0; j < total; j++) {
199 if (j < GD_n_cluster(g)) {
200 Agraph_t *const subg = children[j];
201 boxf bb = GD_bb(subg);
202 bb.LL = sub_pointf(bb.LL, rootbb.LL);
203 bb.UR = sub_pointf(bb.UR, rootbb.LL);
204 GD_bb(subg) = bb;
205 if (Verbose > 1) {
206 indent (depth);
207 fprintf (stderr, "%s : %f %f %f %f\n", agnameof(subg), bb.LL.x, bb.LL.y, bb.UR.x, bb.UR.y);
208 }
209 }
210 else {
211 Agnode_t *const n = children[j];
212 if (n) {
213 ND_coord(n) = sub_pointf (ND_coord(n), rootbb.LL);
214 if (Verbose > 1) {
215 indent (depth);
216 fprintf (stderr, "%s : %f %f\n", agnameof(n), ND_coord(n).x, ND_coord(n).y);
217 }
218 }
219 }
220 }
221
222 rootbb = (boxf){.UR = sub_pointf(rootbb.UR, rootbb.LL)};
223 GD_bb(g) = rootbb;
224
225 if (Verbose > 1) {
226 indent (depth);
227 fprintf (stderr, "%s : %f %f %f %f\n", agnameof(g), rootbb.LL.x, rootbb.LL.y, rootbb.UR.x, rootbb.UR.y);
228 }
229
230 LIST_FREE(&gs);
231 free (children);
232 free (pts);
233}
234
235static void
236reposition (Agraph_t* g, int depth)
237{
238 boxf bb = GD_bb(g);
239
240 if (Verbose > 1) {
241 indent (depth);
242 fprintf (stderr, "reposition %s\n", agnameof(g));
243 }
244
245 /* translate nodes in g but not in a subcluster */
246 if (depth) {
247 for (Agnode_t *n = agfstnode(g); n; n = agnxtnode(g, n)) {
248 if (PARENT(n) != g)
249 continue;
250 ND_coord(n).x += bb.LL.x;
251 ND_coord(n).y += bb.LL.y;
252 if (Verbose > 1) {
253 indent (depth);
254 fprintf (stderr, "%s : %f %f\n", agnameof(n), ND_coord(n).x, ND_coord(n).y);
255 }
256 }
257 }
258
259 /* translate top-level clusters and recurse */
260 for (int i = 1; i <= GD_n_cluster(g); i++) {
261 Agraph_t *const subg = GD_clust(g)[i];
262 if (depth) {
263 boxf sbb = GD_bb(subg);
264 sbb.LL.x += bb.LL.x;
265 sbb.LL.y += bb.LL.y;
266 sbb.UR.x += bb.LL.x;
267 sbb.UR.y += bb.LL.y;
268 if (Verbose > 1) {
269 indent (depth);
270 fprintf (stderr, "%s : %f %f %f %f\n", agnameof(subg), sbb.LL.x, sbb.LL.y, sbb.UR.x, sbb.UR.y);
271 }
272 GD_bb(subg) = sbb;
273 }
274 reposition (subg, depth+1);
275 }
276
277}
278
279static void
280mkClusters (Agraph_t* g, clist_t* pclist, Agraph_t* parent)
281{
282 clist_t list = {0};
283 clist_t* clist;
284
285 if (pclist == NULL) {
286 // [0] is empty. The clusters are in [1..cnt].
287 LIST_APPEND(&list, NULL);
288 clist = &list;
289 }
290 else
291 clist = pclist;
292
293 for (graph_t *subg = agfstsubg(g); subg; subg = agnxtsubg(subg)) {
294 if (is_a_cluster(subg)) {
295 agbindrec(subg, "Agraphinfo_t", sizeof(Agraphinfo_t), true);
296 do_graph_label (subg);
297 LIST_APPEND(clist, subg);
298 mkClusters(subg, NULL, subg);
299 }
300 else {
301 mkClusters(subg, clist, parent);
302 }
303 }
304 if (pclist == NULL) {
305 assert(LIST_SIZE(&list) - 1 <= INT_MAX);
306 GD_n_cluster(g) = (int)(LIST_SIZE(&list) - 1);
307 if (LIST_SIZE(&list) > 1) {
308 LIST_SHRINK_TO_FIT(&list);
309 LIST_DETACH(&list, &GD_clust(g), NULL);
310 } else {
311 LIST_FREE(&list);
312 }
313 }
314}
315
317{
318 cluster_init_graph(g);
319 mkClusters(g, NULL, g);
320 layout(g, 0);
321 reposition (g, 0);
322
323 if (GD_drawing(g)->ratio_kind) {
324 Agnode_t* n;
325 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
326 ND_pos(n)[0] = PS2INCH(ND_coord(n).x);
327 ND_pos(n)[1] = PS2INCH(ND_coord(n).y);
328 }
329 spline_edges0(g, true);
330 }
331 else {
332 int et = EDGE_TYPE (g);
333 if (et != EDGETYPE_NONE) spline_edges1(g, et);
334 }
336}
337
338static void cleanup_graphs (Agraph_t *g)
339{
340 for (int i = 1; i <= GD_n_cluster(g); i++) {
341 graph_t *const subg = GD_clust(g)[i];
342 free_label(GD_label(subg));
343 cleanup_graphs (subg);
344 }
345 free (GD_clust(g));
346}
347
349{
350 for (node_t *n = agfstnode(g); n; n = agnxtnode(g, n)) {
351 for (edge_t *e = agfstout(g, n); e; e = agnxtout(g, e)) {
353 }
355 }
357}
358
#define DFLT_MARGIN
Definition adjust.h:23
Memory allocation wrappers that exit on failure.
static void * gv_calloc(size_t nmemb, size_t size)
Definition alloc.h:26
#define parent(i)
Definition closest.c:73
void setEdgeType(graph_t *g, int defaultValue)
Definition utils.c:1420
int late_int(void *obj, attrsym_t *attr, int defaultValue, int minimum)
Definition utils.c:36
void common_init_edge(edge_t *e)
Definition utils.c:507
bool is_a_cluster(Agraph_t *g)
Definition utils.c:693
#define BOTTOM_IX
Definition const.h:111
#define TOP_IX
Definition const.h:113
#define EDGETYPE_LINE
Definition const.h:235
#define EDGETYPE_NONE
Definition const.h:234
#define PS2INCH(a_points)
Definition geom.h:64
geometric functions (e.g. on points and boxes)
static WUR pointf mid_pointf(pointf p, pointf q)
Definition geomprocs.h:104
static WUR pointf sub_pointf(pointf p, pointf q)
Definition geomprocs.h:96
static WUR pointf add_pointf(pointf p, pointf q)
Definition geomprocs.h:88
#define EXPANDBB(b0, b1)
Definition geomprocs.h:65
unsigned short Ndim
Definition globals.h:62
static bool Verbose
Definition gml2gv.c:24
void free(void *)
node NULL
Definition grammar.y:181
int agnnodes(Agraph_t *g)
Definition graph.c:155
Agsym_t * agattr_text(Agraph_t *g, int kind, char *name, const char *value)
creates or looks up text attributes of a graph
Definition attr.c:334
Agedge_t * agfstout(Agraph_t *g, Agnode_t *n)
Definition edge.c:26
Agedge_t * agnxtout(Agraph_t *g, Agedge_t *e)
Definition edge.c:41
void agwarningf(const char *fmt,...)
Definition agerror.c:173
#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_bb(g)
Definition types.h:354
#define GD_n_cluster(g)
Definition types.h:389
#define GD_ndim(g)
Definition types.h:390
#define GD_label(g)
Definition types.h:374
Agnode_t * agnxtnode(Agraph_t *g, Agnode_t *n)
Definition node.c:48
Agnode_t * agfstnode(Agraph_t *g)
Definition node.c:41
#define ND_ysize(n)
Definition types.h:538
#define ND_alg(n)
Definition types.h:484
#define ND_pos(n)
Definition types.h:520
#define ND_coord(n)
Definition types.h:490
#define ND_xsize(n)
Definition types.h:537
char * agnameof(void *)
returns a string descriptor for the object.
Definition id.c:143
@ AGNODE
Definition cgraph.h:207
@ AGRAPH
Definition cgraph.h:207
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:89
Agraph_t * agfstsubg(Agraph_t *g)
Definition subg.c:73
Agraph_t * agnxtsubg(Agraph_t *subg)
Definition subg.c:78
void do_graph_label(graph_t *sg)
Set characteristics of graph label if it exists.
Definition input.c:834
void free_label(textlabel_t *p)
Definition labels.c:202
type-generic dynamically expanding list
#define LIST_DETACH(list, datap, sizep)
Definition list.h:443
#define LIST(type)
Definition list.h:55
#define LIST_SIZE(list)
Definition list.h:80
#define LIST_APPEND(list, item)
Definition list.h:120
#define LIST_FREE(list)
Definition list.h:370
#define LIST_SHRINK_TO_FIT(list)
Definition list.h:358
#define LIST_FRONT(list)
Definition list.h:180
#define LIST_IS_EMPTY(list)
Definition list.h:90
#define LIST_GET(list, index)
Definition list.h:155
#define EDGE_TYPE(g)
Definition macros.h:25
void neato_init_node(node_t *n)
Definition neatoinit.c:61
NEATOPROCS_API void spline_edges0(Agraph_t *, bool)
NEATOPROCS_API int spline_edges1(graph_t *g, int)
static void cleanup_graphs(Agraph_t *g)
Definition osageinit.c:338
static void indent(int i)
Definition osageinit.c:36
static void mkClusters(Agraph_t *g, clist_t *pclist, Agraph_t *parent)
Definition osageinit.c:280
static void reposition(Agraph_t *g, int depth)
Definition osageinit.c:236
void osage_cleanup(Agraph_t *g)
Definition osageinit.c:348
#define PARENT(n)
Definition osageinit.c:33
static void layout(Agraph_t *g, int depth)
Definition osageinit.c:66
void osage_layout(Agraph_t *g)
Definition osageinit.c:316
#define DFLT_SZ
Definition osageinit.c:32
pointf * putRects(size_t ng, boxf *bbs, pack_info *pinfo)
Definition pack.c:928
pack_mode getPackInfo(Agraph_t *g, pack_mode dflt, int dfltMargin, pack_info *pinfo)
Definition pack.c:1282
support for connected components
pack_mode
Definition pack.h:55
@ l_graph
Definition pack.h:55
@ l_array
Definition pack.h:55
unsigned int packval_t
Definition pack.h:65
#define PK_USER_VALS
Definition pack.h:58
void dotneato_postprocess(Agraph_t *g)
Definition postproc.c:689
void gv_cleanup_edge(Agedge_t *e)
Definition utils.c:1510
void gv_cleanup_node(Agnode_t *n)
Definition utils.c:1522
graph or subgraph
Definition cgraph.h:424
Agraph_t * root
subgraphs - ancestors
Definition cgraph.h:433
string attribute descriptor symbol in Agattr_s.dict
Definition cgraph.h:640
Definition geom.h:41
pointf UR
Definition geom.h:41
pointf LL
Definition geom.h:41
int flags
Definition pack.h:75
pack_mode mode
Definition pack.h:72
packval_t * vals
Definition pack.h:74
unsigned int margin
Definition pack.h:70
double x
Definition geom.h:29
double y
Definition geom.h:29