Graphviz 14.1.2~dev.20260118.0226
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 v1.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors: Details at https://graphviz.org
9 *************************************************************************/
10
11#include "config.h"
12
13#include <algorithm>
14#include <common/types.h>
15#include <common/globals.h>
16#include <sparse/general.h>
17#include <math.h>
18#include <numeric>
19#include <sparse/SparseMatrix.h>
21#include <time.h>
22#include <sparse/clustering.h>
23#include <mingle/ink.h>
25#include <string.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++) res += (x[i] - y[i])*(x[i] - y[i]);
39 return res;
40}
41
42static double dist(int dim, const double *x, const double *y) {
43 return sqrt(sqr_dist(dim,x,y));
44}
45
46static pedge pedge_new(int np, int dim, const double *x) {
47 pedge e;
48
49 e.npoints = np;
50 e.dim = dim;
51 e.len = np;
52 e.x.assign(x, &x[dim * e.len]);
53 e.edge_length = dist(dim, &x[0 * dim], &x[(np - 1) * dim]);
54 e.wgt = 1;
55 return e;
56
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, int ne, const std::vector<pedge> &edges) {
163 double maxwgt = 0;
164
165 fprintf(fp,"strict graph{\n");
166 /* points */
167 for (int 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, "%d [pos=\"", i);
175 for (int k = 0; k < dim; k++) {
176 if (k != 0) fprintf(fp, ",");
177 fprintf(fp, "%f", x[sta*dim+k]);
178 }
179 fprintf(fp, "\"];\n");
180
181 fprintf(fp, "%d [pos=\"", i + ne);
182 for (int k = 0; k < dim; k++) {
183 if (k != 0) fprintf(fp, ",");
184 fprintf(fp, "%f", x[sto*dim+k]);
185 }
186 fprintf(fp, "\"];\n");
187
188 }
189
190 /* figure out max number of bundled original edges in a pedge */
191 for (int i = 0; i < ne; i++){
192 const pedge &edge = edges[i];
193 if (!edge.wgts.empty()) {
194 for (int j = 0; j < edge.npoints - 1; j++) {
195 maxwgt = std::max(maxwgt, edge.wgts[j]);
196 }
197 }
198 }
199
200 /* spline and colors */
201 for (int i = 0; i < ne; i++){
202 fprintf(fp,"%d -- %d [pos=\"", i, i + ne);
203 const pedge &edge = edges[i];
204 const std::vector<double> &x = edge.x;
205 const int dim = edge.dim;
206 /* splines */
207 for (int j = 0; j < edge.npoints; j++) {
208 if (j != 0) {
209 int mm = 3;
210 fprintf(fp," ");
211 /* there are ninterval+1 points, add 3*ninterval+2 points, get rid of internal ninternal-1 points,
212 make into 3*ninterval+4 points so that gviz spline rendering can work */
213 const double *tt;
214 const double tt1[] = {0.15, 0.5, 0.85};
215 const double tt2[] = {0.15, 0.4, 0.6, 0.85};
216 if (j == 1 || j == edge.npoints - 1) {
217 // every interval gets 3 points inserted except the first and last one
218 tt = tt2;
219 mm = 4;
220 } else {
221 tt = tt1;
222 }
223 for (int kk = 1; kk <= mm; kk++){
224 const double t = tt[kk - 1];
225 for (int k = 0; k < dim; k++) {
226 if (k != 0) fprintf(fp,",");
227 fprintf(fp, "%f", x[(j - 1) * dim + k] * (1 - t) + x[j * dim + k] * t);
228 }
229 fprintf(fp," ");
230 }
231 }
232 if (j == 0 || j == edge.npoints - 1){
233 for (int k = 0; k < dim; k++) {
234 if (k != 0) fprintf(fp,",");
235 fprintf(fp, "%f", x[j*dim+k]);
236 }
237 }
238 }
239 /* colors based on how much bundling */
240 if (!edge.wgts.empty()) {
241 fprintf(fp, "\", wgts=\"");
242 for (int j = 0; j < edge.npoints - 1; j++){
243 if (j != 0) fprintf(fp,",");
244 fprintf(fp, "%f", edge.wgts[j]);
245 }
246
247 double len_total0 = 0;
248 fprintf(fp, "\", color=\"");
249 for (int j = 0; j < edge.npoints - 1; j++){
250 double len = 0;
251 int k;
252 for (k = 0; k < dim; k++){
253 len += (edge.x[dim * j + k] - edge.x[dim * (j + 1) + k]) * (edge.x[dim * j + k] - edge.x[dim * (j + 1) + k]);
254 }
255 len = sqrt(len/k);
256 len_total0 += len;
257 }
258 for (int j = 0; j < edge.npoints - 1; j++) {
259 double len = 0;
260 int k;
261 for (k = 0; k < dim; k++){
262 len += (edge.x[dim * j + k] - edge.x[dim * (j + 1) + k]) * (edge.x[dim * j + k] - edge.x[dim * (j + 1) + k]);
263 }
264 len = sqrt(len/k);
265 const double t = edge.wgts[j] / maxwgt;
266 // interpolate between red (t = 1) to blue (t = 0)
267 const int r = 255 * t;
268 const int g = 0;
269 const int b = 255 * (1 - t);
270 if (j != 0) fprintf(fp,":");
271 fprint_rgb(fp, r, g, b, 85);
272 if (j < edge.npoints - 2) fprintf(fp, ";%f", len / len_total0);
273 }
274
275 }
276 fprintf(fp, "\"];\n");
277
278 }
279 fprintf(fp,"}\n");
280}
281
282#ifdef DEBUG
283static void pedge_print(char *comments, const pedge &e) {
284 int i, j, dim;
285 dim = e.dim;
286 fprintf(stderr,"%s", comments);
287 for (i = 0; i < e.npoints; i++){
288 if (i > 0) fprintf(stderr,",");
289 fprintf(stderr,"{");
290 for (j = 0; j < dim; j++){
291 if (j > 0) fprintf(stderr,",");
292 fprintf(stderr, "%f", e.x[dim * i + j]);
293 }
294 fprintf(stderr,"}");
295 }
296 fprintf(stderr,"\n");
297}
298#endif
299
300void pedge_wgts_realloc(pedge &e, int n) {
301 int i;
302 if (n <= e.npoints)
303 return;
304 e.x.resize(e.dim * n, 0);
305 if (e.wgts.empty()) {
306 e.wgts.resize(n - 1);
307 for (i = 0; i < e.npoints; i++)
308 e.wgts[i] = e.wgt;
309 } else {
310 e.wgts.resize(n - 1);
311 }
312 e.len = n;
313}
314
316 /* double the number of points (more precisely, add a point between two points in the polyline */
317 int npoints = e.npoints, len = e.len, i, dim = e.dim;
318 int j, ii, ii2, np;
319
320 assert(npoints >= 2);
321 if (npoints*2-1 > len){
322 len = 3*npoints;
323 e.x.resize(dim * len, 0);
324 }
325 std::vector<double> &x = e.x;
326
327 for (i = npoints - 1; i >= 0; i--){
328 ii = 2*i;
329 for (j = 0; j < dim; j++){
330 x[dim*ii + j] = x[dim*i + j];
331 }
332 }
333
334 for (i = 0; i < npoints - 1; i++){
335 ii = 2*i;/* left and right interpolant of a new point */
336 ii2 = 2*(i+1);
337 for (j = 0; j < dim; j++){
338 x[dim*(2*i + 1) + j] = 0.5*(x[dim*ii + j] + x[dim*ii2 + j]);
339 }
340 }
341 e.len = len;
342 np = e.npoints = 2 * e.npoints - 1;
343 e.edge_length = dist(dim, &x.data()[0 * dim], &x.data()[(np - 1) * dim]);
344}
345
346static void edge_tension_force(std::vector<double> &force, const pedge &e) {
347 const std::vector<double> &x = e.x;
348 const int dim = e.dim;
349 const int np = e.npoints;
350 int i, left, right, j;
351 double s;
352
353 /* tension force = ((np-1)*||2x-xleft-xright||)/||e||, so the force is nominal and unitless
354 */
355 s = (np - 1) / std::max(SMALL, e.edge_length);
356 for (i = 1; i <= np - 2; i++){
357 left = i - 1;
358 right = i + 1;
359 for (j = 0; j < dim; j++) force[i*dim + j] += s*(x[left*dim + j] - x[i*dim + j]);
360 for (j = 0; j < dim; j++) force[i*dim + j] += s*(x[right*dim + j] - x[i*dim + j]);
361 }
362}
363
364static void edge_attraction_force(double similarity, const pedge &e1,
365 const pedge &e2, std::vector<double> &force) {
366 /* attractive force from x2 applied to x1 */
367 const std::vector<double> &x1 = e1.x, &x2 = e2.x;
368 const int dim = e1.dim;
369 const int np = e1.npoints;
370 const double edge_length = e1.edge_length;
371
372 assert(e1.npoints == e2.npoints);
373
374 /* attractive force = 1/d where d = D/||e1|| is the relative distance, D is the distance between e1 and e2.
375 so the force is nominal and unitless
376 */
377 if (similarity > 0){
378 const double s = similarity * edge_length;
379 for (int i = 1; i <= np - 2; i++){
380 double dist = sqr_dist(dim, &x1.data()[i * dim], &x2.data()[i * dim]);
381 if (dist < SMALL) dist = SMALL;
382 const double ss = s / (dist + 0.1 * edge_length * sqrt(dist));
383 for (int j = 0; j < dim; j++) force[i*dim + j] += ss*(x2[i*dim + j] - x1[i*dim + j]);
384 }
385 } else {/* clip e2 */
386 const double s = -similarity * edge_length;
387 for (int i = 1; i <= np - 2; i++){
388 double dist = sqr_dist(dim, &x1.data()[i * dim], &x2.data()[(np - 1 - i) * dim]);
389 if (dist < SMALL) dist = SMALL;
390 const double ss = s / (dist + 0.1 * edge_length * sqrt(dist));
391 for (int j = 0; j < dim; j++) force[i*dim + j] += ss*(x2[(np - 1 - i)*dim + j] - x1[i*dim + j]);
392 }
393 }
394
395}
396
398 std::vector<pedge> &edges, int maxit,
399 double step0, double K) {
400 int i, j, ne = A->n, k;
401 int *ia = A->ia, *ja = A->ja, iter = 0;
402 double *a = (double*) A->a;
403 const int np = edges[0].npoints, dim = edges[0].dim;
404 double step = step0;
405 double fnorm_a, fnorm_t, edge_length, start;
406
407 if (Verbose > 1)
408 fprintf(stderr, "total interaction pairs = %" PRISIZE_T
409 " out of %d, avg neighbors per edge = %f\n", A->nz, A->m * A->m,
410 (double)A->nz / A->m);
411
412 std::vector<double> force_t(dim * np);
413 std::vector<double> force_a(dim * np);
414 while (step > 0.001 && iter < maxit){
415 start = clock();
416 iter++;
417 for (i = 0; i < ne; i++){
418 for (j = 0; j < dim*np; j++) {
419 force_t[j] = 0.;
420 force_a[j] = 0.;
421 }
422 pedge &e1 = edges[i];
423 std::vector<double> &x = e1.x;
424 edge_tension_force(force_t, e1);
425 for (j = ia[i]; j < ia[i+1]; j++){
426 const pedge &e2 = edges[ja[j]];
427 edge_attraction_force(a[j], e1, e2, force_a);
428 }
429 fnorm_t = std::max(SMALL, norm(dim * (np - 2), &force_t.data()[dim]));
430 fnorm_a = std::max(SMALL, norm(dim * (np - 2), &force_a.data()[dim]));
431 edge_length = e1.edge_length;
432
433 for (j = 1; j <= np - 2; j++){
434 for (k = 0; k < dim; k++) {
435 x[j * dim + k] += step * edge_length
436 * (force_t[j * dim + k] + K * force_a[j * dim+k])
437 / hypot(fnorm_t, K * fnorm_a);
438 }
439 }
440
441 }
442 step = step*0.9;
443 if (Verbose > 1)
444 fprintf(stderr, "iter ==== %d cpu = %f npoints = %d\n", iter, (double)(clock() - start) / CLOCKS_PER_SEC, np - 2);
445 }
446}
447
448static void modularity_ink_bundling(int dim, int ne, SparseMatrix B,
449 std::vector<pedge> &edges,
450 double angle_param, double angle) {
451 int *assignment = NULL, nclusters;
452 double modularity;
453 int *clusterp, *clusters;
455 point_t meet1, meet2;
456 double ink0, ink1;
457 int i, j, jj;
458
459 SparseMatrix BB;
460
461 /* B may contain negative entries */
462 BB = SparseMatrix_copy(B);
463 BB = SparseMatrix_apply_fun(BB, fabs);
464 modularity_clustering(BB, true, 0, &nclusters, &assignment, &modularity);
466
467 if (Verbose > 1) fprintf(stderr, "there are %d clusters, modularity = %f\n",nclusters, modularity);
468
470
471 for (i = 0; i < ne; i++){
472 jj = assignment[i];
474 }
475
478 clusterp = D->ia;
479 clusters = D->ja;
480 for (i = 0; i < nclusters; i++) {
481 ink1 = ink(edges, clusterp[i + 1] - clusterp[i], &clusters[clusterp[i]],
482 &ink0, &meet1, &meet2, angle_param, angle);
483 if (Verbose > 1)
484 fprintf(stderr,"nedges = %d ink0 = %f, ink1 = %f\n",clusterp[i+1] - clusterp[i], ink0, ink1);
485 if (ink1 < ink0){
486 for (j = clusterp[i]; j < clusterp[i+1]; j++){
487 /* make this edge 5 points, insert two meeting points at 1 and 2, make 3 the last point */
488 pedge_double(edges[clusters[j]]);
489 pedge_double(edges[clusters[j]]);
490 pedge &e = edges[clusters[j]];
491 e.x[1 * dim] = meet1.x;
492 e.x[1 * dim + 1] = meet1.y;
493 e.x[2 * dim] = meet2.x;
494 e.x[2 * dim + 1] = meet2.y;
495 e.x[3 * dim] = e.x[4 * dim];
496 e.x[3 * dim + 1] = e.x[4 * dim + 1];
497 e.npoints = 4;
498 }
499 }
500 }
502}
503
505 const std::vector<pedge> &edges,
506 int compatibility_method, double tol) {
507 /* go through the links and make sure edges are compatible */
509 int *ia, *ja, i, j, jj;
510 double start;
511 double dist;
512
514 ia = A->ia; ja = A->ja;
515 start = clock();
516 for (i = 0; i < ne; i++){
517 for (j = ia[i]; j < ia[i+1]; j++){
518 jj = ja[j];
519 if (i == jj) continue;
520 if (compatibility_method == COMPATIBILITY_DIST){
521 dist = edge_compatibility_full(edges[i], edges[jj]);
522 } else if (compatibility_method == COMPATIBILITY_FULL){
523 dist = edge_compatibility(edges[i], edges[jj]);
524 }
525
526 if (fabs(dist) > tol){
529 }
530 }
531 }
534 B = C;
535 if (Verbose > 1)
536 fprintf(stderr, "edge compatibilitu time = %f\n",((double) (clock() - start))/CLOCKS_PER_SEC);
537 return B;
538}
539
540std::vector<pedge> edge_bundling(SparseMatrix A0, int dim,
541 const std::vector<double> &x, int maxit_outer,
542 double K, int method, int nneighbor,
543 int compatibility_method, int max_recursion,
544 double angle_param, double angle) {
545 /* bundle edges.
546 A: edge graph
547 x: edge i is at {p,q},
548 . where p = x[2*dim*i : 2*dim*i+dim-1]
549 . and q = x[2*dim*i+dim : 2*dim*i+2*dim-1]
550 maxit_outer: max outer iteration for force directed bundling. Every outer iter subdivide each edge segment into 2.
551 K: nominal edge length in force directed bundling
552 method: which method to use.
553 nneighbor: number of neighbors to be used in forming nearest neighbor graph. Used only in agglomerative method
554 compatibility_method: which method to use to calculate compatibility. Used only in force directed.
555 max_recursion: used only in agglomerative method. Specify how many level of recursion to do to bundle bundled edges again
556
557 */
558 int ne = A0->m;
559 SparseMatrix A = A0, B = NULL;
560 int i;
561 double tol = 0.001;
562 int k;
563 double step0 = 0.1, start = 0.0;
564 int maxit = 10;
565
566 assert(A->n == ne);
567 std::vector<pedge> edges;
568 edges.reserve(ne);
569
570 for (i = 0; i < ne; i++){
571 edges.emplace_back(pedge_new(2, dim, &x.data()[dim * 2 * i]));
572 }
573
574 A = SparseMatrix_symmetrize(A0, true);
575
576
577
578 if (Verbose) start = clock();
579 if (method == METHOD_INK){
580
581 /* go through the links and make sure edges are compatible */
582 B = check_compatibility(A, ne, edges, compatibility_method, tol);
583
584 modularity_ink_bundling(dim, ne, B, edges, angle_param, angle);
585
586 } else if (method == METHOD_INK_AGGLOMERATE){
587 /* plan: merge a node with its neighbors if doing so improve. Form coarsening graph, repeat until no more ink saving */
588 agglomerative_ink_bundling(dim, A, edges, nneighbor, max_recursion,
589 angle_param, angle);
590 } else if (method == METHOD_FD){/* FD method */
591
592 /* go through the links and make sure edges are compatible */
593 B = check_compatibility(A, ne, edges, compatibility_method, tol);
594
595
596 for (k = 0; k < maxit_outer; k++){
597 for (i = 0; i < ne; i++){
598 pedge_double(edges[i]);
599 }
600 step0 /= 2;
601 force_directed_edge_bundling(B, edges, maxit, step0, K);
602 }
603
604 } else if (method == METHOD_NONE){
605 ;
606 } else {
607 assert(0);
608 }
609 if (Verbose)
610 fprintf(stderr, "total edge bundling cpu = %f\n", (double)(clock() - start) / CLOCKS_PER_SEC);
611 if (B != A) SparseMatrix_delete(B);
612 if (A != A0) SparseMatrix_delete(A);
613
614 return edges;
615}
SparseMatrix SparseMatrix_from_coordinate_format(SparseMatrix A)
SparseMatrix SparseMatrix_symmetrize(SparseMatrix A, bool pattern_symmetric_only)
SparseMatrix SparseMatrix_coordinate_form_add_entry(SparseMatrix A, int irn, int jcn, const void *val)
void SparseMatrix_delete(SparseMatrix A)
SparseMatrix SparseMatrix_copy(SparseMatrix A)
SparseMatrix SparseMatrix_apply_fun(SparseMatrix A, double(*fun)(double x))
SparseMatrix SparseMatrix_new(int m, int n, size_t nz, int type, int format)
@ MATRIX_TYPE_REAL
@ MATRIX_TYPE_PATTERN
@ FORMAT_COORD
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
static SparseMatrix check_compatibility(SparseMatrix A, int ne, const std::vector< pedge > &edges, int compatibility_method, double tol)
#define SMALL
pedge pedge_wgt_new(int np, int dim, double *x, double wgt)
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)
static void modularity_ink_bundling(int dim, int ne, SparseMatrix B, std::vector< pedge > &edges, double angle_param, double angle)
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)
void pedge_export_gv(FILE *fp, int ne, const std::vector< pedge > &edges)
static void edge_tension_force(std::vector< double > &force, const pedge &e)
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)
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:244
node NULL
Definition grammar.y:181
#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:228
double ink1(const pedge &e)
Definition ink.cpp:309
static const int dim
#define C
Definition pack.c:32
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:4058
static const double tol
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