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