Graphviz 14.1.2~dev.20260123.1158
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#include "config.h"
23
24/* if NC changes, a bunch of scanf calls below are in trouble */
25#define NC 3 /* size of HSB color vector */
26
27#include <cgraph/cgraph.h>
28#include <cgraph/ingraphs.h>
29#include "colorxlate.h"
30#include <math.h>
31#include <stdbool.h>
32#include <stdlib.h>
33#include <util/agxbuf.h>
34#include <util/gv_math.h>
35#include <util/exit.h>
36#include <util/list.h>
37
38typedef struct {
39 Agrec_t h;
40 double relrank; /* coordinate of its rank, smaller means lower rank */
41 double x[NC]; /* color vector */
43
44#define ND_relrank(n) (((Agnodeinfo_t*)((n)->base.data))->relrank)
45#define ND_x(n) (((Agnodeinfo_t*)((n)->base.data))->x)
46
47#include <stdio.h>
48
49#include <getopt.h>
50
51double Defcolor[NC] = { 0.0, 0.0, 1.0 }; /* white */
52int Forward = 1; /* how to propagate colors w.r.t. ranks */
53int LR = 0; /* rank orientation */
54
58
59static int cmpf(const void *x, const void *y) {
60 Agnode_t *const *n0 = x;
61 Agnode_t *const *n1 = y;
62 double relrank0 = ND_relrank(*n0);
63 double relrank1 = ND_relrank(*n1);
64 if (relrank0 < relrank1)
65 return -1;
66 if (relrank0 > relrank1)
67 return 1;
68 return 0;
69}
70
71static void setcolor(char *p, double *v)
72{
73 agxbuf buf = {0};
74 if (sscanf(p, "%lf %lf %lf", v, v + 1, v + 2) != 3 && p[0]) {
75 colorxlate(p, &buf);
76 sscanf(agxbuse(&buf), "%lf %lf %lf", v, v + 1, v + 2);
77 }
78 agxbfree(&buf);
79}
80
81static char **Files;
82
83static char *useString = "Usage: gvcolor [-?] <files>\n\
84 -? - print usage\n\
85If no files are specified, stdin is used";
86
87static void usage(int v)
88{
89 puts(useString);
91}
92
93static void init(int argc, char *argv[])
94{
95 int c;
96
97 opterr = 0;
98 while ((c = getopt(argc, argv, ":?")) != -1) {
99 switch (c) {
100 case '?':
101 if (optopt == '\0' || optopt == '?')
102 usage(0);
103 fprintf(stderr, "gvcolor: option -%c unrecognized\n", optopt);
104 usage(1);
105 break;
106 default:
107 fprintf(stderr, "gvcolor: unexpected error\n");
108 graphviz_exit(EXIT_FAILURE);
109 }
110 }
111 argv += optind;
112 argc -= optind;
113
114 if (argc)
115 Files = argv;
116}
117
118static void color(Agraph_t * g)
119{
120 char *p;
121 double x, y, maxrank = 0.0;
122 double lowsat, highsat;
123
124 if (agattr_text(g, AGNODE, "pos", 0) == NULL) {
125 fprintf(stderr,
126 "graph must be run through 'dot' before 'gvcolor'\n");
127 graphviz_exit(1);
128 }
129 aginit(g, AGNODE, "nodeinfo", sizeof(Agnodeinfo_t), true);
130 if (agattr_text(g, AGNODE, "style", 0) == NULL)
131 agattr_text(g, AGNODE, "style", "filled");
132 if ((p = agget(g, "Defcolor")))
133 setcolor(p, Defcolor);
134
135 if ((p = agget(g, "rankdir")) && p[0] == 'L')
136 LR = 1;
137 if ((p = agget(g, "flow")) && p[0] == 'b')
138 Forward = 0;
139 if ((p = agget(g, "saturation"))) {
140 if (sscanf(p, "%lf,%lf", &lowsat, &highsat) == 2) {
141 MinRankSaturation = lowsat;
142 MaxRankSaturation = highsat;
144 }
145 }
146
147 /* assemble the sorted list of nodes and store the initial colors */
148 LIST(Agnode_t *) nlist = {0};
149 for (Agnode_t *n = agfstnode(g); n; n = agnxtnode(g, n)) {
150 LIST_APPEND(&nlist, n);
151 if ((p = agget(n, "color")))
152 setcolor(p, ND_x(n));
153 p = agget(n, "pos");
154 sscanf(p, "%lf,%lf", &x, &y);
155 ND_relrank(n) = LR ? x : y;
156 maxrank = fmax(maxrank, ND_relrank(n));
157 }
158 if (LR != Forward)
159 for (size_t i = 0; i < LIST_SIZE(&nlist); i++) {
160 Agnode_t *const n = LIST_GET(&nlist, i);
161 ND_relrank(n) = maxrank - ND_relrank(n);
162 }
163 LIST_SORT(&nlist, cmpf);
164
165 /* this is the pass that pushes the colors through the edges */
166 for (size_t i = 0; i < LIST_SIZE(&nlist); i++) {
167 Agnode_t *const n = LIST_GET(&nlist, i);
168
169 /* skip nodes that were manually colored */
170 int cnt = 0;
171 for (int j = 0; j < NC; j++)
172 if (!is_exactly_zero(ND_x(n)[j]))
173 cnt++;
174 if (cnt > 0)
175 continue;
176
177 double sum[NC] = {0};
178 cnt = 0;
179 for (Agedge_t *e = agfstedge(g, n); e; e = agnxtedge(g, e, n)) {
180 Agnode_t *v = aghead(e);
181 if (v == n)
182 v = agtail(e);
183 if (ND_relrank(v) - ND_relrank(n) - 0.01 < 0) {
184 double t = 0.0;
185 for (int j = 0; j < NC; j++) {
186 t += ND_x(v)[j];
187 sum[j] += ND_x(v)[j];
188 }
189 if (t > 0.0)
190 cnt++;
191 }
192 }
193 if (cnt)
194 for (int j = 0; j < NC; j++)
195 ND_x(n)[j] = sum[j] / cnt;
196 }
197
198 /* apply saturation adjustment and convert color to string */
199 for (size_t i = 0; i < LIST_SIZE(&nlist); i++) {
200 double h, s, b, t;
201 char buf[64];
202
203 Agnode_t *const n = LIST_GET(&nlist, i);
204
205 t = 0.0;
206 for (int j = 0; j < NC; j++)
207 t += ND_x(n)[j];
208 if (t > 0.0) {
209 h = ND_x(n)[0];
210 if (AdjustSaturation) {
211 s = ND_relrank(n) / maxrank;
212 if (!Forward)
213 s = 1.0 - s;
216 } else
217 s = 1.0;
218 s *= ND_x(n)[1];
219 b = ND_x(n)[2];
220 } else {
221 h = Defcolor[0];
222 s = Defcolor[1];
223 b = Defcolor[2];
224 }
225 snprintf(buf, sizeof(buf), "%f %f %f", h, s, b);
226 agset(n, "color", buf);
227 }
228 LIST_FREE(&nlist);
229}
230
231int main(int argc, char **argv)
232{
233 Agraph_t *g;
234 ingraph_state ig;
235
236 init(argc, argv);
237 newIngraph(&ig, Files);
238
239 while ((g = nextGraph(&ig)) != 0) {
240 color(g);
241 agwrite(g, stdout);
242 fflush(stdout);
243 agclose(g);
244 }
245
246 graphviz_exit(0);
247}
Dynamically expanding string buffers.
static void agxbfree(agxbuf *xb)
free any malloced resources
Definition agxbuf.h:97
static WUR char * agxbuse(agxbuf *xb)
Definition agxbuf.h:325
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
node NULL
Definition grammar.y:181
static int cnt(Dict_t *d, Dtlink_t **set)
Definition graph.c:198
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:336
int agset(void *obj, char *name, const char *value)
Definition attr.c:477
char * agget(void *obj, char *name)
Definition attr.c:450
#define agtail(e)
Definition cgraph.h:977
Agedge_t * agnxtedge(Agraph_t *g, Agedge_t *e, Agnode_t *n)
Definition edge.c:98
#define aghead(e)
Definition cgraph.h:978
Agedge_t * agfstedge(Agraph_t *g, Agnode_t *n)
Definition edge.c:89
int agclose(Agraph_t *g)
deletes a graph, freeing its associated storage
Definition graph.c:97
int agwrite(Agraph_t *g, void *chan)
Return 0 on success, EOF on failure.
Definition write.c:669
Agnode_t * agnxtnode(Agraph_t *g, Agnode_t *n)
Definition node.c:50
Agnode_t * agfstnode(Agraph_t *g)
Definition node.c:43
@ 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:172
Arithmetic helper functions.
static bool is_exactly_zero(double v)
is a value precisely 0.0?
Definition gv_math.h:67
static void init(int argc, char *argv[])
Definition gvcolor.c:93
#define ND_x(n)
Definition gvcolor.c:45
#define NC
Definition gvcolor.c:25
static int cmpf(const void *x, const void *y)
Definition gvcolor.c:59
static void color(Agraph_t *g)
Definition gvcolor.c:118
int AdjustSaturation
Definition gvcolor.c:55
double Defcolor[NC]
Definition gvcolor.c:51
double MaxRankSaturation
Definition gvcolor.c:57
int Forward
Definition gvcolor.c:52
double MinRankSaturation
Definition gvcolor.c:56
int LR
Definition gvcolor.c:53
static char * useString
Definition gvcolor.c:83
#define ND_relrank(n)
Definition gvcolor.c:44
static char ** Files
Definition gvcolor.c:81
static void setcolor(char *p, double *v)
Definition gvcolor.c:71
static const char * usage
Definition gvpr.c:54
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
type-generic dynamically expanding list
#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_SORT(list, cmp)
Definition list.h:338
#define LIST_GET(list, index)
Definition list.h:155
double relrank
Definition gvcolor.c:40
graph or subgraph
Definition cgraph.h:424
implementation of Agrec_t
Definition cgraph.h:172
int main()
Definition grammar.c:90