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