Graphviz 16.1.1~dev.20261014.0450
Loading...
Searching...
No Matches
edge_bundling.cpp
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 <algorithm>
14#include <common/globals.h>
15#include <common/types.h>
16#include <math.h>
19#include <mingle/ink.h>
20#include <numeric>
21#include <sparse/SparseMatrix.h>
22#include <sparse/clustering.h>
23#include <sparse/general.h>
24#include <string.h>
25#include <time.h>
26#include <util/prisize_t.h>
27#include <vector>
28
29#define SMALL 1.e-10
30
31static double norm(int n, const double *x) {
32 return sqrt(std::inner_product(x, x + n, x, 0.0));
33}
34
35static double sqr_dist(int dim, const double *x, const double *y) {
36 int i;
37 double res = 0;
38 for (i = 0; i < dim; i++)
39 res += (x[i] - y[i]) * (x[i] - y[i]);
40 return res;
41}
42
43static double dist(int dim, const double *x, const double *y) {
44 return sqrt(sqr_dist(dim, x, y));
45}
46
47static pedge pedge_new(int np, int dim, const double *x) {
48 pedge e;
49
50 e.npoints = np;
51 e.dim = dim;
52 e.len = np;
53 e.x.assign(x, &x[dim * e.len]);
54 e.edge_length = dist(dim, &x[0 * dim], &x[(np - 1) * dim]);
55 e.wgt = 1;
56 return e;
57}
58
59pedge pedge_wgt_new(int np, int dim, double *x, double wgt) {
60 pedge e;
61
62 e.npoints = np;
63 e.dim = dim;
64 e.len = np;
65 e.x.assign(x, &x[dim * e.len]);
66 e.edge_length = dist(dim, &x[0 * dim], &x[(np - 1) * dim]);
67 e.wgt = wgt;
68 e.wgts = std::vector<double>(np - 1, wgt);
69 return e;
70}
71
73
74static double edge_compatibility(const pedge &e1, const pedge &e2) {
75 /* two edges are u1->v1, u2->v2.
76 return 1 if two edges are exactly the same, 0 if they are very different.
77 */
78 double dist1, dist2, len1, len2;
79 const int dim = e1.dim;
80 bool flipped = false;
81
82 const double *u1 = e1.x.data();
83 const double *v1 = e1.x.data() + e1.npoints * dim - dim;
84 const double *u2 = e2.x.data();
85 const double *v2 = e2.x.data() + e2.npoints * dim - dim;
86 dist1 = sqr_dist(dim, u1, u2) + sqr_dist(dim, v1, v2);
87 dist2 = sqr_dist(dim, u1, v2) + sqr_dist(dim, v1, u2);
88 if (dist1 > dist2) {
89 std::swap(u2, v2);
90 dist1 = dist2;
91 flipped = true;
92 }
93 len1 = dist(dim, u1, v1);
94 len2 = dist(dim, u2, v2);
95 dist1 = std::max(0.1, dist1 / (len1 + len2 + 0.0001 * dist1));
96 if (flipped) {
97 return -1 / dist1;
98 } else {
99 return 1 / dist1;
100 }
101}
102
103static double edge_compatibility_full(const pedge &e1, const pedge &e2) {
104 /* two edges are u1->v1, u2->v2.
105 return 1 if two edges are exactly the same, 0 if they are very different.
106 This is based on Holten and van Wijk's paper
107 */
108 double dist1, dist2, len1, len2, len;
109 double tmp, ca, cp, cs;
110 int dim = e1.dim, i;
111 bool flipped = false;
112
113 const double *u1 = e1.x.data();
114 const double *v1 = e1.x.data() + e1.npoints * dim - dim;
115 const double *u2 = e2.x.data();
116 const double *v2 = e2.x.data() + e2.npoints * dim - dim;
117 dist1 = sqr_dist(dim, u1, u2) + sqr_dist(dim, v1, v2);
118 dist2 = sqr_dist(dim, u1, v2) + sqr_dist(dim, v1, u2);
119 if (dist1 > dist2) {
120 std::swap(u2, v2);
121 flipped = true;
122 }
123 len1 = std::max(dist(dim, u1, v1), SMALL);
124 len2 = std::max(dist(dim, u2, v2), SMALL);
125 len = 0.5 * (len1 + len2);
126
127 /* angle compatibility */
128 ca = 0;
129 for (i = 0; i < dim; i++)
130 ca += (v1[i] - u1[i]) * (v2[i] - u2[i]);
131 ca = fabs(ca / (len1 * len2));
132 assert(ca > -0.001);
133
134 /* scale compatibility */
135 cs = 2 / (std::max(len1, len2) / len + len / std::min(len1, len2));
136 assert(cs > -0.001 && cs < 1.001);
137
138 /* position compatibility */
139 cp = 0;
140 for (i = 0; i < dim; i++) {
141 tmp = .5 * (v1[i] + u1[i]) - .5 * (v2[i] + u2[i]);
142 cp += tmp * tmp;
143 }
144 cp = sqrt(cp);
145 cp = len / (len + cp);
146 assert(cp > -0.001 && cp < 1.001);
147
148 /* visibility compatibility */
149
150 dist1 = cp * ca * cs;
151 if (flipped) {
152 return -dist1;
153 } else {
154 return dist1;
155 }
156}
157
158static void fprint_rgb(FILE *fp, int r, int g, int b, int alpha) {
159 fprintf(fp, "#%02x%02x%02x%02x", r, g, b, alpha);
160}
161
162void pedge_export_gv(FILE *fp, size_t ne, const std::vector<pedge> &edges) {
163 double maxwgt = 0;
164
165 fprintf(fp, "strict graph{\n");
166 /* points */
167 for (size_t i = 0; i < ne; i++) {
168 const pedge &edge = edges[i];
169 const std::vector<double> &x = edge.x;
170 const int dim = edge.dim;
171 const int sta = 0;
172 const int sto = edge.npoints - 1;
173
174 fprintf(fp, "%" PRISIZE_T " [pos=\"", i);
175 for (int k = 0; k < dim; k++) {
176 if (k != 0)
177 fprintf(fp, ",");
178 fprintf(fp, "%f", x[sta * dim + k]);
179 }
180 fprintf(fp, "\"];\n");
181
182 fprintf(fp, "%" PRISIZE_T " [pos=\"", i + ne);
183 for (int k = 0; k < dim; k++) {
184 if (k != 0)
185 fprintf(fp, ",");
186 fprintf(fp, "%f", x[sto * dim + k]);
187 }
188 fprintf(fp, "\"];\n");
189 }
190
191 /* figure out max number of bundled original edges in a pedge */
192 for (size_t i = 0; i < ne; i++) {
193 const pedge &edge = edges[i];
194 if (!edge.wgts.empty()) {
195 for (int j = 0; j < edge.npoints - 1; j++) {
196 maxwgt = std::max(maxwgt, edge.wgts[j]);
197 }
198 }
199 }
200
201 /* spline and colors */
202 for (size_t i = 0; i < ne; i++) {
203 fprintf(fp, "%" PRISIZE_T " -- %" PRISIZE_T " [pos=\"", i, i + ne);
204 const pedge &edge = edges[i];
205 const std::vector<double> &x = edge.x;
206 const int dim = edge.dim;
207 /* splines */
208 for (int j = 0; j < edge.npoints; j++) {
209 if (j != 0) {
210 int mm = 3;
211 fprintf(fp, " ");
212 /* there are ninterval+1 points, add 3*ninterval+2 points, get rid of
213 internal ninternal-1 points, make into 3*ninterval+4 points so that
214 gviz spline rendering can work */
215 const double *tt;
216 const double tt1[] = {0.15, 0.5, 0.85};
217 const double tt2[] = {0.15, 0.4, 0.6, 0.85};
218 if (j == 1 || j == edge.npoints - 1) {
219 // every interval gets 3 points inserted except the first and last one
220 tt = tt2;
221 mm = 4;
222 } else {
223 tt = tt1;
224 }
225 for (int kk = 1; kk <= mm; kk++) {
226 const double t = tt[kk - 1];
227 for (int k = 0; k < dim; k++) {
228 if (k != 0)
229 fprintf(fp, ",");
230 fprintf(fp, "%f",
231 x[(j - 1) * dim + k] * (1 - t) + x[j * dim + k] * t);
232 }
233 fprintf(fp, " ");
234 }
235 }
236 if (j == 0 || j == edge.npoints - 1) {
237 for (int k = 0; k < dim; k++) {
238 if (k != 0)
239 fprintf(fp, ",");
240 fprintf(fp, "%f", x[j * dim + k]);
241 }
242 }
243 }
244 /* colors based on how much bundling */
245 if (!edge.wgts.empty()) {
246 fprintf(fp, "\", wgts=\"");
247 for (int j = 0; j < edge.npoints - 1; j++) {
248 if (j != 0)
249 fprintf(fp, ",");
250 fprintf(fp, "%f", edge.wgts[j]);
251 }
252
253 double len_total0 = 0;
254 fprintf(fp, "\", color=\"");
255 for (int j = 0; j < edge.npoints - 1; j++) {
256 double len = 0;
257 int k;
258 for (k = 0; k < dim; k++) {
259 len += (edge.x[dim * j + k] - edge.x[dim * (j + 1) + k]) *
260 (edge.x[dim * j + k] - edge.x[dim * (j + 1) + k]);
261 }
262 len = sqrt(len / k);
263 len_total0 += len;
264 }
265 for (int j = 0; j < edge.npoints - 1; j++) {
266 double len = 0;
267 int k;
268 for (k = 0; k < dim; k++) {
269 len += (edge.x[dim * j + k] - edge.x[dim * (j + 1) + k]) *
270 (edge.x[dim * j + k] - edge.x[dim * (j + 1) + k]);
271 }
272 len = sqrt(len / k);
273 const double t = edge.wgts[j] / maxwgt;
274 // interpolate between red (t = 1) to blue (t = 0)
275 const int r = 255 * t;
276 const int g = 0;
277 const int b = 255 * (1 - t);
278 if (j != 0)
279 fprintf(fp, ":");
280 fprint_rgb(fp, r, g, b, 85);
281 if (j < edge.npoints - 2)
282 fprintf(fp, ";%f", len / len_total0);
283 }
284 }
285 fprintf(fp, "\"];\n");
286 }
287 fprintf(fp, "}\n");
288}
289
290#ifdef DEBUG
291static void pedge_print(char *comments, const pedge &e) {
292 int i, j, dim;
293 dim = e.dim;
294 fprintf(stderr, "%s", comments);
295 for (i = 0; i < e.npoints; i++) {
296 if (i > 0)
297 fprintf(stderr, ",");
298 fprintf(stderr, "{");
299 for (j = 0; j < dim; j++) {
300 if (j > 0)
301 fprintf(stderr, ",");
302 fprintf(stderr, "%f", e.x[dim * i + j]);
303 }
304 fprintf(stderr, "}");
305 }
306 fprintf(stderr, "\n");
307}
308#endif
309
310void pedge_wgts_realloc(pedge &e, int n) {
311 int i;
312 if (n <= e.npoints)
313 return;
314 e.x.resize(e.dim * n, 0);
315 if (e.wgts.empty()) {
316 e.wgts.resize(n - 1);
317 for (i = 0; i < e.npoints; i++)
318 e.wgts[i] = e.wgt;
319 } else {
320 e.wgts.resize(n - 1);
321 }
322 e.len = n;
323}
324
326 /* double the number of points (more precisely, add a point between two points
327 * in the polyline */
328 int npoints = e.npoints, len = e.len, i, dim = e.dim;
329 int j, ii, ii2, np;
330
331 assert(npoints >= 2);
332 if (npoints * 2 - 1 > len) {
333 len = 3 * npoints;
334 e.x.resize(dim * len, 0);
335 }
336 std::vector<double> &x = e.x;
337
338 for (i = npoints - 1; i >= 0; i--) {
339 ii = 2 * i;
340 for (j = 0; j < dim; j++) {
341 x[dim * ii + j] = x[dim * i + j];
342 }
343 }
344
345 for (i = 0; i < npoints - 1; i++) {
346 ii = 2 * i; /* left and right interpolant of a new point */
347 ii2 = 2 * (i + 1);
348 for (j = 0; j < dim; j++) {
349 x[dim * (2 * i + 1) + j] = 0.5 * (x[dim * ii + j] + x[dim * ii2 + j]);
350 }
351 }
352 e.len = len;
353 np = e.npoints = 2 * e.npoints - 1;
354 e.edge_length = dist(dim, &x.data()[0 * dim], &x.data()[(np - 1) * dim]);
355}
356
357static void edge_tension_force(std::vector<double> &force, const pedge &e) {
358 const std::vector<double> &x = e.x;
359 const int dim = e.dim;
360 const int np = e.npoints;
361 int i, left, right, j;
362 double s;
363
364 /* tension force = ((np-1)*||2x-xleft-xright||)/||e||, so the force is nominal
365 * and unitless
366 */
367 s = (np - 1) / std::max(SMALL, e.edge_length);
368 for (i = 1; i <= np - 2; i++) {
369 left = i - 1;
370 right = i + 1;
371 for (j = 0; j < dim; j++)
372 force[i * dim + j] += s * (x[left * dim + j] - x[i * dim + j]);
373 for (j = 0; j < dim; j++)
374 force[i * dim + j] += s * (x[right * dim + j] - x[i * dim + j]);
375 }
376}
377
378static void edge_attraction_force(double similarity, const pedge &e1,
379 const pedge &e2, std::vector<double> &force) {
380 /* attractive force from x2 applied to x1 */
381 const std::vector<double> &x1 = e1.x, &x2 = e2.x;
382 const int dim = e1.dim;
383 const int np = e1.npoints;
384 const double edge_length = e1.edge_length;
385
386 assert(e1.npoints == e2.npoints);
387
388 /* attractive force = 1/d where d = D/||e1|| is the relative distance, D is
389 the distance between e1 and e2. so the force is nominal and unitless
390 */
391 if (similarity > 0) {
392 const double s = similarity * edge_length;
393 for (int i = 1; i <= np - 2; i++) {
394 double dist = sqr_dist(dim, &x1.data()[i * dim], &x2.data()[i * dim]);
395 if (dist < SMALL)
396 dist = SMALL;
397 const double ss = s / (dist + 0.1 * edge_length * sqrt(dist));
398 for (int j = 0; j < dim; j++)
399 force[i * dim + j] += ss * (x2[i * dim + j] - x1[i * dim + j]);
400 }
401 } else { /* clip e2 */
402 const double s = -similarity * edge_length;
403 for (int i = 1; i <= np - 2; i++) {
404 double dist =
405 sqr_dist(dim, &x1.data()[i * dim], &x2.data()[(np - 1 - i) * dim]);
406 if (dist < SMALL)
407 dist = SMALL;
408 const double ss = s / (dist + 0.1 * edge_length * sqrt(dist));
409 for (int j = 0; j < dim; j++)
410 force[i * dim + j] +=
411 ss * (x2[(np - 1 - i) * dim + j] - x1[i * dim + j]);
412 }
413 }
414}
415
417 std::vector<pedge> &edges, int maxit,
418 double step0, double K) {
419 int i, j, ne = A->n, k;
420 int *ia = A->ia, *ja = A->ja, iter = 0;
421 double *a = (double *)A->a;
422 const int np = edges[0].npoints, dim = edges[0].dim;
423 double step = step0;
424 double fnorm_a, fnorm_t, edge_length, start;
425
426 if (Verbose > 1)
427 fprintf(stderr,
428 "total interaction pairs = %" PRISIZE_T " out of %" PRISIZE_T
429 ", avg neighbors per edge = %f\n",
430 A->nz, A->m * A->m, (double)A->nz / (double)A->m);
431
432 std::vector<double> force_t(dim * np);
433 std::vector<double> force_a(dim * np);
434 while (step > 0.001 && iter < maxit) {
435 start = clock();
436 iter++;
437 for (i = 0; i < ne; i++) {
438 for (j = 0; j < dim * np; j++) {
439 force_t[j] = 0.;
440 force_a[j] = 0.;
441 }
442 pedge &e1 = edges[i];
443 std::vector<double> &x = e1.x;
444 edge_tension_force(force_t, e1);
445 for (j = ia[i]; j < ia[i + 1]; j++) {
446 const pedge &e2 = edges[ja[j]];
447 edge_attraction_force(a[j], e1, e2, force_a);
448 }
449 fnorm_t = std::max(SMALL, norm(dim * (np - 2), &force_t.data()[dim]));
450 fnorm_a = std::max(SMALL, norm(dim * (np - 2), &force_a.data()[dim]));
451 edge_length = e1.edge_length;
452
453 for (j = 1; j <= np - 2; j++) {
454 for (k = 0; k < dim; k++) {
455 x[j * dim + k] += step * edge_length *
456 (force_t[j * dim + k] + K * force_a[j * dim + k]) /
457 hypot(fnorm_t, K * fnorm_a);
458 }
459 }
460 }
461 step = step * 0.9;
462 if (Verbose > 1)
463 fprintf(stderr, "iter ==== %d cpu = %f npoints = %d\n", iter,
464 (double)(clock() - start) / CLOCKS_PER_SEC, np - 2);
465 }
466}
467
468static void modularity_ink_bundling(int dim, size_t ne, SparseMatrix B,
469 std::vector<pedge> &edges,
470 double angle_param, double angle) {
471 int *assignment = nullptr, nclusters;
472 double modularity;
473 int *clusterp, *clusters;
475 point_t meet1, meet2;
476 double ink0, ink1;
477 int j, jj;
478
479 SparseMatrix BB;
480
481 /* B may contain negative entries */
482 BB = SparseMatrix_copy(B);
483 BB = SparseMatrix_apply_fun(BB, fabs);
484 modularity_clustering(BB, true, 0, &nclusters, &assignment, &modularity);
486
487 if (Verbose > 1)
488 fprintf(stderr, "there are %d clusters, modularity = %f\n", nclusters,
489 modularity);
490
492
493 for (size_t i = 0; i < ne; i++) {
494 jj = assignment[i];
495 SparseMatrix_coordinate_form_add_entry(C, jj, (int)i, nullptr);
496 }
497
500 clusterp = D->ia;
501 clusters = D->ja;
502 for (int i = 0; i < nclusters; i++) {
503 ink1 = ink(edges, clusterp[i + 1] - clusterp[i], &clusters[clusterp[i]],
504 &ink0, &meet1, &meet2, angle_param, angle);
505 if (Verbose > 1)
506 fprintf(stderr, "nedges = %d ink0 = %f, ink1 = %f\n",
507 clusterp[i + 1] - clusterp[i], ink0, ink1);
508 if (ink1 < ink0) {
509 for (j = clusterp[i]; j < clusterp[i + 1]; j++) {
510 /* make this edge 5 points, insert two meeting points at 1 and 2, make 3
511 * the last point */
512 pedge_double(edges[clusters[j]]);
513 pedge_double(edges[clusters[j]]);
514 pedge &e = edges[clusters[j]];
515 e.x[1 * dim] = meet1.x;
516 e.x[1 * dim + 1] = meet1.y;
517 e.x[2 * dim] = meet2.x;
518 e.x[2 * dim + 1] = meet2.y;
519 e.x[3 * dim] = e.x[4 * dim];
520 e.x[3 * dim + 1] = e.x[4 * dim + 1];
521 e.npoints = 4;
522 }
523 }
524 }
526}
527
529 const std::vector<pedge> &edges,
530 int compatibility_method, double tol) {
531 /* go through the links and make sure edges are compatible */
533 int *ia, *ja, j, jj;
534 double start;
535 double dist;
536
538 ia = A->ia;
539 ja = A->ja;
540 start = clock();
541 for (size_t i = 0; i < ne; i++) {
542 for (j = ia[i]; j < ia[i + 1]; j++) {
543 jj = ja[j];
544 if ((int)i == jj)
545 continue;
546 if (compatibility_method == COMPATIBILITY_DIST) {
547 dist = edge_compatibility_full(edges[i], edges[jj]);
548 } else if (compatibility_method == COMPATIBILITY_FULL) {
549 dist = edge_compatibility(edges[i], edges[jj]);
550 }
551
552 if (fabs(dist) > tol) {
555 }
556 }
557 }
560 B = C;
561 if (Verbose > 1)
562 fprintf(stderr, "edge compatibilitu time = %f\n",
563 ((double)(clock() - start)) / CLOCKS_PER_SEC);
564 return B;
565}
566
567std::vector<pedge> edge_bundling(SparseMatrix A0, int dim,
568 const std::vector<double> &x, int maxit_outer,
569 double K, int method, int nneighbor,
570 int compatibility_method, int max_recursion,
571 double angle_param, double angle) {
572 /* bundle edges.
573 A: edge graph
574 x: edge i is at {p,q},
575 . where p = x[2*dim*i : 2*dim*i+dim-1]
576 . and q = x[2*dim*i+dim : 2*dim*i+2*dim-1]
577 maxit_outer: max outer iteration for force directed bundling. Every outer
578 iter subdivide each edge segment into 2. K: nominal edge length in force
579 directed bundling method: which method to use. nneighbor: number of
580 neighbors to be used in forming nearest neighbor graph. Used only in
581 agglomerative method compatibility_method: which method to use to calculate
582 compatibility. Used only in force directed. max_recursion: used only in
583 agglomerative method. Specify how many level of recursion to do to bundle
584 bundled edges again
585
586 */
587 const size_t ne = A0->m;
588 SparseMatrix A = A0, B = nullptr;
589 double tol = 0.001;
590 int k;
591 double step0 = 0.1, start = 0.0;
592 int maxit = 10;
593
594 assert((size_t)A->n == ne);
595 std::vector<pedge> edges;
596 edges.reserve(ne);
597
598 for (size_t i = 0; i < ne; i++) {
599 edges.emplace_back(pedge_new(2, dim, &x.data()[dim * 2 * (int)i]));
600 }
601
602 A = SparseMatrix_symmetrize(A0, true);
603
604 if (Verbose)
605 start = clock();
606 if (method == METHOD_INK) {
607
608 /* go through the links and make sure edges are compatible */
609 B = check_compatibility(A, ne, edges, compatibility_method, tol);
610
611 modularity_ink_bundling(dim, ne, B, edges, angle_param, angle);
612
613 } else if (method == METHOD_INK_AGGLOMERATE) {
614 /* plan: merge a node with its neighbors if doing so improve. Form
615 * coarsening graph, repeat until no more ink saving */
616 agglomerative_ink_bundling(dim, A, edges, nneighbor, max_recursion,
617 angle_param, angle);
618 } else if (method == METHOD_FD) { /* FD method */
619
620 /* go through the links and make sure edges are compatible */
621 B = check_compatibility(A, ne, edges, compatibility_method, tol);
622
623 for (k = 0; k < maxit_outer; k++) {
624 for (size_t i = 0; i < ne; i++) {
625 pedge_double(edges[i]);
626 }
627 step0 /= 2;
628 force_directed_edge_bundling(B, edges, maxit, step0, K);
629 }
630
631 } else if (method == METHOD_NONE) {
632 ;
633 } else {
634 assert(0);
635 }
636 if (Verbose)
637 fprintf(stderr, "total edge bundling cpu = %f\n",
638 (double)(clock() - start) / CLOCKS_PER_SEC);
639 if (B != A)
641 if (A != A0)
643
644 return edges;
645}
SparseMatrix SparseMatrix_new(size_t m, int n, size_t nz, int type, int format)
SparseMatrix SparseMatrix_from_coordinate_format(SparseMatrix A)
SparseMatrix SparseMatrix_symmetrize(SparseMatrix A, bool pattern_symmetric_only)
void SparseMatrix_delete(SparseMatrix A)
SparseMatrix SparseMatrix_copy(SparseMatrix A)
SparseMatrix SparseMatrix_apply_fun(SparseMatrix A, double(*fun)(double x))
@ MATRIX_TYPE_REAL
@ MATRIX_TYPE_PATTERN
@ FORMAT_COORD
#define SparseMatrix_coordinate_form_add_entry(A, irn, jcn, val)
wrap SparseMatrix_coordinate_form_add_entry_ for type safety
void agglomerative_ink_bundling(int dim, SparseMatrix A, std::vector< pedge > &edges, int nneighbor, int MAX_RECURSE_LEVEL, double angle_param, double angle)
#define right(i)
Definition closest.c:74
void modularity_clustering(SparseMatrix A, bool inplace, int ncluster_target, int *nclusters, int **assignment, double *modularity)
Definition clustering.c:343
#define left
Definition dthdr.h:12
#define SMALL
pedge pedge_wgt_new(int np, int dim, double *x, double wgt)
static SparseMatrix check_compatibility(SparseMatrix A, size_t ne, const std::vector< pedge > &edges, int compatibility_method, double tol)
static void force_directed_edge_bundling(SparseMatrix A, std::vector< pedge > &edges, int maxit, double step0, double K)
void pedge_wgts_realloc(pedge &e, int n)
static void edge_attraction_force(double similarity, const pedge &e1, const pedge &e2, std::vector< double > &force)
static void fprint_rgb(FILE *fp, int r, int g, int b, int alpha)
std::vector< pedge > edge_bundling(SparseMatrix A0, int dim, const std::vector< double > &x, int maxit_outer, double K, int method, int nneighbor, int compatibility_method, int max_recursion, double angle_param, double angle)
static double norm(int n, const double *x)
static void edge_tension_force(std::vector< double > &force, const pedge &e)
static void modularity_ink_bundling(int dim, size_t ne, SparseMatrix B, std::vector< pedge > &edges, double angle_param, double angle)
static double edge_compatibility(const pedge &e1, const pedge &e2)
void pedge_double(pedge &e)
static double edge_compatibility_full(const pedge &e1, const pedge &e2)
static double sqr_dist(int dim, const double *x, const double *y)
void pedge_export_gv(FILE *fp, size_t ne, const std::vector< pedge > &edges)
static double dist(int dim, const double *x, const double *y)
void pedge_delete(pedge &)
static pedge pedge_new(int np, int dim, const double *x)
@ METHOD_FD
@ METHOD_NONE
@ METHOD_INK
@ METHOD_INK_AGGLOMERATE
@ COMPATIBILITY_FULL
@ COMPATIBILITY_DIST
#define A(n, t)
Definition expr.h:76
static double len(glCompPoint p)
Definition glutils.c:138
static bool Verbose
Definition gml2gv.c:26
edge
Definition gmlparse.y:246
#define B
Definition hierarchy.c:120
#define D
Definition hierarchy.c:122
double ink(const std::vector< pedge > &edges, int numEdges, int *pick, double *ink0, point_t *meet1, point_t *meet2, double angle_param, double angle)
Definition ink.cpp:227
double ink1(const pedge &e)
Definition ink.cpp:308
static const int dim
#define C
Definition pack.c:33
PATHUTIL_API COORD dist2(Ppoint_t, Ppoint_t)
Definition visibility.c:122
static const int maxit
Definition power.c:18
#define PRISIZE_T
Definition prisize_t.h:25
#define alpha
Definition shapes.c:4034
static const double tol
size_t m
row dimension
std::vector< double > x
coordinates of the npoints poly points. Dimension dim*npoints
double edge_length
double wgt
int npoints
std::vector< double > wgts
Definition ink.h:16
double y
Definition ink.h:17
double x
Definition ink.h:17
graphs, nodes and edges info: Agraphinfo_t, Agnodeinfo_t and Agedgeinfo_t
Definition grammar.c:90
Agnode_t * n
Definition grammar.c:91