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