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