Graphviz 14.1.2~dev.20260118.2044
Loading...
Searching...
No Matches
tree_map.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#include "config.h"
12
13#include <common/render.h>
14#include <math.h>
15#include <patchwork/tree_map.h>
16#include <util/alloc.h>
17#include <util/prisize_t.h>
18
19static void squarify(size_t n, double *area, rectangle *recs, size_t nadded, double maxarea, double minarea, double totalarea,
20 double asp, rectangle fillrec){
21 /* add a list of area in fillrec using squarified treemap alg.
22 n: number of items to add
23 area: area of these items, Sum to 1 (?).
24 nadded: number of items already added
25 maxarea: maxarea of already added items
26 minarea: min areas of already added items
27 asp: current worst aspect ratio of the already added items so far
28 fillrec: the rectangle to be filled in.
29 */
30 double w = fmin(fillrec.size[0], fillrec.size[1]);
31
32 if (n == 0) return;
33
34 if (Verbose) {
35 fprintf(stderr, "trying to add to rect {%f +/- %f, %f +/- %f}\n",fillrec.x[0], fillrec.size[0], fillrec.x[1], fillrec.size[1]);
36 fprintf(stderr, "total added so far = %" PRISIZE_T "\n", nadded);
37 }
38
39 if (nadded == 0){
40 nadded = 1;
41 maxarea = minarea = area[0];
42 asp = fmax(area[0] / (w * w), w * w / area[0]);
43 totalarea = area[0];
44 squarify(n, area, recs, nadded, maxarea, minarea, totalarea, asp, fillrec);
45 } else {
46 double newmaxarea, newminarea, s, h, maxw, minw, newasp = 0, hh, ww, xx, yy;
47 if (nadded < n){
48 newmaxarea = fmax(maxarea, area[nadded]);
49 newminarea = fmin(minarea, area[nadded]);
50 s = totalarea + area[nadded];
51 h = s/w;
52 maxw = newmaxarea/h;
53 minw = newminarea/h;
54 newasp = fmax(h / minw, maxw / h);/* same as MAX{s^2/(w^2*newminarea), (w^2*newmaxarea)/(s^2)}*/
55 }
56 if (nadded < n && newasp <= asp){/* aspectio improved, keep adding */
57 squarify(n, area, recs, ++nadded, newmaxarea, newminarea, s, newasp, fillrec);
58 } else {
59 /* aspectio worsen if add another area, fixed the already added recs */
60 if (Verbose) fprintf(stderr, "adding %" PRISIZE_T
61 " items, total area = %f, w = %f, area/w=%f\n",
62 nadded, totalarea, w, totalarea/w);
63 if (fillrec.size[0] <= fillrec.size[1]) {
64 // tall rec. fix the items along x direction, left to right, at top
65 hh = totalarea/w;
66 xx = fillrec.x[0] - fillrec.size[0]/2;
67 for (size_t i = 0; i < nadded; i++){
68 recs[i].size[1] = hh;
69 ww = area[i]/hh;
70 recs[i].size[0] = ww;
71 recs[i].x[1] = fillrec.x[1] + 0.5*(fillrec.size[1]) - hh/2;
72 recs[i].x[0] = xx + ww/2;
73 xx += ww;
74 }
75 fillrec.x[1] -= hh/2;/* the new empty space is below the filled space */
76 fillrec.size[1] -= hh;
77 } else {/* short rec. fix along y top to bot, at left*/
78 ww = totalarea/w;
79 yy = fillrec.x[1] + fillrec.size[1]/2;
80 for (size_t i = 0; i < nadded; i++){
81 recs[i].size[0] = ww;
82 hh = area[i]/ww;
83 recs[i].size[1] = hh;
84 recs[i].x[0] = fillrec.x[0] - 0.5*(fillrec.size[0]) + ww/2;
85 recs[i].x[1] = yy - hh/2;
86 yy -= hh;
87 }
88 fillrec.x[0] += ww/2;/* the new empty space is right of the filled space */
89 fillrec.size[0] -= ww;
90 }
91 squarify(n - nadded, area + nadded, recs + nadded, 0, 0., 0., 0., 1., fillrec);
92 }
93
94 }
95}
96
97/* tree_map:
98 * Perform a squarified treemap layout on a single level.
99 * n - number of rectangles
100 * area - area of rectangles
101 * fillred - rectangle to be filled
102 * return array of rectangles
103 */
104rectangle* tree_map(size_t n, double *area, rectangle fillrec){
105 /* fill a rectangle rec with n items, each item i has area[i] area. */
106 double total = 0, minarea = 1., maxarea = 0., asp = 1, totalarea = 0;
107
108 for (size_t i = 0; i < n; i++) total += area[i];
109 /* make sure there is enough area */
110 if (total > fillrec.size[0] * fillrec.size[1] + 0.001)
111 return NULL;
112
113 rectangle *recs = gv_calloc(n, sizeof(rectangle));
114 squarify(n, area, recs, 0, maxarea, minarea, totalarea, asp, fillrec);
115 return recs;
116}
Memory allocation wrappers that exit on failure.
static void * gv_calloc(size_t nmemb, size_t size)
Definition alloc.h:26
static bool Verbose
Definition gml2gv.c:26
node NULL
Definition grammar.y:181
#define PRISIZE_T
Definition prisize_t.h:25
double x[2]
Definition tree_map.h:17
double size[2]
Definition tree_map.h:18
rectangle * tree_map(size_t n, double *area, rectangle fillrec)
Definition tree_map.c:104
static void squarify(size_t n, double *area, rectangle *recs, size_t nadded, double maxarea, double minarea, double totalarea, double asp, rectangle fillrec)
Definition tree_map.c:19
Definition grammar.c:90