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