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