Graphviz 15.1.1~dev.20260630.1303
Loading...
Searching...
No Matches
edge_distinct_coloring.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 v2.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
7 *
8 * Contributors: Details at https://graphviz.org
9 *************************************************************************/
10
11#include "config.h"
12
13#include <assert.h>
14#include <sparse/general.h>
15#include <math.h>
16#include <stdbool.h>
17#include <stddef.h>
18#include <string.h>
19#include <time.h>
20#include <sparse/SparseMatrix.h>
23#include <sparse/DotIO.h>
25#include <sparse/QuadTree.h>
26#include <util/list.h>
27#include <util/prisize_t.h>
28
29static int splines_intersect(size_t dim,
30 double cos_critical, int check_edges_with_same_endpoint,
31 char *xsplines1, char *xsplines2){
32 /* cos_critical: cos of critical angle
33 check_edges_with_same_endpoint: whether need to treat two splines from
34 . the same end point specially in ignoring splines that exit/enter the same end point at around 180
35 xsplines1,xsplines2: the first and second splines corresponding to two edges
36
37 */
38 int iter1 = 0, iter2 = 0;
39 double cos_a;
40 bool endp1 = false;
41 bool endp2 = false;
42
43 double tmp[2] = {0};
44 LIST(double) x1 = {0};
45 LIST(double) x2 = {0};
46
47 assert(dim == 2);
48
49 /* splines could be a list of
50 1. 3n points
51 2. of the form "e,x,y" followed by 3n points, where x,y is really padded to the end of the 3n points
52 3. of the form "s,x,y" followed by 3n points, where x,y is padded to the start of the 3n points
53 */
54 if (xsplines1){
55 if(strstr(xsplines1, "e,")){
56 endp1 = true;
57 xsplines1 = strstr(xsplines1, "e,") + 2;
58 } else if (strstr(xsplines1, "s,")){
59 xsplines1 = strstr(xsplines1, "s,") + 2;
60 }
61 }
62 for (double x, y; xsplines1 && sscanf(xsplines1,"%lf,%lf", &x, &y) == 2; ) {
63 if (endp1 && iter1 == 0){
64 tmp[0] = x;
65 tmp[1] = y;
66 } else {
67 LIST_APPEND(&x1, x);
68 LIST_APPEND(&x1, y);
69 }
70 iter1++;
71 xsplines1 = strchr(xsplines1, ' ');
72 if (!xsplines1) break;
73 xsplines1++;
74 }
75 if (endp1){/* pad the end point at the last position */
76 LIST_APPEND(&x1, tmp[0]);
77 LIST_APPEND(&x1, tmp[1]);
78 }
79
80
81 /* splines could be a list of
82 1. 3n points
83 2. of the form "e,x,y" followed by 3n points, where x,y is really padded to the end of the 3n points
84 3. of the form "s,x,y" followed by 3n points, where x,y is padded to the start of the 3n points
85 */
86 if (xsplines2){
87 if(strstr(xsplines2, "e,")){
88 endp2 = true;
89 xsplines2 = strstr(xsplines2, "e,") + 2;
90 } else if (strstr(xsplines2, "s,")){
91 xsplines2 = strstr(xsplines2, "s,") + 2;
92 }
93 }
94 for (double x, y; xsplines2 && sscanf(xsplines2,"%lf,%lf", &x, &y) == 2; ) {
95 if (endp2 && iter2 == 0){
96 tmp[0] = x;
97 tmp[1] = y;
98 } else {
99 LIST_APPEND(&x2, x);
100 LIST_APPEND(&x2, y);
101 }
102 iter2++;
103 xsplines2 = strchr(xsplines2, ' ');
104 if (!xsplines2) break;
105 xsplines2++;
106 }
107 if (endp2){/* pad the end point at the last position */
108 LIST_APPEND(&x2, tmp[0]);
109 LIST_APPEND(&x2, tmp[1]);
110 }
111
112 assert(LIST_SIZE(&x1) % dim == 0);
113 for (size_t i = 0; i < LIST_SIZE(&x1) / 2 - 1; i++) {
114 assert(LIST_SIZE(&x2) % dim == 0);
115 for (size_t j = 0; j < LIST_SIZE(&x2) / 2 - 1; j++) {
116 cos_a = intersection_angle(LIST_AT(&x1, dim * i),
117 LIST_AT(&x1, dim * (i + 1)),
118 LIST_AT(&x2, dim * j),
119 LIST_AT(&x2, dim * (j + 1)));
120 if (!check_edges_with_same_endpoint && cos_a >= -1) cos_a = fabs(cos_a);
121 if (cos_a > cos_critical) {
122 LIST_FREE(&x1);
123 LIST_FREE(&x2);
124 return 1;
125 }
126
127 }
128 }
129
130 LIST_FREE(&x1);
131 LIST_FREE(&x2);
132 return 0;
133}
134
135Agraph_t *edge_distinct_coloring(const char *color_scheme, int *lightness,
136 Agraph_t *g, double angle, double accuracy,
137 int check_edges_with_same_endpoint, int seed) {
138 double *x = NULL;
139 int dim = 2;
140 SparseMatrix A, B, C;
141 int *irn, *jcn, nz2 = 0;
142 double cos_critical = cos(angle/180*3.14159), cos_a;
143 int u1, v1, u2, v2, j;
144 double *colors = NULL;
145 int flag, ne;
146 char **xsplines = NULL;
147 size_t cdim;
148
150 if (!x){
151 fprintf(stderr,"The gv file contains no or improper 2D coordinates\n");
152 return NULL;
153 }
154
155
156 irn = A->ia; jcn = A->ja;
157 const size_t nz = A->nz;
158
159 /* get rid of self edges */
160 for (size_t i = 0; i < nz; i++){
161 if (irn[i] != jcn[i]){
162 irn[nz2] = irn[i];
163 jcn[nz2++] = jcn[i];
164 }
165 }
166
167 if (Verbose)
168 fprintf(stderr,"cos = %f, nz2 = %d\n", cos_critical, nz2);
169 /* now find edge collision */
170 B = SparseMatrix_new((size_t)nz2, nz2, 1, MATRIX_TYPE_REAL, FORMAT_COORD);
171
172 if (Import_dot_splines(g, &ne, &xsplines)){
173#ifdef TIME
174 clock_t start = clock();
175#endif
176 assert(ne == nz2);
177 cos_a = 1.;/* for splines we exit conflict check as soon as we find an conflict, so the angle may not be representative, hence set to constant */
178 for (int i = 0; i < nz2; i++){
179 for (j = i+1; j < nz2; j++){
180 if (splines_intersect((size_t)dim, cos_critical,
181 check_edges_with_same_endpoint, xsplines[i],
182 xsplines[j])) {
184 }
185 }
186 }
187#ifdef TIME
188 fprintf(stderr, "cpu for dual graph =%10.3f", ((double) (clock() - start))/CLOCKS_PER_SEC);
189#endif
190
191 } else {
192 /* no splines, just simple edges */
193#ifdef TIME
194 clock_t start = clock();
195#endif
196
197
198 for (int i = 0; i < nz2; i++){
199 u1 = irn[i]; v1 = jcn[i];
200 for (j = i+1; j < nz2; j++){
201 u2 = irn[j]; v2 = jcn[j];
202 cos_a = intersection_angle(&(x[dim*u1]), &(x[dim*v1]), &(x[dim*u2]), &(x[dim*v2]));
203 if (!check_edges_with_same_endpoint && cos_a >= -1) cos_a = fabs(cos_a);
204 if (cos_a > cos_critical) {
206 }
207 }
208 }
209#ifdef TIME
210 fprintf(stderr, "cpu for dual graph (splines) =%10.3f\n", ((double) (clock() - start))/CLOCKS_PER_SEC);
211#endif
212 }
214 if (B != C) SparseMatrix_delete(B);
215
216 {
217#ifdef TIME
218 clock_t start = clock();
219#endif
220 const bool weightedQ = false;
221 flag = node_distinct_coloring(color_scheme, lightness, weightedQ, C,
222 accuracy, seed, &cdim, &colors);
223 if (flag) goto RETURN;
224#ifdef TIME
225 fprintf(stderr, "cpu for color assignment =%10.3f\n", ((double) (clock() - start))/CLOCKS_PER_SEC);
226#endif
227 }
228
229 if (Verbose)
230 fprintf(stderr, "The edge conflict graph has %" PRISIZE_T " nodes and %" PRISIZE_T
231 " edges\n", C->m, C->nz);
232
233 attach_edge_colors(g, cdim, colors);
234
235 RETURN:
238 free(colors);
239 free(x);
240 if (xsplines){
241 for (int i = 0; i < ne; i++){
242 free(xsplines[i]);
243 }
244 free(xsplines);
245 }
246 return g;
247}
SparseMatrix SparseMatrix_import_dot(Agraph_t *g, double **x, int format)
Definition DotIO.c:91
void attach_edge_colors(Agraph_t *g, size_t dim, double *colors)
Definition DotIO.c:60
int Import_dot_splines(Agraph_t *g, int *ne, char ***xsplines)
Definition DotIO.c:190
SparseMatrix SparseMatrix_new(size_t m, int n, size_t nz, int type, int format)
SparseMatrix SparseMatrix_from_coordinate_format(SparseMatrix A)
void SparseMatrix_delete(SparseMatrix A)
@ FORMAT_COORD
#define SparseMatrix_coordinate_form_add_entry(A, irn, jcn, val)
wrap SparseMatrix_coordinate_form_add_entry_ for type safety
@ MATRIX_TYPE_REAL
Agraph_t * edge_distinct_coloring(const char *color_scheme, int *lightness, Agraph_t *g, double angle, double accuracy, int check_edges_with_same_endpoint, int seed)
static int splines_intersect(size_t dim, double cos_critical, int check_edges_with_same_endpoint, char *xsplines1, char *xsplines2)
static long seed
Definition exeval.c:1010
#define A(n, t)
Definition expr.h:76
static bool Verbose
Definition gml2gv.c:26
void free(void *)
node NULL
Definition grammar.y:181
#define B
Definition hierarchy.c:120
double intersection_angle(double *p1, double *p2, double *q1, double *q2)
type-generic dynamically expanding list
#define LIST_AT(list, index)
Definition list.h:172
#define LIST_APPEND(list,...)
Definition list.h:124
#define LIST(type)
Definition list.h:55
#define LIST_SIZE(list)
Definition list.h:80
#define LIST_FREE(list)
Definition list.h:373
static const int dim
int node_distinct_coloring(const char *color_scheme, int *lightness, bool weightedQ, SparseMatrix A0, double accuracy, int seed, size_t *cdim0, double **colors)
#define C
Definition pack.c:32
#define PRISIZE_T
Definition prisize_t.h:25
#define RETURN(v)
Definition strmatch.c:146
graph or subgraph
Definition cgraph.h:424