Graphviz 13.0.0~dev.20241220.2304
Loading...
Searching...
No Matches
gvcolor.c
Go to the documentation of this file.
1
6/*************************************************************************
7 * Copyright (c) 2011 AT&T Intellectual Property
8 * All rights reserved. This program and the accompanying materials
9 * are made available under the terms of the Eclipse Public License v1.0
10 * which accompanies this distribution, and is available at
11 * https://www.eclipse.org/legal/epl-v10.html
12 *
13 * Contributors: Details at https://graphviz.org
14 *************************************************************************/
15
16
17/*
18 * Written by Stephen North
19 * Updated by Emden Gansner
20 */
21
22/* if NC changes, a bunch of scanf calls below are in trouble */
23#define NC 3 /* size of HSB color vector */
24
25#include <assert.h>
26#include <cgraph/cgraph.h>
27#include <cgraph/ingraphs.h>
28#include "colorxlate.h"
29#include <math.h>
30#include <stdbool.h>
31#include <stdlib.h>
32#include <util/agxbuf.h>
33#include <util/alloc.h>
34#include <util/exit.h>
35
36typedef struct {
37 Agrec_t h;
38 double relrank; /* coordinate of its rank, smaller means lower rank */
39 double x[NC]; /* color vector */
41
42#define ND_relrank(n) (((Agnodeinfo_t*)((n)->base.data))->relrank)
43#define ND_x(n) (((Agnodeinfo_t*)((n)->base.data))->x)
44
45#include <stdio.h>
46
47#include <getopt.h>
48
49double Defcolor[NC] = { 0.0, 0.0, 1.0 }; /* white */
50int Forward = 1; /* how to propagate colors w.r.t. ranks */
51int LR = 0; /* rank orientation */
52
56
57static int cmpf(const void *x, const void *y) {
58// Suppress Clang/GCC -Wcast-qual warning. Casting away const here is acceptable
59// as the later usage is const. We need the cast because the macros use
60// non-const pointers for genericity.
61#ifdef __GNUC__
62#pragma GCC diagnostic push
63#pragma GCC diagnostic ignored "-Wcast-qual"
64#endif
65 Agnode_t **n0 = (Agnode_t **)x;
66 Agnode_t **n1 = (Agnode_t **)y;
67#ifdef __GNUC__
68#pragma GCC diagnostic pop
69#endif
70 double relrank0 = ND_relrank(*n0);
71 double relrank1 = ND_relrank(*n1);
72 if (relrank0 < relrank1)
73 return -1;
74 if (relrank0 > relrank1)
75 return 1;
76 return 0;
77}
78
79static void setcolor(char *p, double *v)
80{
81 agxbuf buf = {0};
82 if (sscanf(p, "%lf %lf %lf", v, v + 1, v + 2) != 3 && p[0]) {
83 colorxlate(p, &buf);
84 sscanf(agxbuse(&buf), "%lf %lf %lf", v, v + 1, v + 2);
85 }
86 agxbfree(&buf);
87}
88
89static char **Files;
90
91static char *useString = "Usage: gvcolor [-?] <files>\n\
92 -? - print usage\n\
93If no files are specified, stdin is used\n";
94
95static void usage(int v)
96{
97 printf("%s",useString);
99}
100
101static void init(int argc, char *argv[])
102{
103 int c;
104
105 opterr = 0;
106 while ((c = getopt(argc, argv, ":?")) != -1) {
107 switch (c) {
108 case '?':
109 if (optopt == '\0' || optopt == '?')
110 usage(0);
111 else {
112 fprintf(stderr, "gvcolor: option -%c unrecognized\n",
113 optopt);
114 usage(1);
115 }
116 break;
117 default:
118 fprintf(stderr, "gvcolor: unexpected error\n");
119 graphviz_exit(EXIT_FAILURE);
120 }
121 }
122 argv += optind;
123 argc -= optind;
124
125 if (argc)
126 Files = argv;
127}
128
129static void color(Agraph_t * g)
130{
131 int nn, j, cnt;
132 Agnode_t *n, *v, **nlist;
133 Agedge_t *e;
134 char *p;
135 double x, y, maxrank = 0.0;
136 double sum[NC], d, lowsat, highsat;
137
138 if (agattr(g, AGNODE, "pos", 0) == NULL) {
139 fprintf(stderr,
140 "graph must be run through 'dot' before 'gvcolor'\n");
141 graphviz_exit(1);
142 }
143 aginit(g, AGNODE, "nodeinfo", sizeof(Agnodeinfo_t), true);
144 if (agattr(g, AGNODE, "style", 0) == NULL)
145 agattr(g, AGNODE, "style", "filled");
146 if ((p = agget(g, "Defcolor")))
147 setcolor(p, Defcolor);
148
149 if ((p = agget(g, "rankdir")) && p[0] == 'L')
150 LR = 1;
151 if ((p = agget(g, "flow")) && p[0] == 'b')
152 Forward = 0;
153 if ((p = agget(g, "saturation"))) {
154 if (sscanf(p, "%lf,%lf", &lowsat, &highsat) == 2) {
155 MinRankSaturation = lowsat;
156 MaxRankSaturation = highsat;
158 }
159 }
160
161 /* assemble the sorted list of nodes and store the initial colors */
162 nn = agnnodes(g);
163 assert(nn >= 0);
164 size_t nnodes = (size_t)nn;
165 nlist = gv_calloc(nnodes, sizeof(Agnode_t *));
166 size_t i = 0;
167 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
168 nlist[i++] = n;
169 if ((p = agget(n, "color")))
170 setcolor(p, ND_x(n));
171 p = agget(n, "pos");
172 sscanf(p, "%lf,%lf", &x, &y);
173 ND_relrank(n) = (LR ? x : y);
174 maxrank = fmax(maxrank, ND_relrank(n));
175 }
176 if (LR != Forward)
177 for (i = 0; i < nnodes; i++) {
178 n = nlist[i];
179 ND_relrank(n) = maxrank - ND_relrank(n);
180 }
181 qsort(nlist, nnodes, sizeof(Agnode_t *), cmpf);
182
183 /* this is the pass that pushes the colors through the edges */
184 for (i = 0; i < nnodes; i++) {
185 n = nlist[i];
186
187 /* skip nodes that were manually colored */
188 cnt = 0;
189 for (j = 0; j < NC; j++)
190 if (ND_x(n)[j] != 0.0)
191 cnt++;
192 if (cnt > 0)
193 continue;
194
195 for (j = 0; j < NC; j++)
196 sum[j] = 0.0;
197 cnt = 0;
198 for (e = agfstedge(g, n); e; e = agnxtedge(g, e, n)) {
199 v = aghead(e);
200 if (v == n)
201 v = agtail(e);
202 d = ND_relrank(v) - ND_relrank(n) - 0.01;
203 if (d < 0) {
204 double t = 0.0;
205 for (j = 0; j < NC; j++) {
206 t += ND_x(v)[j];
207 sum[j] += ND_x(v)[j];
208 }
209 if (t > 0.0)
210 cnt++;
211 }
212 }
213 if (cnt)
214 for (j = 0; j < NC; j++)
215 ND_x(n)[j] = sum[j] / cnt;
216 }
217
218 /* apply saturation adjustment and convert color to string */
219 for (i = 0; i < nnodes; i++) {
220 double h, s, b, t;
221 char buf[64];
222
223 n = nlist[i];
224
225 t = 0.0;
226 for (j = 0; j < NC; j++)
227 t += ND_x(n)[j];
228 if (t > 0.0) {
229 h = ND_x(n)[0];
230 if (AdjustSaturation) {
231 s = ND_relrank(n) / maxrank;
232 if (!Forward)
233 s = 1.0 - s;
236 } else
237 s = 1.0;
238 s = s * ND_x(n)[1];
239 b = ND_x(n)[2];
240 } else {
241 h = Defcolor[0];
242 s = Defcolor[1];
243 b = Defcolor[2];
244 }
245 snprintf(buf, sizeof(buf), "%f %f %f", h, s, b);
246 agset(n, "color", buf);
247 }
248 free (nlist);
249}
250
251int main(int argc, char **argv)
252{
253 Agraph_t *g;
254 ingraph_state ig;
255
256 init(argc, argv);
257 newIngraph(&ig, Files);
258
259 while ((g = nextGraph(&ig)) != 0) {
260 color(g);
261 agwrite(g, stdout);
262 fflush(stdout);
263 agclose(g);
264 }
265
266 graphviz_exit(0);
267}
static void agxbfree(agxbuf *xb)
free any malloced resources
Definition agxbuf.h:78
static WUR char * agxbuse(agxbuf *xb)
Definition agxbuf.h:307
Memory allocation wrappers that exit on failure.
static void * gv_calloc(size_t nmemb, size_t size)
Definition alloc.h:26
abstract graph C library, Cgraph API
void colorxlate(char *str, agxbuf *buf)
Definition colxlate.c:46
static NORETURN void graphviz_exit(int status)
Definition exit.h:23
void free(void *)
node NULL
Definition grammar.y:163
static int cnt(Dict_t *d, Dtlink_t **set)
Definition graph.c:210
int agnnodes(Agraph_t *g)
Definition graph.c:169
Agsym_t * agattr(Agraph_t *g, int kind, char *name, const char *value)
creates or looks up attributes of a graph
Definition attr.c:338
int agset(void *obj, char *name, const char *value)
Definition attr.c:466
char * agget(void *obj, char *name)
Definition attr.c:439
#define agtail(e)
Definition cgraph.h:880
Agedge_t * agnxtedge(Agraph_t *g, Agedge_t *e, Agnode_t *n)
Definition edge.c:94
#define aghead(e)
Definition cgraph.h:881
Agedge_t * agfstedge(Agraph_t *g, Agnode_t *n)
Definition edge.c:85
int agclose(Agraph_t *g)
deletes a graph, freeing its associated storage
Definition graph.c:102
int agwrite(Agraph_t *g, void *chan)
Return 0 on success, EOF on failure.
Definition write.c:730
Agnode_t * agnxtnode(Agraph_t *g, Agnode_t *n)
Definition node.c:47
Agnode_t * agfstnode(Agraph_t *g)
Definition node.c:40
@ AGNODE
Definition cgraph.h:207
void aginit(Agraph_t *g, int kind, const char *rec_name, int rec_size, int move_to_front)
attach new records to objects of specified kind
Definition rec.c:170
static void init(int argc, char *argv[])
Definition gvcolor.c:101
#define ND_x(n)
Definition gvcolor.c:43
#define NC
Definition gvcolor.c:23
static int cmpf(const void *x, const void *y)
Definition gvcolor.c:57
static void color(Agraph_t *g)
Definition gvcolor.c:129
int AdjustSaturation
Definition gvcolor.c:53
double Defcolor[NC]
Definition gvcolor.c:49
double MaxRankSaturation
Definition gvcolor.c:55
int Forward
Definition gvcolor.c:50
double MinRankSaturation
Definition gvcolor.c:54
int LR
Definition gvcolor.c:51
static char * useString
Definition gvcolor.c:91
#define ND_relrank(n)
Definition gvcolor.c:42
static char ** Files
Definition gvcolor.c:89
static void setcolor(char *p, double *v)
Definition gvcolor.c:79
static const char * usage
Definition gvpr.c:51
Agraph_t * nextGraph(ingraph_state *sp)
Definition ingraphs.c:61
ingraph_state * newIngraph(ingraph_state *sp, char **files)
Definition ingraphs.c:140
supports user-supplied data
double relrank
Definition gvcolor.c:38
graph or subgraph
Definition cgraph.h:425
implementation of Agrec_t
Definition cgraph.h:172
int main()
Definition grammar.c:93