1 /* $Id$Revision: */
2 /* vim:set shiftwidth=4 ts=8: */
3
4 /*************************************************************************
5 * Copyright (c) 2011 AT&T Intellectual Property
6 * All rights reserved. This program and the accompanying materials
7 * are made available under the terms of the Eclipse Public License v1.0
8 * which accompanies this distribution, and is available at
9 * http://www.eclipse.org/legal/epl-v10.html
10 *
11 * Contributors: See CVS logs. Details at http://www.graphviz.org/
12 *************************************************************************/
13
14 #define STANDALONE
15 #include "SparseMatrix.h"
16 #include "general.h"
17 #include "QuadTree.h"
18 #include "string.h"
19 /* #include "types.h" */
20 #include <cgraph.h>
21 #include "make_map.h"
22 /* #include "ps.h" */
23 #include "stress_model.h"
24 #include "country_graph_coloring.h"
25 #include "colorutil.h"
26 #include "delaunay.h"
27
28 #ifdef SINGLE
29 #define REAL float
30 #else /* not SINGLE */
31 #define REAL double
32 #endif /* not SINGLE */
33 /* #include "triangle.h" */
34
35 #include "lab.h"
36 #include "node_distinct_coloring.h"
37
map_palette_optimal_coloring(char * color_scheme,char * lightness,SparseMatrix A0,real accuracy,int seed,float ** rgb_r,float ** rgb_g,float ** rgb_b)38 void map_palette_optimal_coloring(char *color_scheme, char *lightness, SparseMatrix A0, real accuracy, int seed,
39 float **rgb_r, float **rgb_g, float **rgb_b){
40 /*
41 for a graph A, get a distinctive color of its nodes so that the color distanmce among all nodes are maximized. Here
42 color distance on a node is defined as the minimum of color differences between a node and its neighbors.
43 accuracy is the threshold given so that when finding the coloring for each node, the optimal is
44 with in "accuracy" of the true global optimal.
45 color_scheme: rgb, gray, lab, or one of the color palettes in color_palettes.h, or a list of hex rgb colors separaterd by comma like "#ff0000,#00ff00"
46 lightness: of the form 0,70, specifying the range of lightness of LAB color. Ignored if scheme is not COLOR_LAB.
47 . if NULL, 0,70 is assumed
48 A: the graph of n nodes
49 accuracy: how accurate to find the optimal
50 cdim: dimension of the color space
51 seed: random_seed. If negative, consider -seed as the number of random start iterations
52 rgb_r, rgb_g, rgb_b: float array of length A->m + 1, which contains color for each country. 1-based
53 */
54
55 /*color: On input an array of size n*cdim, if NULL, will be allocated. On exit the final color assignment for node i is [cdim*i,cdim*(i+1)), in RGB (between 0 to 1)
56 color_diff: the minuimum color difference across all edges
57 color_diff_sum: the sum of min color dfference across all nodes
58 */
59 real *colors = NULL, color_diff, color_diff_sum;
60 int flag;
61 int n = A0->m, i, cdim;
62
63 SparseMatrix A;
64 int weightedQ = TRUE;
65 int iter_max = 100;
66
67 {real *dist = NULL;
68 A = SparseMatrix_symmetrize(A0, FALSE);
69 SparseMatrix_distance_matrix(A, 0, &dist);
70 SparseMatrix_delete(A);
71 A = SparseMatrix_from_dense(n, n, dist);
72 FREE(dist);
73 A = SparseMatrix_remove_diagonal(A);
74 SparseMatrix_export(stdout, A);
75 }
76
77 // A = SparseMatrix_multiply(A0, A0);
78 node_distinct_coloring(color_scheme, lightness, weightedQ, A, accuracy, iter_max, seed, &cdim, &colors, &color_diff, &color_diff_sum, &flag);
79
80 if (A != A0){
81 SparseMatrix_delete(A);
82 }
83 *rgb_r = MALLOC(sizeof(float)*(n+1));
84 *rgb_g = MALLOC(sizeof(float)*(n+1));
85 *rgb_b = MALLOC(sizeof(float)*(n+1));
86
87 for (i = 0; i < n; i++){
88 (*rgb_r)[i+1] = (float) colors[cdim*i];
89 (*rgb_g)[i+1] = (float) colors[cdim*i + 1];
90 (*rgb_b)[i+1] = (float) colors[cdim*i + 2];
91 }
92 FREE(colors);
93
94 }
95
map_optimal_coloring(int seed,SparseMatrix A,float * rgb_r,float * rgb_g,float * rgb_b)96 void map_optimal_coloring(int seed, SparseMatrix A, float *rgb_r, float *rgb_g, float *rgb_b){
97 int *p = NULL;
98 float *u = NULL;
99 int n = A->m;
100 int i;
101 real norm1;
102
103 country_graph_coloring(seed, A, &p, &norm1);
104
105 rgb_r++; rgb_b++; rgb_g++;/* seems necessary, but need to better think about cases when clusters are not contigous */
106 vector_float_take(n, rgb_r, n, p, &u);
107 for (i = 0; i < n; i++) rgb_r[i] = u[i];
108 vector_float_take(n, rgb_g, n, p, &u);
109 for (i = 0; i < n; i++) rgb_g[i] = u[i];
110 vector_float_take(n, rgb_b, n, p, &u);
111 for (i = 0; i < n; i++) rgb_b[i] = u[i];
112 FREE(u);
113
114 }
115
get_poly_id(int ip,SparseMatrix point_poly_map)116 static int get_poly_id(int ip, SparseMatrix point_poly_map){
117 return point_poly_map->ja[point_poly_map->ia[ip]];
118 }
119
improve_contiguity(int n,int dim,int * grouping,SparseMatrix poly_point_map,real * x,SparseMatrix graph,real * label_sizes)120 void improve_contiguity(int n, int dim, int *grouping, SparseMatrix poly_point_map, real *x, SparseMatrix graph, real *label_sizes){
121 /*
122 grouping: which group each of the vertex belongs to
123 poly_point_map: a matrix of dimension npolys x (n + nrandom), poly_point_map[i,j] != 0 if polygon i contains the point j.
124 . If j < n, it is the original point, otherwise it is artificial point (forming the rectangle around a label) or random points.
125 */
126 int i, j, *ia, *ja, u, v;
127 //int *ib, *jb;
128 real *a;
129 SparseMatrix point_poly_map, D;
130 real dist;
131 int nbad = 0, flag;
132 int maxit = 10;
133 real tol = 0.001;
134
135 D = SparseMatrix_get_real_adjacency_matrix_symmetrized(graph);
136
137 assert(graph->m == n);
138 ia = D->ia; ja = D->ja;
139 a = (real*) D->a;
140
141 /* point_poly_map: each row i has only 1 entry at column j, which says that point i is in polygon j */
142 point_poly_map = SparseMatrix_transpose(poly_point_map);
143
144 // ib = point_poly_map->ia;
145 // jb = point_poly_map->ja;
146
147
148 for (i = 0; i < n; i++){
149 u = i;
150 for (j = ia[i]; j < ia[i+1]; j++){
151 v = ja[j];
152 dist = distance_cropped(x, dim, u, v);
153 /*
154 if ((grouping[u] != grouping[v]) || (get_poly_id(u, point_poly_map) == get_poly_id(v, point_poly_map))){
155 a[j] = 1.1*dist;
156 } else {
157 nbad++;
158 a[j] = 0.9*dist;
159 }
160 */
161 if (grouping[u] != grouping[v]){
162 a[j] = 1.1*dist;
163 } else if (get_poly_id(u, point_poly_map) == get_poly_id(v, point_poly_map)){
164 a[j] = dist;
165 } else {
166 nbad++;
167 a[j] = 0.9*dist;
168 }
169
170 }
171 }
172
173 if (Verbose) fprintf(stderr,"ratio (edges among discontiguous regions vs total edges)=%f\n",((real) nbad)/ia[n]);
174 stress_model(dim, D, D, &x, FALSE, maxit, tol, &flag);
175
176 assert(!flag);
177
178 SparseMatrix_delete(D);
179 SparseMatrix_delete(point_poly_map);
180 }
181
182 /*
183 struct color_card{
184 int ncolor;
185 real *rgb;
186 };
187
188 color_card color_card_new(int ncolor, real *rgb){
189 color_card c;
190
191 c->ncolor = ncolor;
192 c->rgb = MALLOC(sizeof(real)*ncolor);
193 for (i = 0; i < ncolor*3; i++){
194 c->rgb[i] = rgb[i];
195 }
196 return c;
197 }
198
199 void color_card_delete(color_card c){
200 FREE(c->rgb);
201 }
202
203 color_card_blend(color_card c, real x){
204 real c1[3], c2[3];
205 int ista, isto;
206 if (x > 1) x = 1;
207 if (x < 0) x = 0;
208 ista = x*(ncolor-1);
209
210 }
211
212 */
213
214 struct Triangle {
215 int vertices[3];/* 3 points */
216 real center[2]; /* center of the triangle */
217 };
218
normal(real v[],real normal[])219 static void normal(real v[], real normal[]){
220 if (v[0] == 0){
221 normal[0] = 1; normal[1] = 0;
222 } else {
223 normal[0] = -v[1];
224 normal[1] = v[0];
225 }
226 return;
227 }
228
229
230
triangle_center(real x[],real y[],real z[],real c[])231 static void triangle_center(real x[], real y[], real z[], real c[]){
232 /* find the "center" c, which is the intersection of the 3 vectors that are normal to each
233 of the edges respectively, and which passes through the center of the edges respectively
234 center[{x_, y_, z_}] := Module[
235 {xy = 0.5*(x + y), yz = 0.5*(y + z), zx = 0.5*(z + x), nxy, nyz,
236 beta, cen},
237 nxy = normal[y - x];
238 nyz = normal[y - z];
239 beta = (y-x).(xy - yz)/(nyz.(y-x));
240 cen = yz + beta*nyz;
241 Graphics[{Line[{x, y, z, x}], Red, Point[cen], Line[{cen, xy}],
242 Line[{cen, yz}], Green, Line[{cen, zx}]}]
243
244 ]
245 */
246 real xy[2], yz[2], nxy[2], nyz[2], ymx[2], ymz[2], beta, bot;
247 int i;
248
249 for (i = 0; i < 2; i++) ymx[i] = y[i] - x[i];
250 for (i = 0; i < 2; i++) ymz[i] = y[i] - z[i];
251 for (i = 0; i < 2; i++) xy[i] = 0.5*(x[i] + y[i]);
252 for (i = 0; i < 2; i++) yz[i] = 0.5*(y[i] + z[i]);
253
254
255 normal(ymx, nxy);
256 normal(ymz, nyz);
257 bot = nyz[0]*(x[0]-y[0])+nyz[1]*(x[1]-y[1]);
258 if (bot == 0){/* xy and yz are parallel */
259 c[0] = xy[0]; c[1] = xy[1];
260 return;
261 }
262 beta = ((x[0] - y[0])*(xy[0] - yz[0])+(x[1] - y[1])*(xy[1] - yz[1]))/bot;
263 c[0] = yz[0] + beta*nyz[0];
264 c[1] = yz[1] + beta*nyz[1];
265 return;
266
267 }
268
matrix_add_entry(SparseMatrix A,int i,int j,int val)269 static SparseMatrix matrix_add_entry(SparseMatrix A, int i, int j, int val){
270 int i1 = i, j1 = j;
271 if (i < j) {
272 i1 = j; j1 = i;
273 }
274 A = SparseMatrix_coordinate_form_add_entries(A, 1, &j1, &i1, &val);
275 return SparseMatrix_coordinate_form_add_entries(A, 1, &i1, &j1, &val);
276 }
277
278
279
plot_polys(int use_line,SparseMatrix polys,real * x_poly,int * polys_groups,float * r,float * g,float * b)280 void plot_polys(int use_line, SparseMatrix polys, real *x_poly, int *polys_groups, float *r, float *g, float *b){
281 int i, j, *ia = polys->ia, *ja = polys->ja, *a = (int*) polys->a, npolys = polys->m, nverts = polys->n, ipoly = -1, max_grp,
282 min_grp;
283
284
285 min_grp = max_grp = polys_groups[0];
286 for (i = 0; i < npolys; i++) {
287 max_grp = MAX(polys_groups[i], max_grp);
288 min_grp = MIN(polys_groups[i], min_grp);
289 }
290 if (max_grp == min_grp) max_grp++;
291 if (Verbose) fprintf(stderr,"npolys = %d\n",npolys);
292 printf("Graphics[{");
293 for (i = 0; i < npolys; i++){
294 for (j = ia[i]; j < ia[i+1]; j++){
295 assert(ja[j] < nverts && ja[j] >= 0);
296 if (a[j] != ipoly){/* the first poly, or a hole */
297 ipoly = a[j];
298 if (ipoly != a[0]) printf("}],");
299 if (use_line){
300 printf("Black,");
301 printf("Line[{");
302 } else {
303 /*printf("Hue[%f],",0.6*(polys_groups[i]/(real) (max_grp-min_grp)));*/
304 if (r && g && b){
305 printf("RGBColor[%f,%f,%f],",r[polys_groups[i]], g[polys_groups[i]], b[polys_groups[i]]);
306 } else {
307 printf("Hue[%f],",((polys_groups[i]-min_grp)/(real) (max_grp-min_grp)));
308 }
309 printf("Polygon[{");
310 }
311
312 } else {
313 if (j > ia[i]) printf(",");
314 }
315 printf("{%f,%f}",x_poly[2*ja[j]],x_poly[2*ja[j]+1]);
316 }
317 }
318 printf("}]}]");
319 }
320
321 #if 0
322 void ps_one_poly(psfile_t *f, int use_line, int border, int fill, int close, int is_river, int np, float *xp, float *yp){
323 if (use_line){
324 if (is_river){
325 /*river*/
326 } else {
327 }
328 ps_polygon(f, np, xp, yp, border, fill, close);
329 } else {
330 ps_polygon(f, np, xp, yp, border, fill, close);
331 }
332 }
333
334 void plot_ps_polygons(psfile_t *f, int use_line, SparseMatrix polys, real *x_poly, int *polys_groups){
335 int i, j, *ia = polys->ia, *ja = polys->ja, *a = (int*) polys->a, npolys = polys->m, nverts = polys->n, ipoly,first;
336 int np = 0, maxlen = 0;
337 float *xp, *yp;
338 int border = 0, fill = -1, close = 1;
339 int is_river;
340
341 for (i = 0; i < npolys; i++) maxlen = MAX(maxlen, ia[i+1]-ia[i]);
342
343 xp = MALLOC(sizeof(float)*maxlen);
344 yp = MALLOC(sizeof(float)*maxlen);
345
346 if (Verbose) fprintf(stderr,"npolys = %d\n",npolys);
347 first = ABS(a[0]); ipoly = first + 1;
348 for (i = 0; i < npolys; i++){
349 np = 0;
350 for (j = ia[i]; j < ia[i+1]; j++){
351 assert(ja[j] < nverts && ja[j] >= 0);
352 if (ABS(a[j]) != ipoly){/* the first poly, or a hole */
353 ipoly = ABS(a[j]);
354 is_river = (a[j] < 0);
355 ps_one_poly(f, use_line, border, fill, close, is_river, np, xp, yp);
356 np = 0;/* start a new polygon */
357
358 }
359 xp[np] = x_poly[2*ja[j]]; yp[np++] = x_poly[2*ja[j]+1];
360 }
361 if (use_line) {
362 ps_one_poly(f, use_line, border, fill, close, is_river, np, xp, yp);
363 } else {
364 ps_one_poly(f, use_line, polys_groups[i], polys_groups[i], close, is_river, np, xp, yp);
365 }
366 }
367 FREE(xp);
368 FREE(yp);
369
370 }
371
372 static void plot_line(real *x, real *y){
373 printf("Line[{{%f,%f},{%f,%f}}]", x[0], x[1], y[0], y[1]);
374 }
375 static void plot_voronoi(int n, SparseMatrix A, struct Triangle *T){
376 int *val, i, j, nline = 0;
377 val = (int*) A->a;
378
379 printf("Graphics[{");
380 for (i = 0; i < n; i++){
381 for (j = A->ia[i]; j < A->ia[i+1]; j++){
382 if (j < A->ia[n] - A->ia[0] - 1 && A->ja[j] == A->ja[j+1]){
383 if (nline > 0) printf(",");
384 nline++;
385 plot_line((T)[val[j]].center, (T)[val[j+1]].center);
386 j++;
387 }
388 }
389 }
390 printf("}]");
391 }
392
393
394 void plot_ps_labels(psfile_t *f, int n, int dim, real *x, char **labels, real *width, float *fsz){
395
396 int i;
397
398 for (i = 0; i < n; i++){
399 if (fsz){
400 ps_font(f, NULL, 3*fsz[i]); /* name can be NULL if the current font name is to be used */
401 } else {
402 ps_font(f, NULL, -7); /* name can be NULL if the current font name is to be used */
403 }
404 ps_textc(f, x[i*dim], x[i*dim+1], labels[i], 0);
405 }
406
407 }
408
409 static void plot_ps_edges(psfile_t *f, SparseMatrix A, int dim, real *x){
410 int i, *ia, *ja, n, j;
411 float xx[2], yy[2];
412 n = A->m;
413 ia = A->ia;
414 ja = A->ja;
415 for (i = 0; i < n; i++){
416 for (j = ia[i]; j < ia[i+1]; j++){
417 if (ja[j] == i) continue;
418 xx[0] = x[i*dim];
419 xx[1] = x[ja[j]*dim];
420 yy[0] = x[i*dim+1];
421 yy[1] = x[ja[j]*dim+1];
422 ps_polygon(f, 2, xx, yy, TRUE, -1, FALSE);
423 }
424 }
425 }
426 static void plot_triangles(int n, SparseMatrix A, int dim, real *x){
427 int i, j, ii, jj;
428 printf("Graphics[{Green");
429 for (i = 0; i < n; i++) {
430 for (j = A->ia[i]; j < A->ia[i+1]; j++){
431 ii = i;
432 jj = A->ja[j];
433 if (j < A->ia[n] - A->ia[0] - 1 && A->ja[j] == A->ja[j+1]) j++;
434 printf(",Line[{{%f,%f},{%f,%f}}]", x[ii*dim], x[ii*dim+1], x[jj*dim], x[jj*dim+1]);
435 }
436 }
437 printf("}]");
438 }
439
440 static void poly_bbox(SparseMatrix polys, real *x_poly, real *bbox){
441 /* get the bounding box of a polygon.
442 bbox[0]: xmin
443 bbox[1]: xmax
444 bbox[2]: ymin
445 bbox[3]: ymax
446 */
447 int i, j, *ia = polys->ia, *ja = polys->ja;
448 int npolys = polys->m;
449
450 bbox[0] = bbox[1] = x_poly[2*ja[ia[0]]];
451 bbox[2] = bbox[3] = x_poly[2*ja[ia[0]] + 1];
452
453 for (i = 0; i < npolys; i++){
454 for (j = ia[i]; j < ia[i+1]; j++){
455 bbox[0] = MIN(bbox[0], x_poly[2*ja[j]]);
456 bbox[1] = MAX(bbox[1], x_poly[2*ja[j]]);
457 bbox[2] = MIN(bbox[2], x_poly[2*ja[j]+1]);
458 bbox[3] = MAX(bbox[3], x_poly[2*ja[j]+1]);
459 }
460 }
461 }
462
463 void plot_ps_map(int n, int dim, real *x, SparseMatrix polys, SparseMatrix poly_lines, real line_width, real *x_poly, int *polys_groups, char **labels, real *width,
464 float *fsz, float *r, float *g, float *b, char *plot_label, real *bg_color, SparseMatrix A){
465
466 psfile_t *f;
467 int i;
468 real xmin[2], xmax[2], w = 7, h = 10;
469 real asp;
470 real bbox[4];
471 float pad = 20, label_fsz = 10;
472 int MAX_GRP;
473 int IBG;/*back ground color number */
474 int plot_polyQ = TRUE;
475
476 if (!r || !g || !b) plot_polyQ = FALSE;
477
478 xmin[0] = xmax[0] = x[0];
479 xmin[1] = xmax[1] = x[1];
480
481 for (i = 0; i < n; i++){
482 xmin[0] = MIN(xmin[0], x[i*dim] - width[i*dim]);
483 xmax[0] = MAX(xmax[0], x[i*dim] + width[i*dim]);
484 xmin[1] = MIN(xmin[1], x[i*dim + 1] - width[i*dim+1]);
485 xmax[1] = MAX(xmax[1], x[i*dim + 1] + width[i*dim+1]);
486 }
487
488 if (polys){
489 poly_bbox(polys, x_poly, bbox);
490 xmin[0] = MIN(xmin[0], bbox[0]);
491 xmax[0] = MAX(xmax[0], bbox[1]);
492 xmin[1] = MIN(xmin[1], bbox[2]);
493 xmax[1] = MAX(xmax[1], bbox[3]);
494 }
495
496 if (poly_lines){
497 poly_bbox(poly_lines, x_poly, bbox);
498 xmin[0] = MIN(xmin[0], bbox[0]);
499 xmax[0] = MAX(xmax[0], bbox[1]);
500 xmin[1] = MIN(xmin[1], bbox[2]);
501 xmax[1] = MAX(xmax[1], bbox[3]);
502 }
503
504 pad = .08*MIN(xmax[0] - xmin[0], xmax[1] - xmin[1]);
505 label_fsz = pad/3;
506
507 xmin[0] -= pad;
508 xmax[0] += pad;
509 xmin[1] -= pad;
510 xmax[1] += pad;
511
512
513 if ((xmax[1] - xmin[1]) < 0.001*(xmax[0] - xmin[0])){
514 asp = 0.001;
515 } else {
516 asp = (xmax[1] - xmin[1])/(xmax[0] - xmin[0]);
517 }
518 if (w*asp > h){
519 w = h/asp;
520 } else {
521 h = w*asp;
522 }
523 fprintf(stderr, "asp = %f, w = %f, h = %f\n",asp,w,h);
524
525 /* f = ps_create_autoscale("test.ps", "title", 7, 7, 0);*/
526 f = ps_create_autoscale(NULL, "title", w, h, 0);
527 /*f = ps_create_epsf(NULL, "title", xmin[0], xmin[1], xmax[0] - xmin[0], xmax[1] - xmin[1]);*/
528
529 ps_line_width(f, 0.00001); // line width 1 point
530
531 ps_font(f, NULL, 10); /* name can be NULL if the current font name is to be used */
532
533 MAX_GRP = polys_groups[0];
534
535 for (i = 0; i < polys->m; i++){
536 if (r && g && b) ps_define_color_rgb(f, polys_groups[i], r[polys_groups[i]], g[polys_groups[i]], b[polys_groups[i]]);
537 MAX_GRP = MAX(MAX_GRP, polys_groups[i]);
538 assert(polys_groups[i] < PS_MAX_COLORS && polys_groups[i] >= 0);
539 }
540
541 /* set bg color */
542 IBG = MAX_GRP + 1;
543 assert(MAX_GRP + 1 < PS_MAX_COLORS);
544 if (bg_color) ps_define_color_rgb(f, IBG, bg_color[0], bg_color[1], bg_color[2]);
545
546 ps_color_model(f, PS_COLOR_MODEL_PALETTE);
547 if (bg_color) ps_rect(f, (float) xmin[0], (float) xmin[1], xmax[0] - xmin[0], xmax[1] - xmin[1], -1, IBG);
548
549
550 /* labels */
551 ps_color_model(f, PS_COLOR_MODEL_RGB);
552 ps_font(f, NULL, label_fsz); /* name can be NULL if the current font name is to be used */
553 ps_textc(f, (float)(.5*(xmin[0] + xmax[0])), (float) xmin[1] + pad, plot_label, 0);
554
555 ps_color_model(f, PS_COLOR_MODEL_PALETTE);
556
557 /*polygons */
558 if (plot_polyQ) plot_ps_polygons(f, FALSE, polys, x_poly, polys_groups);
559
560 ps_color_model(f, PS_COLOR_MODEL_RGB);
561 /* polylines*/
562 if (line_width >= 0){
563 ps_line_width(f, (float) line_width);
564 plot_ps_polygons(f, TRUE, poly_lines, x_poly, polys_groups);
565 }
566
567 /* edges*/
568 if (A) plot_ps_edges(f, A, dim, x);
569
570 if (labels) plot_ps_labels(f, n, dim, x, labels, width, fsz);
571
572 ps_done(f);
573
574
575 }
576
577 #endif
578
579
plot_dot_edges(FILE * f,SparseMatrix A,int dim,real * x)580 static void plot_dot_edges(FILE *f, SparseMatrix A, int dim, real *x){
581 int i, *ia, *ja, j;
582
583
584 int n = A->m;
585 ia = A->ia;
586 ja = A->ja;
587 for (i = 0; i < n; i++){
588 for (j = ia[i]; j < ia[i+1]; j++){
589 if (ja[j] == i) continue;
590 fprintf(f,"%d -- %d;\n",i,ja[j]);
591 }
592 }
593 }
594 #if 0
595 static void plot_processing_edges(FILE *f, SparseMatrix A, int dim, real *x){
596 int i, *ia, *ja, j;
597
598 //fprintf(f,"stroke(.5);\n");
599 fprintf(f, "beginLines\n");
600 fprintf(f, "color(125,125,125)\n");
601 int n = A->m;
602 ia = A->ia;
603 ja = A->ja;
604 for (i = 0; i < n; i++){
605 for (j = ia[i]; j < ia[i+1]; j++){
606 if (ja[j] == i) continue;
607 //fprintf(f,"line(%f, %f, %f, %f);\n", x[i*dim], x[i*dim+1], x[ja[j]*dim], x[ja[j]*dim+1]);
608 fprintf(f,"%f %f %f %f\n", x[i*dim], x[i*dim+1], x[ja[j]*dim], x[ja[j]*dim+1]);
609 }
610 }
611 fprintf(f,"endLines\n");
612 }
613 #endif
614
plot_dot_labels(FILE * f,int n,int dim,real * x,char ** labels,real * width,float * fsz)615 void plot_dot_labels(FILE *f, int n, int dim, real *x, char **labels, real *width, float *fsz){
616 int i;
617
618 for (i = 0; i < n; i++){
619 if (fsz){
620 fprintf(f, "%d [label=\"%s\", pos=\"%lf,%lf\", fontsize=%f];\n",i, labels[i], x[i*dim], x[i*dim+1], fsz[i]);
621 } else {
622 fprintf(f, "%d [label=\"%s\", pos=\"%lf,%lf\"];\n",i, labels[i], x[i*dim], x[i*dim+1]);
623 }
624 }
625
626 }
627
628 #if 0
629 void plot_processing_labels(FILE *f, int n, int dim, real *x, char **labels, real *width, float *fsz){
630 int i;
631 // fprintf(f, "PFont myFont; myFont = createFont(\"FFScala\",8); fill(0,0,0);\n");
632 for (i = 0; i < n; i++){
633 if (fsz){
634 // fprintf(f, "textFont(myFont, %f); text(\"%s\", %f, %f);\n", fsz[i], labels[i], x[i*dim], x[i*dim+1]);
635 fprintf(f, "beginText\nfontSize(%f)\ntext(\"%s\")\nposition(%f, %f)\nendText\n", fsz[i], labels[i], x[i*dim], x[i*dim+1]);
636 } else {
637 fprintf(f, "beginText\ntext(\"%s\")\nposition(%f, %f)\nendText\n", labels[i], x[i*dim], x[i*dim+1]);
638 }
639 }
640
641 }
642 #endif
643
dot_polygon(char ** sbuff,int * len,int * len_max,int np,float * xp,float * yp,real line_width,int fill,int close,char * cstring)644 static void dot_polygon(char **sbuff, int *len, int *len_max, int np, float *xp, float *yp, real line_width,
645 int fill, int close, char *cstring){
646 int i;
647 int ret = 0;
648 char buf[10000];
649 char swidth[10000];
650 int len_swidth;
651
652 if (np > 0){
653 /* figure out the size needed */
654 if (fill >= 0){/* poly*/
655 ret += snprintf(buf, sizeof(buf), " c %d -%s C %d -%s P %d ",(int) strlen(cstring), cstring, (int) strlen(cstring), cstring, np);
656 } else {/* line*/
657 assert(line_width >= 0);
658 if (line_width > 0){
659 sprintf(swidth,"%f",line_width);
660 len_swidth = strlen(swidth);
661 sprintf(swidth,"S %d -setlinewidth(%f)",len_swidth+14, line_width);
662 ret += snprintf(buf, sizeof(buf), " c %d -%s %s L %d ",(int) strlen(cstring), cstring, swidth, np);
663 } else {
664 ret += snprintf(buf, sizeof(buf), " c %d -%s L %d ",(int) strlen(cstring), cstring, np);
665 }
666 }
667 for (i = 0; i < np; i++){
668 ret += sprintf(buf, " %f %f",xp[i], yp[i]);
669 }
670
671 if (*len + ret > *len_max - 1){
672 *len_max = *len_max + MAX(100, 0.2*(*len_max)) + ret;
673 *sbuff = REALLOC(*sbuff, *len_max);
674 }
675
676 /* do the actual string */
677 if (fill >= 0){
678 ret = sprintf(&((*sbuff)[*len]), " c %d -%s C %d -%s P %d ",(int) strlen(cstring), cstring, (int) strlen(cstring), cstring, np);
679 } else {
680 if (line_width > 0){
681 sprintf(swidth,"%f",line_width);
682 len_swidth = strlen(swidth);
683 sprintf(swidth,"S %d -setlinewidth(%f)",len_swidth+14, line_width);
684 ret = sprintf(&((*sbuff)[*len]), " c %d -%s %s L %d ",(int) strlen(cstring), cstring, swidth, np);
685 } else {
686 ret = sprintf(&((*sbuff)[*len]), " c %d -%s L %d ",(int) strlen(cstring), cstring, np);
687 }
688 }
689 (*len) += ret;
690 for (i = 0; i < np; i++){
691 assert(*len < *len_max);
692 ret = sprintf(&((*sbuff)[*len]), " %f %f",xp[i], yp[i]);
693 (*len) += ret;
694 }
695
696
697 }
698 }
processing_polygon(FILE * f,int np,float * xp,float * yp,real line_width,int fill,int close,float rr,float gg,float bb)699 static void processing_polygon(FILE *f, int np, float *xp, float *yp, real line_width, int fill, int close,
700 float rr, float gg, float bb){
701 int i;
702
703 if (np > 0){
704 if (fill >= 0){
705 // fprintf(f, "beginShape();\n noStroke(); fill(%f, %f, %f);\n", 255*rr, 255*gg, 255*bb);
706 fprintf(f, "beginPolygons\ncolor(%f, %f, %f)\n", 255*rr, 255*gg, 255*bb);
707 } else {
708 //fprintf(f, "beginShape();\n");
709 fprintf(f, "beginPolylines\n");
710 if (line_width > 0){
711 fprintf(f, "strokeWeight(%f);\n", line_width);
712 }
713 }
714 for (i = 0; i < np; i++){
715 //fprintf(f, "vertex(%f, %f);\n",xp[i], yp[i]);
716 fprintf(f, "%f %f\n",xp[i], yp[i]);
717 }
718 //fprintf(f, "endShape(CLOSE);\n");
719 if (fill >= 0){
720 fprintf(f, "endPolygons\n");
721 } else {
722 fprintf(f, "endPolylines\n");
723 }
724
725 }
726 }
727
dot_one_poly(char ** sbuff,int * len,int * len_max,int use_line,real line_width,int fill,int close,int is_river,int np,float * xp,float * yp,char * cstring)728 void dot_one_poly(char **sbuff, int *len, int *len_max, int use_line, real line_width, int fill, int close, int is_river, int np, float *xp, float *yp, char *cstring){
729 if (use_line){
730 if (is_river){
731 /*river*/
732 } else {
733 }
734 dot_polygon(sbuff, len, len_max, np, xp, yp, line_width, fill, close, cstring);
735 } else {
736 dot_polygon(sbuff, len, len_max, np, xp, yp, line_width, fill, close, cstring);
737 }
738 }
739
processing_one_poly(FILE * f,int use_line,real line_width,int fill,int close,int is_river,int np,float * xp,float * yp,float rr,float gg,float bb)740 void processing_one_poly(FILE *f, int use_line, real line_width, int fill, int close, int is_river, int np, float *xp, float *yp,
741 float rr, float gg, float bb){
742 if (use_line){
743 if (is_river){
744 /*river*/
745 } else {
746 }
747 processing_polygon(f, np, xp, yp, line_width, fill, close, rr, gg, bb);
748 } else {
749 processing_polygon(f, np, xp, yp, line_width, fill, close, rr, gg, bb);
750 }
751 }
752
753
plot_dot_polygons(char ** sbuff,int * len,int * len_max,real line_width,char * line_color,SparseMatrix polys,real * x_poly,int * polys_groups,float * r,float * g,float * b,char * opacity)754 void plot_dot_polygons(char **sbuff, int *len, int *len_max, real line_width, char *line_color, SparseMatrix polys, real *x_poly, int *polys_groups, float *r, float *g, float *b, char *opacity){
755 int i, j, *ia = polys->ia, *ja = polys->ja, *a = (int*) polys->a, npolys = polys->m, nverts = polys->n, ipoly,first;
756 int np = 0, maxlen = 0;
757 float *xp, *yp;
758 int fill = -1, close = 1;
759 int is_river = FALSE;
760 char cstring[] = "#aaaaaaff";
761 int use_line = (line_width >= 0);
762
763 for (i = 0; i < npolys; i++) maxlen = MAX(maxlen, ia[i+1]-ia[i]);
764
765 xp = MALLOC(sizeof(float)*maxlen);
766 yp = MALLOC(sizeof(float)*maxlen);
767
768 if (Verbose) fprintf(stderr,"npolys = %d\n",npolys);
769 first = ABS(a[0]); ipoly = first + 1;
770 for (i = 0; i < npolys; i++){
771 np = 0;
772 for (j = ia[i]; j < ia[i+1]; j++){
773 assert(ja[j] < nverts && ja[j] >= 0);
774 if (ABS(a[j]) != ipoly){/* the first poly, or a hole */
775 ipoly = ABS(a[j]);
776 is_river = (a[j] < 0);
777 if (r && g && b) {
778 rgb2hex(r[polys_groups[i]], g[polys_groups[i]], b[polys_groups[i]], cstring, opacity);
779 }
780 dot_one_poly(sbuff, len, len_max, use_line, line_width, fill, close, is_river, np, xp, yp, cstring);
781 np = 0;/* start a new polygon */
782 }
783 xp[np] = x_poly[2*ja[j]]; yp[np++] = x_poly[2*ja[j]+1];
784 }
785 if (use_line) {
786 dot_one_poly(sbuff, len, len_max, use_line, line_width, fill, close, is_river, np, xp, yp, line_color);
787 } else {
788 /* why set fill to polys_groups[i]?*/
789 //dot_one_poly(sbuff, len, len_max, use_line, polys_groups[i], polys_groups[i], close, is_river, np, xp, yp, cstring);
790 dot_one_poly(sbuff, len, len_max, use_line, -1, 1, close, is_river, np, xp, yp, cstring);
791 }
792 }
793 FREE(xp);
794 FREE(yp);
795
796 }
797
plot_processing_polygons(FILE * f,real line_width,SparseMatrix polys,real * x_poly,int * polys_groups,float * r,float * g,float * b)798 void plot_processing_polygons(FILE *f, real line_width, SparseMatrix polys, real *x_poly, int *polys_groups, float *r, float *g, float *b){
799 int i, j, *ia = polys->ia, *ja = polys->ja, *a = (int*) polys->a, npolys = polys->m, nverts = polys->n, ipoly,first;
800 int np = 0, maxlen = 0;
801 float *xp, *yp;
802 int fill = -1, close = 1;
803 int is_river = FALSE;
804 int use_line = (line_width >= 0);
805 float rr = 0, gg = 0, bb = 0;
806
807 for (i = 0; i < npolys; i++) maxlen = MAX(maxlen, ia[i+1]-ia[i]);
808
809 xp = MALLOC(sizeof(float)*maxlen);
810 yp = MALLOC(sizeof(float)*maxlen);
811
812 if (Verbose) fprintf(stderr,"npolys = %d\n",npolys);
813 first = ABS(a[0]); ipoly = first + 1;
814 for (i = 0; i < npolys; i++){
815 np = 0;
816 for (j = ia[i]; j < ia[i+1]; j++){
817 assert(ja[j] < nverts && ja[j] >= 0);
818 if (ABS(a[j]) != ipoly){/* the first poly, or a hole */
819 ipoly = ABS(a[j]);
820 is_river = (a[j] < 0);
821 if (r && g && b) {
822 rr = r[polys_groups[i]]; gg = g[polys_groups[i]]; bb = b[polys_groups[i]];
823 }
824 processing_one_poly(f, use_line, line_width, fill, close, is_river, np, xp, yp, rr, gg, bb);
825 np = 0;/* start a new polygon */
826 }
827 xp[np] = x_poly[2*ja[j]]; yp[np++] = x_poly[2*ja[j]+1];
828 }
829 if (use_line) {
830 processing_one_poly(f, use_line, line_width, fill, close, is_river, np, xp, yp, rr, gg, bb);
831 } else {
832 /* why set fill to polys_groups[i]?*/
833 processing_one_poly(f, use_line, -1, 1, close, is_river, np, xp, yp, rr, gg, bb);
834 }
835 }
836 FREE(xp);
837 FREE(yp);
838
839 }
840
841
plot_dot_map(Agraph_t * gr,int n,int dim,real * x,SparseMatrix polys,SparseMatrix poly_lines,real line_width,char * line_color,real * x_poly,int * polys_groups,char ** labels,real * width,float * fsz,float * r,float * g,float * b,char * opacity,char * plot_label,real * bg_color,SparseMatrix A,FILE * f)842 void plot_dot_map(Agraph_t* gr, int n, int dim, real *x, SparseMatrix polys, SparseMatrix poly_lines, real line_width, char *line_color, real *x_poly, int *polys_groups, char **labels, real *width,
843 float *fsz, float *r, float *g, float *b, char* opacity, char *plot_label, real *bg_color, SparseMatrix A, FILE* f){
844 /* if graph object exist, we just modify some attributes, otherwise we dump the whole graph */
845 int plot_polyQ = TRUE;
846 char *sbuff;
847 int len = 0, len_max = 1000;
848
849 sbuff = N_NEW(len_max,char);
850
851 if (!r || !g || !b) plot_polyQ = FALSE;
852
853 if (!gr) {
854 fprintf(f, "graph map {\n node [margin = 0 width=0.0001 height=0.00001 shape=plaintext];\n graph [outputorder=edgesfirst, bgcolor=\"#dae2ff\"]\n edge [color=\"#55555515\",fontname=\"Helvetica-Bold\"]\n");
855 } else {
856 agattr(gr, AGNODE, "margin", "0");
857 agattr(gr, AGNODE, "width", "0.0001");
858 agattr(gr, AGNODE, "height", "0.0001");
859 agattr(gr, AGNODE, "shape", "plaintext");
860 agattr(gr, AGNODE, "margin", "0");
861 agattr(gr, AGNODE, "fontname", "Helvetica-Bold");
862 agattr(gr, AGRAPH, "outputorder", "edgesfirst");
863 agattr(gr, AGRAPH, "bgcolor", "#dae2ff");
864 if (!A) agattr(gr, AGEDGE, "style","invis");/* do not plot edges */
865 // agedgeattr(gr, "color", "#55555515");
866 }
867
868 /*polygons */
869 if (plot_polyQ) {
870 if (!gr) fprintf(f,"_background = \"");
871 plot_dot_polygons(&sbuff, &len, &len_max, -1., NULL, polys, x_poly, polys_groups, r, g, b, opacity);
872 }
873
874 /* polylines: line width is set here */
875 if (line_width >= 0){
876 plot_dot_polygons(&sbuff, &len, &len_max, line_width, line_color, poly_lines, x_poly, polys_groups, NULL, NULL, NULL, NULL);
877 }
878 if (!gr) {
879 fprintf(f,"%s",sbuff);
880 fprintf(f,"\"\n");/* close polygons/lines */
881 } else {
882 agattr(gr, AGRAPH, "_background", sbuff);
883 agwrite(gr, f);
884 }
885
886 /* nodes */
887 if (!gr && labels) plot_dot_labels(f, n, dim, x, labels, width, fsz);
888 /* edges */
889 if (!gr && A) plot_dot_edges(f, A, dim, x);
890
891 /* background color + plot label?*/
892
893 if (!gr) fprintf(f, "}\n");
894
895 FREE(sbuff);
896 }
897
898 #if 0
899 static void get_polygon_bbox(SparseMatrix polys, real *x_poly, real *bbox_x, real *bbox_y){
900 /* find bounding box. bbox_x is the xmin and xmax, bbox_y is ymin and ymax */
901 int i, j, *ia = polys->ia, *ja = polys->ja, *a = (int*) polys->a, npolys = polys->m, nverts = polys->n, ipoly,first;
902 int NEW = TRUE;
903
904 first = ABS(a[0]); ipoly = first + 1;
905 for (i = 0; i < npolys; i++){
906 for (j = ia[i]; j < ia[i+1]; j++){
907 assert(ja[j] < nverts && ja[j] >= 0);
908 if (NEW){
909 bbox_x[0] = bbox_x[1] = x_poly[2*ja[j]];
910 bbox_y[0] = bbox_y[1] = x_poly[2*ja[j]+1];
911 NEW = FALSE;
912 } else {
913 bbox_x[0] = MIN(bbox_x[0], x_poly[2*ja[j]]);
914 bbox_x[1] = MAX(bbox_x[1], x_poly[2*ja[j]]);
915 bbox_y[0] = MIN(bbox_y[0], x_poly[2*ja[j]+1]);
916 bbox_y[1] = MAX(bbox_y[1], x_poly[2*ja[j]+1]);
917 }
918 }
919 }
920 }
921 #endif
922
923 #if 0
924 void plot_processing_map(Agraph_t* gr, int n, int dim, real *x, SparseMatrix polys, SparseMatrix poly_lines, real line_width, int nverts, real *x_poly, int *polys_groups, char **labels, real *width,
925 float *fsz, float *r, float *g, float *b, char *plot_label, real *bg_color, SparseMatrix A){
926 /* if graph object exist, we just modify some attributes, otherwise we dump the whole graph */
927 int plot_polyQ = TRUE;
928 FILE *f = stdout;
929 real xmin[2], xwidth[2], scaling=1, bbox_x[2], bbox_y[2];
930 int i;
931
932 /* shift to make all coordinates position */
933 get_polygon_bbox(polys, x_poly, bbox_x, bbox_y);
934 xmin[0] = bbox_x[0]; xmin[1] = bbox_y[0];
935 xwidth[0] = (bbox_x[1] - bbox_x[0])*scaling;
936 xwidth[1] = (bbox_y[1] - bbox_y[0])*scaling;
937 for (i = 0; i < n; i++) {
938 xmin[0] = MIN(xmin[0], x[i*dim]);
939 xmin[1] = MIN(xmin[1], x[i*dim+1]);
940 }
941
942 fprintf(stderr,"xmin={%f, %f}\n", xmin[0], xmin[1]);
943
944 for (i = 0; i < n; i++) {
945 x[i*dim] = (x[i*dim] - xmin[0])*scaling;
946 x[i*dim+1] = (x[i*dim+1] - xmin[1])*scaling;
947 xwidth[0] = MAX(xwidth[0], x[i*dim]);
948 xwidth[1] = MAX(xwidth[1], x[i*dim+1]);
949 }
950 for (i = 0; i < nverts; i++) {
951 x_poly[i*dim] = (x_poly[i*dim] - xmin[0])*scaling;
952 x_poly[i*dim+1] = (x_poly[i*dim+1] - xmin[1])*scaling;
953 }
954 /*
955 fprintf(f,"//This file is for processing language. Syntax:\n//\n");
956 fprintf(f,"//beginPolygons\n//[color(r,g,b)]\n//x y\n...\n//endPolygons\n//\n");
957 fprintf(f,"//beginPolylines\n//[color(r,g,b)]\n//...\n//endPolylines\n\n");
958 fprintf(f,"//beginLines\n//[color(r,g,b)]\n//x1 y1 x2 y2\n//...\n endLines\n//\n");
959 fprintf(f,"//beginText\n//[fontSize(x)]\n//text(\"foo\")\n//position(x,y)\n\\endText\n//\n");
960 fprintf(f,"//\n");
961
962 fprintf(f, "size(%d, %d);\n", (int)(xwidth[0]+1), (int) (xwidth[1]+1));
963 */
964
965 if (!r || !g || !b) plot_polyQ = FALSE;
966
967 if (!gr) {
968 fprintf(f, "background(234, 242, 255)");
969 }
970
971 /*polygons */
972 if (plot_polyQ) {
973 plot_processing_polygons(f, -1., polys, x_poly, polys_groups, r, g, b);
974 }
975
976 /* polylines: line width is set here */
977 if (line_width >= 0){
978 plot_processing_polygons(f, line_width, poly_lines, x_poly, polys_groups, NULL, NULL, NULL);
979 }
980
981 /* edges */
982 if (A) plot_processing_edges(f, A, dim, x);
983
984 /* nodes */
985 if (labels) plot_processing_labels(f, n, dim, x, labels, width, fsz);
986
987
988 }
989 #endif
990
get_tri(int n,int dim,real * x,int * nt,struct Triangle ** T,SparseMatrix * E,int * flag)991 static void get_tri(int n, int dim, real *x, int *nt, struct Triangle **T, SparseMatrix *E, int *flag) {
992 /* always contains a self edge and is symmetric.
993 input:
994 n: number of points
995 dim: dimension, only first2D used
996 x: point j is stored x[j*dim]--x[j*dim+dim-1]
997 output:
998 nt: number of triangles
999 T: triangles
1000 E: a matrix of size nxn, if two points i > j are connected by an taiangulation edge, and is neighboring two triangles
1001 . t1 and t2, then A[i,j] is both t1 and t2
1002 */
1003 int i, j, i0, i1, i2, ntri;
1004 SparseMatrix A, B;
1005
1006 int* trilist = get_triangles(x, n, &ntri);
1007 *flag = 0;
1008
1009
1010 *T = N_NEW(ntri,struct Triangle);
1011
1012 A = SparseMatrix_new(n, n, 1, MATRIX_TYPE_INTEGER, FORMAT_COORD);
1013 for (i = 0; i < ntri; i++) {
1014 for (j = 0; j < 3; j++) {
1015 ((*T)[i]).vertices[j] = trilist[i * 3 + j];
1016 }
1017 i0 = (*T)[i].vertices[0]; i1 = (*T)[i].vertices[1]; i2 = (*T)[i].vertices[2];
1018
1019 triangle_center(&x[i0*dim], &x[i1*dim], &x[i2*dim], (*T)[i].center);
1020 A = matrix_add_entry(A, i0, i1, i);
1021 A = matrix_add_entry(A, i1, i2, i);
1022 A = matrix_add_entry(A, i2, i0, i);
1023 }
1024
1025 B = SparseMatrix_from_coordinate_format_not_compacted(A, SUM_REPEATED_NONE);
1026 SparseMatrix_delete(A);
1027 B = SparseMatrix_sort(B);
1028 *E = B;
1029
1030 *nt = ntri;
1031
1032 FREE(trilist);
1033
1034 return;
1035 }
1036
1037
1038
plot_labels(int n,int dim,real * x,char ** labels)1039 void plot_labels(int n, int dim, real *x, char **labels){
1040 int i, j;
1041
1042 printf("Graphics[{");
1043
1044 for (i = 0; i < n; i++){
1045 printf("Text[\"%s\",{",labels[i]);
1046 for (j = 0; j < 2; j++) {
1047 printf("%f",x[i*dim+j]);
1048 if (j == 0) printf(",");
1049 }
1050 printf("}]");
1051 if (i < n - 1) printf(",\n");
1052 }
1053 printf("}]");
1054
1055
1056 }
plot_points(int n,int dim,real * x)1057 void plot_points(int n, int dim, real *x){
1058 int i, j;
1059
1060 printf("Graphics[{Point[{");
1061 for (i = 0; i < n; i++){
1062 printf("{");
1063 for (j = 0; j < 2; j++) {
1064 printf("%f",x[i*dim+j]);
1065 if (j == 0) printf(",");
1066 }
1067 printf("}");
1068 if (i < n - 1) printf(",");
1069 }
1070 printf("}]");
1071
1072 /*
1073 printf(",");
1074 for (i = 0; i < n; i++){
1075 printf("Text[%d,{",i);
1076 for (j = 0; j < 2; j++) {
1077 printf("%f",x[i*dim+j]);
1078 if (j == 0) printf(",");
1079 }
1080 printf("}]");
1081 if (i < n - 1) printf(",");
1082 }
1083 */
1084 printf("}]");
1085
1086 }
1087
plot_edges(int n,int dim,real * x,SparseMatrix A)1088 void plot_edges(int n, int dim, real *x, SparseMatrix A){
1089 int i, j, k;
1090 int *ia, *ja;
1091
1092 if (!A) {
1093 printf("Graphics[{}]");
1094 return;
1095 }
1096 ia = A->ia; ja = A->ja;
1097
1098 printf("Graphics[(* edges of the graph*){");
1099 for (i = 0; i < n; i++){
1100 for (j = ia[i]; j < ia[i+1]; j++){
1101 if (i > 0 && j == ia[i]) printf(",");;
1102 printf("Line[{{");
1103 for (k = 0; k < 2; k++) {
1104 printf("%f",x[i*dim+k]);
1105 if (k == 0) printf(",");
1106 }
1107 printf("},{");
1108 for (k = 0; k < 2; k++) {
1109 printf("%f",x[ja[j]*dim+k]);
1110 if (k == 0) printf(",");
1111 }
1112 printf("}}]");
1113 if (j < ia[i+1] - 1) printf(",");
1114 }
1115 }
1116 printf("}(* end of edges of the graph*)]");
1117
1118 }
get_country_graph(int n,SparseMatrix A,int * groups,SparseMatrix * poly_point_map,int GRP_RANDOM,int GRP_BBOX)1119 static SparseMatrix get_country_graph(int n, SparseMatrix A, int *groups, SparseMatrix *poly_point_map, int GRP_RANDOM, int GRP_BBOX){
1120 /* form a graph each vertex is a group (a country), and a vertex is connected to another if the two countryes shares borders.
1121 since the group ID may not be contigous (e.g., only groups 2,3,5, -1), we will return NULL if one of the group has non-positive ID! */
1122 int *ia, *ja;
1123 int one = 1, jj, i, j, ig1, ig2;
1124 SparseMatrix B, BB;
1125 int min_grp, max_grp;
1126
1127 min_grp = max_grp = groups[0];
1128 for (i = 0; i < n; i++) {
1129 max_grp = MAX(groups[i], max_grp);
1130 min_grp = MIN(groups[i], min_grp);
1131 }
1132 if (min_grp <= 0) return NULL;
1133 B = SparseMatrix_new(max_grp, max_grp, 1, MATRIX_TYPE_INTEGER, FORMAT_COORD);
1134 ia = A->ia;
1135 ja = A->ja;
1136 for (i = 0; i < n; i++){
1137 ig1 = groups[i]-1;/* add a diagonal entry */
1138 SparseMatrix_coordinate_form_add_entries(B, 1, &ig1, &ig1, &one);
1139 for (j = ia[i]; j < ia[i+1]; j++){
1140 jj = ja[j];
1141 if (i != jj && groups[i] != groups[jj] && groups[jj] != GRP_RANDOM && groups[jj] != GRP_BBOX){
1142 ig1 = groups[i]-1; ig2 = groups[jj]-1;
1143 SparseMatrix_coordinate_form_add_entries(B, 1, &ig1, &ig2, &one);
1144 }
1145 }
1146 }
1147 BB = SparseMatrix_from_coordinate_format(B);
1148 SparseMatrix_delete(B);
1149 return BB;
1150 }
1151
conn_comp(int n,SparseMatrix A,int * groups,SparseMatrix * poly_point_map)1152 static void conn_comp(int n, SparseMatrix A, int *groups, SparseMatrix *poly_point_map){
1153 /* form a graph where only vertices that are connected as well as in the same group are connected */
1154 int *ia, *ja;
1155 int one = 1, jj, i, j;
1156 SparseMatrix B, BB;
1157 int ncomps, *comps = NULL, *comps_ptr = NULL;
1158
1159 B = SparseMatrix_new(n, n, 1, MATRIX_TYPE_INTEGER, FORMAT_COORD);
1160 ia = A->ia;
1161 ja = A->ja;
1162 for (i = 0; i < n; i++){
1163 for (j = ia[i]; j < ia[i+1]; j++){
1164 jj = ja[j];
1165 if (i != jj && groups[i] == groups[jj]){
1166 SparseMatrix_coordinate_form_add_entries(B, 1, &i, &jj, &one);
1167 }
1168 }
1169 }
1170 BB = SparseMatrix_from_coordinate_format(B);
1171
1172 SparseMatrix_weakly_connected_components(BB, &ncomps, &comps, &comps_ptr);
1173 SparseMatrix_delete(B);
1174 SparseMatrix_delete(BB);
1175 *poly_point_map = SparseMatrix_new(ncomps, n, n, MATRIX_TYPE_PATTERN, FORMAT_CSR);
1176 FREE((*poly_point_map)->ia);
1177 FREE((*poly_point_map)->ja);
1178 (*poly_point_map)->ia = comps_ptr;
1179 (*poly_point_map)->ja = comps;
1180 (*poly_point_map)->nz = n;
1181
1182 }
1183
1184
get_poly_lines(int exclude_random,int nt,SparseMatrix graph,SparseMatrix E,int ncomps,int * comps_ptr,int * comps,int * groups,int * mask,SparseMatrix * poly_lines,int ** polys_groups,int GRP_RANDOM,int GRP_BBOX)1185 static void get_poly_lines(int exclude_random, int nt, SparseMatrix graph, SparseMatrix E, int ncomps, int *comps_ptr, int *comps,
1186 int *groups, int *mask, SparseMatrix *poly_lines, int **polys_groups,
1187 int GRP_RANDOM, int GRP_BBOX){
1188 /*============================================================
1189
1190 polygon outlines
1191
1192 ============================================================*/
1193 int i, *tlist, nz, ipoly, ipoly2, nnt, ii, jj, t1, t2, t, cur, next, nn, j, nlink, sta;
1194 int *elist, edim = 3;/* a list tell which vertex a particular vertex is linked with during poly construction.
1195 since the surface is a cycle, each can only link with 2 others, the 3rd position is used to record how many links
1196 */
1197 int *ie = E->ia, *je = E->ja, *e = (int*) E->a, n = E->m;
1198 int *ia = NULL, *ja = NULL;
1199 SparseMatrix A;
1200 int *gmask = NULL;
1201
1202
1203 graph = NULL;/* we disable checking whether a polyline cross an edge for now due to issues with labels */
1204 if (graph) {
1205 assert(graph->m == n);
1206 gmask = malloc(sizeof(int)*n);
1207 for (i = 0; i < n; i++) gmask[i] = -1;
1208 ia = graph->ia; ja = graph->ja;
1209 edim = 5;/* we also store info about whether an edge of a polygon correspondes to a real edge or not. */
1210 }
1211
1212 for (i = 0; i < nt; i++) mask[i] = -1;
1213 /* loop over every point in each connected component */
1214 elist = MALLOC(sizeof(int)*(nt)*edim);
1215 tlist = MALLOC(sizeof(int)*nt*2);
1216 *poly_lines = SparseMatrix_new(ncomps, nt, 1, MATRIX_TYPE_INTEGER, FORMAT_COORD);
1217 *polys_groups = MALLOC(sizeof(int)*(ncomps));
1218
1219 for (i = 0; i < nt; i++) elist[i*edim + 2] = 0;
1220 nz = ie[E->m] - ie[0];
1221
1222 ipoly = 1;
1223
1224 for (i = 0; i < ncomps; i++){
1225 /*fprintf(stderr, "comp %d has %d members\n",i, comps_ptr[i+1]-comps_ptr[i]);*/
1226 nnt = 0;
1227 for (j = comps_ptr[i]; j < comps_ptr[i+1]; j++){
1228 ii = comps[j];
1229
1230 if (graph){
1231 for (jj = ia[ii]; jj < ia[ii+1]; jj++) gmask[ja[jj]] = ii;
1232 }
1233
1234 (*polys_groups)[i] = groups[ii];/* assign the grouping of each poly */
1235
1236 /* skip the country formed by random points */
1237 if (exclude_random && (groups[ii] == GRP_RANDOM || groups[ii] == GRP_BBOX)) continue;
1238
1239 /* always skip bounding box */
1240 if (groups[ii] == GRP_BBOX) continue;
1241
1242 /*fprintf(stderr, "member %d is in group %d, it is\n",ii, groups[ii]);*/
1243 for (jj = ie[ii]; jj < ie[ii+1]; jj++){
1244 /*
1245 fprintf(stderr, "connected with %d in group %d\n",je[jj], groups[je[jj]]);
1246 fprintf(stderr, "jj=%d nz = %d je[jj]=%d je[jj+1]=%d\n",jj,nz, je[jj],je[jj+1]);
1247 */
1248 if (groups[je[jj]] != groups[ii] && jj < nz - 1 && je[jj] == je[jj+1]){/* an triangle edge neighboring 2 triangles and two ends not in the same groups */
1249 t1 = e[jj];
1250 t2 = e[jj+1];
1251
1252 nlink = elist[t1*edim + 2]%2;
1253 elist[t1*edim + nlink] = t2;/* t1->t2*/
1254 if (graph){
1255 if (gmask[je[jj]] == ii){/* a real edge */
1256 elist[t1*edim+nlink+3] = POLY_LINE_REAL_EDGE;
1257 } else {
1258 fprintf(stderr,"not real!!!\n");
1259 elist[t1*edim+nlink+3] = POLY_LINE_NOT_REAL_EDGE;
1260 }
1261 }
1262 elist[t1*edim + 2]++;
1263
1264 nlink = elist[t2*edim + 2]%2;
1265 elist[t2*edim + nlink] = t1;/* t1->t2*/
1266 elist[t2*edim + 2]++;
1267 if (graph){
1268 if (gmask[je[jj]] == ii){/* a real edge */
1269 elist[t2*edim+nlink+3] = POLY_LINE_REAL_EDGE;
1270 } else {
1271 fprintf(stderr,"not real!!!\n");
1272 elist[t2*edim+nlink+3] = POLY_LINE_NOT_REAL_EDGE;
1273 }
1274 }
1275
1276 tlist[nnt++] = t1; tlist[nnt++] = t2;
1277 jj++;
1278 }
1279 }
1280 }/* done poly edges for this component i */
1281
1282
1283 /* debugging*/
1284 #ifdef DEBUG
1285 /*
1286 for (j = 0; j < nnt; j++) {
1287 if (elist[tlist[j]*edim + 2]%2 != 0){
1288 printf("wrong: elist[%d*edim+2] = %d\n",j,elist[tlist[j]*edim + 2]%);
1289 assert(0);
1290 }
1291 }
1292 */
1293 #endif
1294
1295 /* form one or more (if there is a hole) polygon outlines for this component */
1296 for (j = 0; j < nnt; j++){
1297 t = tlist[j];
1298 if (mask[t] != i){
1299 cur = sta = t; mask[cur] = i;
1300 next = neighbor(t, 1, edim, elist);
1301 nlink = 1;
1302 if (graph && neighbor(cur, 3, edim, elist) == POLY_LINE_NOT_REAL_EDGE){
1303 ipoly2 = - ipoly;
1304 } else {
1305 ipoly2 = ipoly;
1306 }
1307 SparseMatrix_coordinate_form_add_entries(*poly_lines, 1, &i, &cur, &ipoly2);
1308 while (next != sta){
1309 mask[next] = i;
1310
1311 if (graph && neighbor(cur, nlink + 3, edim, elist) == POLY_LINE_NOT_REAL_EDGE){
1312 ipoly2 = -ipoly;
1313 } else {
1314 ipoly2 = ipoly;
1315 }
1316 SparseMatrix_coordinate_form_add_entries(*poly_lines, 1, &i, &next, &ipoly2);
1317
1318 nn = neighbor(next, 0, edim, elist);
1319 nlink = 0;
1320 if (nn == cur) {
1321 nlink = 1;
1322 nn = neighbor(next, 1, edim, elist);
1323 }
1324 assert(nn != cur);
1325
1326 cur = next;
1327 next = nn;
1328 }
1329
1330 if (graph && neighbor(cur, nlink + 3, edim, elist) == POLY_LINE_NOT_REAL_EDGE){
1331 ipoly2 = -ipoly;
1332 } else {
1333 ipoly2 = ipoly;
1334 }
1335 SparseMatrix_coordinate_form_add_entries(*poly_lines, 1, &i, &sta, &ipoly2);/* complete a cycle by adding starting point */
1336
1337 ipoly++;
1338 }
1339
1340 }/* found poly_lines for this comp */
1341 }
1342
1343 A = SparseMatrix_from_coordinate_format_not_compacted(*poly_lines, SUM_REPEATED_NONE);
1344 SparseMatrix_delete(*poly_lines);
1345 *poly_lines = A;
1346
1347 FREE(tlist);
1348 FREE(elist);
1349 }
1350
plot_cycle(int head,int * cycle,int * edge_table,real * x)1351 static void plot_cycle(int head, int *cycle, int *edge_table, real *x){
1352 int cur, next;
1353 real x1, x2, y1, y2;
1354
1355 printf("Graphics[{");
1356 cur = head;
1357 while ((next = cycle_next(cur)) != head){
1358 x1 = x[2*edge_head(cur)];
1359 y1 = x[2*edge_head(cur)+1];
1360 x2 = x[2*edge_tail(cur)];
1361 y2 = x[2*edge_tail(cur)+1];
1362 printf("{Black,Arrow[{{%f,%f},{%f,%f}}],Green,Text[%d, {%f,%f}],Text[%d, {%f,%f}]},",x1,y1,x2,y2,edge_head(cur),x1,y1,edge_tail(cur),x2,y2);
1363 cur = next;
1364 }
1365 x1 = x[2*edge_head(cur)];
1366 y1 = x[2*edge_head(cur)+1];
1367 x2 = x[2*edge_tail(cur)];
1368 y2 = x[2*edge_tail(cur)+1];
1369 printf("{Black,Arrow[{{%f,%f},{%f,%f}}],Green,Text[%d, {%f,%f}],Text[%d, {%f,%f}]}}]",x1,y1,x2,y2,edge_head(cur),x1,y1,edge_tail(cur),x2,y2);
1370
1371
1372 }
1373
cycle_print(int head,int * cycle,int * edge_table)1374 static void cycle_print(int head, int *cycle, int *edge_table){
1375 int cur, next;
1376
1377 cur = head;
1378 fprintf(stderr, "cycle (edges): {");
1379 while ((next = cycle_next(cur)) != head){
1380 fprintf(stderr, "%d,",cur);
1381 cur = next;
1382 }
1383 fprintf(stderr, "%d}\n",cur);
1384
1385 cur = head;
1386 fprintf(stderr, "cycle (vertices): ");
1387 while ((next = cycle_next(cur)) != head){
1388 fprintf(stderr, "%d--",edge_head(cur));
1389 cur = next;
1390 }
1391 fprintf(stderr, "%d--%d\n",edge_head(cur),edge_tail(cur));
1392
1393
1394
1395
1396
1397
1398 }
1399
same_edge(int ecur,int elast,int * edge_table)1400 static int same_edge(int ecur, int elast, int *edge_table){
1401 return ((edge_head(ecur) == edge_head(elast) && edge_tail(ecur) == edge_tail(elast))
1402 || (edge_head(ecur) == edge_tail(elast) && edge_tail(ecur) == edge_head(elast)));
1403 }
1404
get_polygon_solids(int exclude_random,int nt,SparseMatrix E,int ncomps,int * comps_ptr,int * comps,int * groups,int * mask,real * x_poly,SparseMatrix * polys,int ** polys_groups,int GRP_RANDOM,int GRP_BBOX)1405 static void get_polygon_solids(int exclude_random, int nt, SparseMatrix E, int ncomps, int *comps_ptr, int *comps,
1406 int *groups, int *mask, real *x_poly, SparseMatrix *polys, int **polys_groups,
1407 int GRP_RANDOM, int GRP_BBOX){
1408 /*============================================================
1409
1410 polygon slids that will be colored
1411
1412 ============================================================*/
1413 int *edge_table;/* a table of edges of the triangle graph. If two vertex u and v are connected and are adjencent to two triangles
1414 t1 and t2, then from u there are two edges to v, one denoted as t1->t2, and the other t2->t1. They are
1415 numbered as e1 and e2. edge_table[e1]={t1,t2} and edge_table[e2]={t2,t1}
1416 */
1417 SparseMatrix half_edges;/* a graph of triangle edges. If two vertex u and v are connected and are adjencent to two triangles
1418 t1 and t2, then from u there are two edges to v, one denoted as t1->t2, and the other t2->t1. They are
1419 numbered as e1 and e2. Likewise from v to u there are also two edges e1 and e2.
1420 */
1421
1422 int n = E->m, *ie = E->ia, *je = E->ja, *e = (int*) E->a, ne, i, j, t1, t2, jj, ii;
1423 int *cycle, cycle_head = 0;/* a list of edges that form a cycle that describe the polygon. cycle[e][0] gives the prev edge in the cycle from e,
1424 cycle[e][1] gives the next edge
1425 */
1426 int *edge_cycle_map, NOT_ON_CYCLE = -1;/* map an edge e to its position on cycle, unless it does not exist (NOT_ON_CYCLE) */
1427 int *emask;/* whether an edge is seens this iter */
1428 enum {NO_DUPLICATE = -1};
1429 int *elist, edim = 3;/* a list tell which edge a particular vertex is linked with when a voro cell has been visited,
1430 since the surface is a cycle, each vertex can only link with 2 edges, the 3rd position is used to record how many links
1431 */
1432
1433 int k, duplicate, ee = 0, ecur, enext, eprev, cur, next, nn, nlink, head, elast = 0, etail, tail, ehead, efirst;
1434
1435 int DEBUG_CYCLE = 0;
1436 SparseMatrix B;
1437
1438 ne = E->nz;
1439 edge_table = MALLOC(sizeof(int)*ne*2);
1440
1441 for (i = 0; i < n; i++) mask[i] = -1;
1442
1443 half_edges = SparseMatrix_new(n, n, 1, MATRIX_TYPE_INTEGER, FORMAT_COORD);
1444
1445 ne = 0;
1446 for (i = 0; i < n; i++){
1447 for (j = ie[i]; j < ie[i+1]; j++){
1448 if (j < ie[n] - ie[0] - 1 && i > je[j] && je[j] == je[j+1]){/* an triangle edge neighboring 2 triangles. Since E is symmetric, we only do one edge of E*/
1449 t1 = e[j];
1450 t2 = e[j+1];
1451 jj = je[j];
1452 assert(jj < n);
1453 edge_table[ne*2] = t1;/*t1->t2*/
1454 edge_table[ne*2+1] = t2;
1455 half_edges = SparseMatrix_coordinate_form_add_entries(half_edges, 1, &i, &jj, &ne);
1456 half_edges = SparseMatrix_coordinate_form_add_entries(half_edges, 1, &jj, &i, &ne);
1457 ne++;
1458
1459 edge_table[ne*2] = t2;/*t2->t1*/
1460 edge_table[ne*2+1] = t1;
1461 half_edges = SparseMatrix_coordinate_form_add_entries(half_edges, 1, &i, &jj, &ne);
1462 half_edges = SparseMatrix_coordinate_form_add_entries(half_edges, 1, &jj, &i, &ne);
1463
1464
1465 ne++;
1466 j++;
1467 }
1468 }
1469 }
1470 assert(E->nz >= ne);
1471
1472 cycle = MALLOC(sizeof(int)*ne*2);
1473 B = SparseMatrix_from_coordinate_format_not_compacted(half_edges, SUM_REPEATED_NONE);
1474 SparseMatrix_delete(half_edges);half_edges = B;
1475
1476 edge_cycle_map = MALLOC(sizeof(int)*ne);
1477 emask = MALLOC(sizeof(int)*ne);
1478 for (i = 0; i < ne; i++) edge_cycle_map[i] = NOT_ON_CYCLE;
1479 for (i = 0; i < ne; i++) emask[i] = -1;
1480
1481 ie = half_edges->ia;
1482 je = half_edges->ja;
1483 e = (int*) half_edges->a;
1484 elist = MALLOC(sizeof(int)*(nt)*3);
1485 for (i = 0; i < nt; i++) elist[i*edim + 2] = 0;
1486
1487 *polys = SparseMatrix_new(ncomps, nt, 1, MATRIX_TYPE_INTEGER, FORMAT_COORD);
1488
1489 for (i = 0; i < ncomps; i++){
1490 if (DEBUG_CYCLE) fprintf(stderr, "\n ============ comp %d has %d members\n",i, comps_ptr[i+1]-comps_ptr[i]);
1491 for (k = comps_ptr[i]; k < comps_ptr[i+1]; k++){
1492 ii = comps[k];
1493 mask[ii] = i;
1494 duplicate = NO_DUPLICATE;
1495 if (DEBUG_CYCLE) fprintf(stderr,"member = %d has %d neighbors\n",ii, ie[ii+1]-ie[ii]);
1496 for (j = ie[ii]; j < ie[ii+1]; j++){
1497 jj = je[j];
1498 ee = e[j];
1499 t1 = edge_head(ee);
1500 if (DEBUG_CYCLE) fprintf(stderr," linked with %d using half-edge %d, {head,tail} of the edge = {%d, %d}\n",jj, ee, t1, edge_tail(ee));
1501 nlink = elist[t1*edim + 2]%2;
1502 elist[t1*edim + nlink] = ee;/* t1->t2*/
1503 elist[t1*edim + 2]++;
1504
1505 if (edge_cycle_map[ee] != NOT_ON_CYCLE) duplicate = ee;
1506 emask[ee] = ii;
1507 }
1508
1509 if (duplicate == NO_DUPLICATE){
1510 /* this must be the first time the cycle is being established, a new voro cell*/
1511 ecur = ee;
1512 cycle_head = ecur;
1513 cycle_next(ecur) = ecur;
1514 cycle_prev(ecur) = ecur;
1515 edge_cycle_map[ecur] = 1;
1516 head = cur = edge_head(ecur);
1517 next = edge_tail(ecur);
1518 if (DEBUG_CYCLE) fprintf(stderr, "NEW CYCLE\n starting with edge %d, {head,tail}={%d,%d}\n", ee, head, next);
1519 while (next != head){
1520 enext = neighbor(next, 0, edim, elist);/* two voro edges linked with triangle "next" */
1521 if ((edge_head(enext) == cur && edge_tail(enext) == next)
1522 || (edge_head(enext) == next && edge_tail(enext) == cur)){/* same edge */
1523 enext = neighbor(next, 1, edim, elist);
1524 };
1525 if (DEBUG_CYCLE) fprintf(stderr, "cur edge = %d, next edge %d, {head,tail}={%d,%d},\n",ecur, enext, edge_head(enext), edge_tail(enext));
1526 nn = edge_head(enext);
1527 if (nn == next) nn = edge_tail(enext);
1528 cycle_next(enext) = cycle_next(ecur);
1529 cycle_prev(enext) = ecur;
1530 cycle_next(ecur) = enext;
1531 cycle_prev(ee) = enext;
1532 edge_cycle_map[enext] = 1;
1533
1534 ecur = enext;
1535 cur = next;
1536 next = nn;
1537 }
1538 if (DEBUG_CYCLE) cycle_print(ee, cycle,edge_table);
1539 } else {
1540 /* we found a duplicate edge, remove that, and all contiguous neighbors that overlap with the current voro
1541 */
1542 ecur = ee = duplicate;
1543 while (emask[ecur] == ii){
1544 /* contigous overlapping edges, Cycling is not possible
1545 since the cycle can not complete surround the new voro cell and yet
1546 do not contain any other edges
1547 */
1548 ecur = cycle_next(ecur);
1549 }
1550 if (DEBUG_CYCLE) fprintf(stderr," duplicating edge = %d, starting from the a non-duplicating edge %d, search backwards\n",ee, ecur);
1551
1552 ecur = cycle_prev(ecur);
1553 efirst = ecur;
1554 while (emask[ecur] == ii){
1555 if (DEBUG_CYCLE) fprintf(stderr," remove edge %d (%d--%d)\n",ecur, edge_head(ecur), edge_tail(ecur));
1556 /* short this duplicating edge */
1557 edge_cycle_map[ecur] = NOT_ON_CYCLE;
1558 enext = cycle_next(ecur);
1559 eprev = cycle_prev(ecur);
1560 cycle_next(ecur) = ecur;/* isolate this edge */
1561 cycle_prev(ecur) = ecur;
1562 cycle_next(eprev) = enext;/* short */
1563 cycle_prev(enext) = eprev;
1564 elast = ecur;/* record the last removed edge */
1565 ecur = eprev;
1566 }
1567
1568 if (DEBUG_CYCLE) {
1569 fprintf(stderr, "remaining (broken) cycle = ");
1570 cycle_print(cycle_next(ecur), cycle,edge_table);
1571 }
1572
1573 /* we now have a broken cycle of head = edge_tail(ecur) and tail = edge_head(cycle_next(ecur)) */
1574 ehead = ecur; etail = cycle_next(ecur);
1575 cycle_head = ehead;
1576 head = edge_tail(ehead);
1577 tail = edge_head(etail);
1578
1579 /* pick an edge ev from head in the voro that is a removed edge: since the removed edges form a path starting from
1580 efirst, and at elast (head of elast is head), usually we just need to check that ev is not the same as elast,
1581 but in the case of a voro filling in a hole, we also need to check that ev is not efirst,
1582 since in this case every edge of the voro cell is removed
1583 */
1584 ecur = neighbor(head, 0, edim, elist);
1585 if (same_edge(ecur, elast, edge_table)){
1586 ecur = neighbor(head, 1, edim, elist);
1587 };
1588
1589 if (DEBUG_CYCLE) fprintf(stderr, "forwarding now from edge %d = {%d, %d}, try to reach vtx %d, first edge from voro = %d\n",
1590 ehead, edge_head(ehead), edge_tail(ehead), tail, ecur);
1591
1592 /* now go along voro edges till we reach the tail of the broken cycle*/
1593 cycle_next(ehead) = ecur;
1594 cycle_prev(ecur) = ehead;
1595 cycle_prev(etail) = ecur;
1596 cycle_next(ecur) = etail;
1597 if (same_edge(ecur, efirst, edge_table)){
1598 if (DEBUG_CYCLE) fprintf(stderr, "this voro cell fill in a hole completely!!!!\n");
1599 } else {
1600
1601 edge_cycle_map[ecur] = 1;
1602 head = cur = edge_head(ecur);
1603 next = edge_tail(ecur);
1604 if (DEBUG_CYCLE) fprintf(stderr, "starting with edge %d, {head,tail}={%d,%d}\n", ecur, head, next);
1605 while (next != tail){
1606 enext = neighbor(next, 0, edim, elist);/* two voro edges linked with triangle "next" */
1607 if ((edge_head(enext) == cur && edge_tail(enext) == next)
1608 || (edge_head(enext) == next && edge_tail(enext) == cur)){/* same edge */
1609 enext = neighbor(next, 1, edim, elist);
1610 };
1611 if (DEBUG_CYCLE) fprintf(stderr, "cur edge = %d, next edge %d, {head,tail}={%d,%d},\n",ecur, enext, edge_head(enext), edge_tail(enext));
1612
1613
1614 nn = edge_head(enext);
1615 if (nn == next) nn = edge_tail(enext);
1616 cycle_next(enext) = cycle_next(ecur);
1617 cycle_prev(enext) = ecur;
1618 cycle_next(ecur) = enext;
1619 cycle_prev(etail) = enext;
1620 edge_cycle_map[enext] = 1;
1621
1622 ecur = enext;
1623 cur = next;
1624 next = nn;
1625 }
1626 }
1627 if (DEBUG_CYCLE && 0) {
1628 cycle_print(etail, cycle,edge_table);
1629 plot_cycle(etail, cycle,edge_table, x_poly);
1630 printf(",");
1631 }
1632
1633 }
1634
1635 }
1636 /* done this component, load to sparse matrix, unset edge_map*/
1637 ecur = cycle_head;
1638 while ((enext = cycle_next(ecur)) != cycle_head){
1639 edge_cycle_map[ecur] = NOT_ON_CYCLE;
1640 head = edge_head(ecur);
1641 SparseMatrix_coordinate_form_add_entries(*polys, 1, &i, &head, &i);
1642 ecur = enext;
1643 }
1644 edge_cycle_map[ecur] = NOT_ON_CYCLE;
1645 head = edge_head(ecur); tail = edge_tail(ecur);
1646 SparseMatrix_coordinate_form_add_entries(*polys, 1, &i, &head, &i);
1647 SparseMatrix_coordinate_form_add_entries(*polys, 1, &i, &tail, &i);
1648
1649
1650 /* unset edge_map */
1651 }
1652
1653
1654
1655 B = SparseMatrix_from_coordinate_format_not_compacted(*polys, SUM_REPEATED_NONE);
1656 SparseMatrix_delete(*polys);
1657 *polys = B;
1658
1659 SparseMatrix_delete(half_edges);
1660 FREE(cycle);
1661 FREE(edge_cycle_map);
1662 FREE(elist);
1663 FREE(emask);
1664 FREE(edge_table);
1665
1666 }
get_polygons(int exclude_random,int n,int nrandom,int dim,SparseMatrix graph,real * xcombined,int * grouping,int nt,struct Triangle * Tp,SparseMatrix E,int * nverts,real ** x_poly,int * npolys,SparseMatrix * poly_lines,SparseMatrix * polys,int ** polys_groups,SparseMatrix * poly_point_map,SparseMatrix * country_graph,int * flag)1667 static void get_polygons(int exclude_random, int n, int nrandom, int dim, SparseMatrix graph, real *xcombined, int *grouping,
1668 int nt, struct Triangle *Tp, SparseMatrix E, int *nverts, real **x_poly,
1669 int *npolys, SparseMatrix *poly_lines, SparseMatrix *polys, int **polys_groups, SparseMatrix *poly_point_map, SparseMatrix *country_graph,
1670 int *flag){
1671 int i, j;
1672 int *mask;
1673 int *groups;
1674 int maxgrp;
1675 int *comps = NULL, *comps_ptr = NULL, ncomps;
1676 int GRP_RANDOM, GRP_BBOX;
1677 SparseMatrix B;
1678
1679 *flag = 0;
1680
1681 assert(dim == 2);
1682 *nverts = nt;
1683
1684 groups = MALLOC(sizeof(int)*(n + nrandom));
1685 maxgrp = grouping[0];
1686 for (i = 0; i < n; i++) {
1687 maxgrp = MAX(maxgrp, grouping[i]);
1688 groups[i] = grouping[i];
1689 }
1690
1691 GRP_RANDOM = maxgrp + 1; GRP_BBOX = maxgrp + 2;
1692 for (i = n; i < n + nrandom - 4; i++) {/* all random points in the same group */
1693 groups[i] = GRP_RANDOM;
1694 }
1695 for (i = n + nrandom - 4; i < n + nrandom; i++) {/* last 4 pts of the expanded bonding box in the same group */
1696 groups[i] = GRP_BBOX;
1697 }
1698
1699 /* finding connected componts: vertices that are connected in the triangle graph, as well as in the same group */
1700 mask = MALLOC(sizeof(int)*MAX(n + nrandom, 2*nt));
1701 conn_comp(n + nrandom, E, groups, poly_point_map);
1702
1703 ncomps = (*poly_point_map)->m;
1704 comps = (*poly_point_map)->ja;
1705 comps_ptr = (*poly_point_map)->ia;
1706
1707 if (exclude_random){
1708 /* connected components are such that the random points and the bounding box 4 points forms the last
1709 remaining components */
1710 for (i = ncomps - 1; i >= 0; i--) {
1711 if ((groups[comps[comps_ptr[i]]] != GRP_RANDOM) &&
1712 (groups[comps[comps_ptr[i]]] != GRP_BBOX)) break;
1713 }
1714 ncomps = i + 1;
1715 if (Verbose) fprintf(stderr,"ncomps = %d\n",ncomps);
1716 } else {/* always exclude bounding box */
1717 for (i = ncomps - 1; i >= 0; i--) {
1718 if (groups[comps[comps_ptr[i]]] != GRP_BBOX) break;
1719 }
1720 ncomps = i + 1;
1721 if (Verbose) fprintf(stderr," ncomops = %d\n",ncomps);
1722 }
1723 *npolys = ncomps;
1724
1725 *x_poly = MALLOC(sizeof(real)*dim*nt);
1726 for (i = 0; i < nt; i++){
1727 for (j = 0; j < dim; j++){
1728 (*x_poly)[i*dim+j] = (Tp[i]).center[j];
1729 }
1730 }
1731
1732
1733 /*============================================================
1734
1735 polygon outlines
1736
1737 ============================================================*/
1738 get_poly_lines(exclude_random, nt, graph, E, ncomps, comps_ptr, comps, groups, mask, poly_lines, polys_groups, GRP_RANDOM, GRP_BBOX);
1739
1740 /*============================================================
1741
1742 polygon solids
1743
1744 ============================================================*/
1745 get_polygon_solids(exclude_random, nt, E, ncomps, comps_ptr, comps, groups, mask, *x_poly, polys, polys_groups, GRP_RANDOM, GRP_BBOX);
1746
1747 B = get_country_graph(n, E, groups, poly_point_map, GRP_RANDOM, GRP_BBOX);
1748 *country_graph = B;
1749
1750 FREE(groups);
1751 FREE(mask);
1752
1753 }
1754
1755
make_map_internal(int exclude_random,int include_OK_points,int n,int dim,real * x0,int * grouping0,SparseMatrix graph,real bounding_box_margin[],int * nrandom,int nedgep,real shore_depth_tol,real edge_bridge_tol,real ** xcombined,int * nverts,real ** x_poly,int * npolys,SparseMatrix * poly_lines,SparseMatrix * polys,int ** polys_groups,SparseMatrix * poly_point_map,SparseMatrix * country_graph,int highlight_cluster,int * flag)1756 int make_map_internal(int exclude_random, int include_OK_points,
1757 int n, int dim, real *x0, int *grouping0, SparseMatrix graph, real bounding_box_margin[], int *nrandom, int nedgep,
1758 real shore_depth_tol, real edge_bridge_tol, real **xcombined, int *nverts, real **x_poly,
1759 int *npolys, SparseMatrix *poly_lines, SparseMatrix *polys, int **polys_groups, SparseMatrix *poly_point_map,
1760 SparseMatrix *country_graph, int highlight_cluster, int *flag){
1761
1762
1763 real xmax[2], xmin[2], area, *x = x0;
1764 int i, j;
1765 QuadTree qt;
1766 int dim2 = 2, nn = 0;
1767 int max_qtree_level = 10;
1768 real ymin[2], min;
1769 int imin, nz, nzok = 0, nzok0 = 0, nt;
1770 real *xran, point[2];
1771 struct Triangle *Tp;
1772 SparseMatrix E;
1773 real boxsize[2];
1774 int INCLUDE_OK_POINTS = include_OK_points;/* OK points are random points inserted and found to be within shore_depth_tol of real/artificial points,
1775 including them instead of throwing away increase realism of boundary */
1776 int *grouping = grouping0;
1777
1778 int HIGHLIGHT_SET = highlight_cluster;
1779
1780 *flag = 0;
1781 for (j = 0; j < dim2; j++) {
1782 xmax[j] = x[j];
1783 xmin[j] = x[j];
1784 }
1785
1786 for (i = 0; i < n; i++){
1787 for (j = 0; j < dim2; j++) {
1788 xmax[j] = MAX(xmax[j], x[i*dim+j]);
1789 xmin[j] = MIN(xmin[j], x[i*dim+j]);
1790 }
1791 }
1792 boxsize[0] = (xmax[0] - xmin[0]);
1793 boxsize[1] = (xmax[1] - xmin[1]);
1794 area = boxsize[0]*boxsize[1];
1795
1796 if (*nrandom == 0) {
1797 *nrandom = n;
1798 } else if (*nrandom < 0){
1799 *nrandom = -(*nrandom)*n;
1800 } else if (*nrandom < 4) {/* by default we add 4 point on 4 corners anyway */
1801 *nrandom = 0;
1802 } else {
1803 *nrandom -= 4;
1804 }
1805
1806 if (shore_depth_tol < 0) shore_depth_tol = sqrt(area/(real) n); /* set to average distance for random distribution */
1807 if (Verbose) fprintf(stderr,"nrandom=%d shore_depth_tol=%.08f\n",*nrandom, shore_depth_tol);
1808
1809
1810 /* add artificial points along each edge to avoid as much as possible
1811 two connected components be separated due to small shore depth */
1812 {
1813 int nz;
1814 real *y;
1815 int k, t, np=nedgep;
1816 if (graph && np){
1817 fprintf(stderr,"add art np = %d\n",np);
1818 nz = graph->nz;
1819 y = MALLOC(sizeof(real)*(dim*n + dim*nz*np));
1820 for (i = 0; i < n*dim; i++) y[i] = x[i];
1821 grouping = MALLOC(sizeof(int)*(n + nz*np));
1822 for (i = 0; i < n; i++) grouping[i] = grouping0[i];
1823 nz = n;
1824 for (i = 0; i < graph->m; i++){
1825
1826 for (j = graph->ia[i]; j < graph->ia[i+1]; j++){
1827 if (!HIGHLIGHT_SET || (grouping[i] == grouping[graph->ja[j]] && grouping[i] == HIGHLIGHT_SET)){
1828 for (t = 0; t < np; t++){
1829 for (k = 0; k < dim; k++){
1830 y[nz*dim+k] = t/((real) np)*x[i*dim+k] + (1-t/((real) np))*x[(graph->ja[j])*dim + k];
1831 }
1832 assert(n + (nz-n)*np + t < n + nz*np && n + (nz-n)*np + t >= 0);
1833 if (t/((real) np) > 0.5){
1834 grouping[nz] = grouping[i];
1835 } else {
1836 grouping[nz] = grouping[graph->ja[j]];
1837 }
1838 nz++;
1839 }
1840 }
1841 }
1842 }
1843 fprintf(stderr, "after adding edge points, n:%d->%d\n",n, nz);
1844 n = nz;
1845 x = y;
1846 qt = QuadTree_new_from_point_list(dim, nz, max_qtree_level, y, NULL);
1847 } else {
1848 qt = QuadTree_new_from_point_list(dim, n, max_qtree_level, x, NULL);
1849 }
1850 }
1851 graph = NULL;
1852
1853
1854 /* generate random points for lake/sea effect */
1855 if (*nrandom != 0){
1856 for (i = 0; i < dim2; i++) {
1857 if (bounding_box_margin[i] > 0){
1858 xmin[i] -= bounding_box_margin[i];
1859 xmax[i] += bounding_box_margin[i];
1860 } else if (bounding_box_margin[i] == 0) {/* auto bounding box */
1861 xmin[i] -= MAX(boxsize[i]*0.2, 2.*shore_depth_tol);
1862 xmax[i] += MAX(boxsize[i]*0.2, 2*shore_depth_tol);
1863 } else {
1864 xmin[i] -= boxsize[i]*(-bounding_box_margin[i]);
1865 xmax[i] += boxsize[i]*(-bounding_box_margin[i]);
1866 }
1867 }
1868 if (Verbose) {
1869 real bbm0 = bounding_box_margin[0];
1870 real bbm1 = bounding_box_margin[1];
1871 if (bbm0 > 0)
1872 fprintf (stderr, "bounding box margin: %.06f", bbm0);
1873 else if (bbm0 == 0)
1874 fprintf (stderr, "bounding box margin: %.06f", MAX(boxsize[0]*0.2, 2*shore_depth_tol));
1875 else
1876 fprintf (stderr, "bounding box margin: (%.06f * %.06f)", boxsize[0], -bbm0);
1877 if (bbm1 > 0)
1878 fprintf (stderr, " %.06f\n", bbm1);
1879 else if (bbm1 == 0)
1880 fprintf (stderr, " %.06f\n", MAX(boxsize[1]*0.2, 2*shore_depth_tol));
1881 else
1882 fprintf (stderr, " (%.06f * %.06f)\n", boxsize[1], -bbm1);
1883 }
1884 if (*nrandom < 0) {
1885 real n1, n2, area2;
1886 area2 = (xmax[1] - xmin[1])*(xmax[0] - xmin[0]);
1887 n1 = (int) area2/(shore_depth_tol*shore_depth_tol);
1888 n2 = n*((int) area2/area);
1889 *nrandom = MAX(n1, n2);
1890 }
1891 srand(123);
1892 xran = MALLOC(sizeof(real)*(*nrandom + 4)*dim2);
1893 nz = 0;
1894 if (INCLUDE_OK_POINTS){
1895 int *grouping2;
1896 nzok0 = nzok = *nrandom - 1;/* points that are within tolerance of real or artificial points */
1897 grouping2 = MALLOC(sizeof(int)*(n + *nrandom));
1898 memcpy(grouping2, grouping, sizeof(int)*n);
1899 grouping = grouping2;
1900 }
1901 nn = n;
1902
1903 for (i = 0; i < *nrandom; i++){
1904
1905 for (j = 0; j < dim2; j++){
1906 point[j] = xmin[j] + (xmax[j] - xmin[j])*drand();
1907 }
1908
1909 QuadTree_get_nearest(qt, point, ymin, &imin, &min, flag);
1910 assert(!(*flag));
1911
1912 if (min > shore_depth_tol){/* point not too close, accepted */
1913 for (j = 0; j < dim2; j++){
1914 xran[nz*dim2+j] = point[j];
1915 }
1916 nz++;
1917 } else if (INCLUDE_OK_POINTS && min > shore_depth_tol/10){/* avoid duplicate points */
1918 for (j = 0; j < dim2; j++){
1919 xran[nzok*dim2+j] = point[j];
1920 }
1921 grouping[nn++] = grouping[imin];
1922 nzok--;
1923
1924 }
1925
1926 }
1927 *nrandom = nz;
1928 if (Verbose) fprintf( stderr, "nn nrandom=%d\n",*nrandom);
1929 } else {
1930 xran = MALLOC(sizeof(real)*4*dim2);
1931 }
1932
1933
1934
1935 /* add 4 corners even if nrandom = 0. The corners should be further away from the other points to avoid skinny triangles */
1936 for (i = 0; i < dim2; i++) xmin[i] -= 0.2*(xmax[i]-xmin[i]);
1937 for (i = 0; i < dim2; i++) xmax[i] += 0.2*(xmax[i]-xmin[i]);
1938 i = *nrandom;
1939 for (j = 0; j < dim2; j++) xran[i*dim2+j] = xmin[j];
1940 i++;
1941 for (j = 0; j < dim2; j++) xran[i*dim2+j] = xmax[j];
1942 i++;
1943 xran[i*dim2] = xmin[0]; xran[i*dim2+1] = xmax[1];
1944 i++;
1945 xran[i*dim2] = xmax[0]; xran[i*dim2+1] = xmin[1];
1946 *nrandom += 4;
1947
1948
1949 if (INCLUDE_OK_POINTS){
1950 *xcombined = MALLOC(sizeof(real)*(nn+*nrandom)*dim2);
1951 } else {
1952 *xcombined = MALLOC(sizeof(real)*(n+*nrandom)*dim2);
1953 }
1954 for (i = 0; i < n; i++) {
1955 for (j = 0; j < dim2; j++) (*xcombined)[i*dim2+j] = x[i*dim+j];
1956 }
1957 for (i = 0; i < *nrandom; i++) {
1958 for (j = 0; j < dim2; j++) (*xcombined)[(i + nn)*dim2+j] = xran[i*dim+j];
1959 }
1960
1961 if (INCLUDE_OK_POINTS){
1962 for (i = 0; i < nn - n; i++) {
1963 for (j = 0; j < dim2; j++) (*xcombined)[(i + n)*dim2+j] = xran[(nzok0 - i)*dim+j];
1964 }
1965 n = nn;
1966 }
1967
1968
1969 {
1970 int nz, nh = 0;/* the set to highlight */
1971 real *xtemp;
1972 if (HIGHLIGHT_SET){
1973 if (Verbose) fprintf(stderr," highlight cluster %d, n = %d\n",HIGHLIGHT_SET, n);
1974 xtemp = MALLOC(sizeof(real)*n*dim);
1975 /* shift set to the beginning */
1976 nz = 0;
1977 for (i = 0; i < n; i++){
1978 if (grouping[i] == HIGHLIGHT_SET){
1979 nh++;
1980 for (j = 0; j < dim; j++){
1981 xtemp[nz++] = x[i*dim+j];
1982 }
1983 }
1984 }
1985 for (i = 0; i < n; i++){
1986 if (grouping[i] != HIGHLIGHT_SET){
1987 for (j = 0; j < dim; j++){
1988 xtemp[nz++] = x[i*dim+j];
1989 }
1990 }
1991 }
1992 assert(nz == n*dim);
1993 for (i = 0; i < nh; i++){
1994 grouping[i] = 1;
1995 }
1996 for (i = nh; i < n; i++){
1997 grouping[i] = 2;
1998 }
1999 memcpy(*xcombined, xtemp, n*dim*sizeof(real));
2000 *nrandom = *nrandom + n - nh;/* count everything except cluster HIGHLIGHT_SET as random */
2001 n = nh;
2002 if (Verbose) fprintf(stderr,"nh = %d\n",nh);
2003 FREE(xtemp);
2004 }
2005 }
2006
2007 get_tri(n + *nrandom, dim2, *xcombined, &nt, &Tp, &E, flag);
2008 get_polygons(exclude_random, n, *nrandom, dim2, graph, *xcombined, grouping, nt, Tp, E, nverts, x_poly, npolys, poly_lines, polys, polys_groups,
2009 poly_point_map, country_graph, flag);
2010 /*
2011 {
2012 plot_voronoi(n + *nrandom, E, Tp);
2013 printf("(*voronoi*),");
2014
2015 }
2016 */
2017
2018
2019
2020
2021 SparseMatrix_delete(E);
2022 FREE(Tp);
2023 FREE(xran);
2024 if (grouping != grouping0) FREE(grouping);
2025 if (x != x0) FREE(x);
2026 return 0;
2027 }
2028
2029
make_map_from_point_groups(int exclude_random,int include_OK_points,int n,int dim,real * x,int * grouping,SparseMatrix graph,real bounding_box_margin[],int * nrandom,real shore_depth_tol,real edge_bridge_tol,real ** xcombined,int * nverts,real ** x_poly,int * npolys,SparseMatrix * poly_lines,SparseMatrix * polys,int ** polys_groups,SparseMatrix * poly_point_map,SparseMatrix * country_graph,int * flag)2030 int make_map_from_point_groups(int exclude_random, int include_OK_points,
2031 int n, int dim, real *x, int *grouping, SparseMatrix graph, real bounding_box_margin[], int *nrandom,
2032 real shore_depth_tol, real edge_bridge_tol, real **xcombined, int *nverts, real **x_poly,
2033 int *npolys, SparseMatrix *poly_lines, SparseMatrix *polys, int **polys_groups, SparseMatrix *poly_point_map,
2034 SparseMatrix *country_graph, int *flag){
2035
2036 /* create a list of polygons from a list of points in 2D. Points belong to groups. Points in the same group that are also close
2037 gemetrically will be in the same polygon describing the outline of the group.
2038
2039 input:
2040 exclude_random:
2041 include_OK_points: OK points are random points inserted and found to be within shore_depth_tol of real/artificial points,
2042 . including them instead of throwing away increase realism of boundary
2043 n: number of points
2044 dim: dimension of the points. If dim > 2, only the first 2D is used.
2045 x: coordinates
2046 grouping: which group each of the vertex belongs to
2047 graph: the link structure between points. If graph == NULL, this is not used. otherwise
2048 . it is assumed that matrix is symmetric and the graph is undirected
2049 bounding_box_margin: margins used to form the bounding box. Dimension 2.
2050 . if negative, it is taken as relative. i.e., -0.5 means a margin of 0.5*box_size
2051 nrandom (inout): number of random points to insert in the bounding box to figure out lakes and seas.
2052 . If nrandom = 0, no points are inserted, if nrandom < 0, the number is decided automatically.
2053 . On exit, it is the actual number of random points used. The last 4 "random" points is always the
2054 .
2055 shore_depth_tol: nrandom random points are inserted in the bounding box of the points,
2056 . such random points are then weeded out if it is within distance of shore_depth_tol from
2057 . real points. If < 0, auto assigned
2058 edge_bridge_tol: insert points on edges to give an bridge effect.These points will be evenly spaced
2059 . along each edge, and be less than a distance of edge_bridge_tol from each other and from the two ends of the edge.
2060 . If < 0, -edge_bridge_tol is the average number of points inserted per half edge
2061 output:
2062 xcombined: combined points which contains n + ncombined number of points, dimension 2x(n+nrandom)
2063 npolys: number of polygons generated to reprsent the real points, the edge insertion points, and the sea/lake points.
2064 nverts: number of vertices in the Voronoi diagram
2065 x_poly: the 2D coordinates of these polygons
2066 poly_lines: the sparse matrix representation of the polygon indices, as well as their identity. The matrix is of size
2067 . npolygons x nverts. The i-th polygon is formed by linking vertices with index in the i-th row of the sparse matrix.
2068 . Each row is of the form {{i,j1,m},...{i,jk,m},{i,j1,m},{i,l1,m+1},...}, where j1--j2--jk--j1 form one loop,
2069 . and l1 -- l2 -- ... form another. Each row can have more than 1 loop only when the connected region the polylines represent
2070 . has at least 1 holes.
2071 polys: the sparse matrix representation of the polygon indices, as well as their identity. The matrix is of size
2072 . npolygons x nverts. The i-th polygon is formed by linking vertices with index in the i-th row of the sparse matrix.
2073 . Unlike poly_lines, here each row represent an one stroke drawing of the SOLID polygon, vertices
2074 . along this path may repeat
2075 polys_groups: the group (color) each polygon belongs to, this include all groups of the real points,
2076 . plus the random point group and the bounding box group
2077 poly_point_map: a matrix of dimension npolys x (n + nrandom), poly_point_map[i,j] != 0 if polygon i contains the point j.
2078 . If j < n, it is the original point, otherwise it is
2079 country_graph: shows which country is a neighbor of which country.
2080 . if country i and country j are neighbor, then the {i,j} entry is the total number of vertices that
2081 . belongs to i and j, and share an edge of the triangulation. In addition, {i,i} and {j,j} have values equal
2082 . to the number of vertices in each of the countries. If the input "grouping" has negative or zero value, then
2083 . country_graph = NULL.
2084
2085 */
2086 int res;
2087 int nedgep = 0;
2088 int highlight_cluster = FALSE;
2089 /* get poly outlines */
2090 res = make_map_internal(exclude_random, include_OK_points, n, dim, x, grouping, graph, bounding_box_margin, nrandom, nedgep,
2091 shore_depth_tol, edge_bridge_tol, xcombined, nverts, x_poly,
2092 npolys, poly_lines, polys, polys_groups, poly_point_map, country_graph, highlight_cluster, flag);
2093
2094 printf("Show[{");
2095
2096 plot_points(n + *nrandom, dim, *xcombined);
2097
2098
2099 printf(",");
2100 plot_polys(TRUE, *poly_lines, *x_poly, *polys_groups, NULL, NULL, NULL);
2101
2102 printf("}]\n");
2103
2104 return res;
2105 }
2106
add_point(int * n,int igrp,real ** x,int * nmax,real point[],int ** groups)2107 static void add_point(int *n, int igrp, real **x, int *nmax, real point[], int **groups){
2108
2109 if (*n >= *nmax){
2110 *nmax = MAX((int) 0.2*(*n), 20) + *n;
2111 *x = REALLOC(*x, sizeof(real)*2*(*nmax));
2112 *groups = REALLOC(*groups, sizeof(int)*(*nmax));
2113 }
2114
2115 (*x)[(*n)*2] = point[0];
2116 (*x)[(*n)*2+1] = point[1];
2117 (*groups)[*n] = igrp;
2118 (*n)++;
2119
2120 }
2121
get_boundingbox(int n,int dim,real * x,real * width,real * bbox)2122 static void get_boundingbox(int n, int dim, real *x, real *width, real *bbox){
2123 int i;
2124 bbox[0] = bbox[1] = x[0];
2125 bbox[2] = bbox[3] = x[1];
2126
2127 for (i = 0; i < n; i++){
2128 bbox[0] = MIN(bbox[0], x[i*dim] - width[i*dim]);
2129 bbox[1] = MAX(bbox[1], x[i*dim] + width[i*dim]);
2130 bbox[2] = MIN(bbox[2], x[i*dim + 1] - width[i*dim+1]);
2131 bbox[3] = MAX(bbox[3], x[i*dim + 1] + width[i*dim+1]);
2132 }
2133 }
2134
2135
make_map_from_rectangle_groups(int exclude_random,int include_OK_points,int n,int dim,real * x,real * sizes,int * grouping,SparseMatrix graph0,real bounding_box_margin[],int * nrandom,int * nart,int nedgep,real shore_depth_tol,real edge_bridge_tol,real ** xcombined,int * nverts,real ** x_poly,int * npolys,SparseMatrix * poly_lines,SparseMatrix * polys,int ** polys_groups,SparseMatrix * poly_point_map,SparseMatrix * country_graph,int highlight_cluster,int * flag)2136 int make_map_from_rectangle_groups(int exclude_random, int include_OK_points,
2137 int n, int dim, real *x, real *sizes,
2138 int *grouping, SparseMatrix graph0, real bounding_box_margin[], int *nrandom, int *nart, int nedgep,
2139 real shore_depth_tol, real edge_bridge_tol,
2140 real **xcombined, int *nverts, real **x_poly,
2141 int *npolys, SparseMatrix *poly_lines, SparseMatrix *polys, int **polys_groups, SparseMatrix *poly_point_map,
2142 SparseMatrix *country_graph, int highlight_cluster, int *flag){
2143
2144 /* create a list of polygons from a list of rectangles in 2D. rectangles belong to groups. rectangles in the same group that are also close
2145 geometrically will be in the same polygon describing the outline of the group. The main difference for this function and
2146 make_map_from_point_groups is that in this function, the input are points with width/heights, and we try not to place
2147 "lakes" inside these rectangles. This is achieved approximately by adding artificial points along the perimeter of the rectangles,
2148 as well as near the center.
2149
2150 input:
2151 include_OK_points: OK points are random points inserted and found to be within shore_depth_tol of real/artificial points,
2152 . including them instead of throwing away increase realism of boundary
2153 n: number of points
2154 dim: dimension of the points. If dim > 2, only the first 2D is used.
2155 x: coordinates
2156 sizes: width and height
2157 grouping: which group each of the vertex belongs to
2158 graph: the link structure between points. If graph == NULL, this is not used. otherwise
2159 . it is assumed that matrix is symmetric and the graph is undirected
2160 bounding_box_margin: margins used to form the bounding box. Dimension 2.
2161 . if negative, it is taken as relative. i.e., -0.5 means a margin of 0.5*box_size
2162 nrandom (inout): number of random points to insert in the bounding box to figure out lakes and seas.
2163 . If nrandom = 0, no points are inserted, if nrandom < 0, the number is decided automatically.
2164 . On exit, it is the actual number of random points used. The last 4 "random" points is always the
2165 .
2166 nart: on entry, number of artificial points to be added along each side of a rectangle enclosing the labels. if < 0, auto-selected.
2167 . On exit, actual number of artificial points added.
2168 nedgep: number of artificial points are adding along edges to establish as much as possible a bright between nodes
2169 . connected by the edge, and avoid islands that are connected. k = 0 mean no points.
2170 shore_depth_tol: nrandom random points are inserted in the bounding box of the points,
2171 . such random points are then weeded out if it is within distance of shore_depth_tol from
2172 . real points. If 0, auto assigned
2173 edge_bridge_tol: insert points on edges to give an bridge effect.These points will be evenly spaced
2174 . along each edge, and be less than a distance of edge_bridge_tol from each other and from the two ends of the edge.
2175 . If < 0, -edge_bridge_tol is the average number of points inserted per half edge
2176
2177 output:
2178 xcombined: combined points which contains n + ncombined number of points, dimension 2x(n+nrandom)
2179 npolys: number of polygons generated to reprsent the real points, the edge insertion points, and the sea/lake points.
2180 nverts: number of vertices in the Voronoi diagram
2181 x_poly: the 2D coordinates of these polygons, dimension nverts*2
2182 poly_lines: the sparse matrix representation of the polygon indices, as well as their identity. The matrix is of size
2183 . npolygons x nverts. The i-th polygon is formed by linking vertices with index in the i-th row of the sparse matrix.
2184 . Each row is of the form {{i,j1,m},...{i,jk,m},{i,j1,m},{i,l1,m+1},...}, where j1--j2--jk--j1 form one loop,
2185 . and l1 -- l2 -- ... form another. Each row can have more than 1 loop only when the connected region the polylines represent
2186 . has at least 1 holes.
2187 polys: the sparse matrix representation of the polygon indices, as well as their identity. The matrix is of size
2188 . npolygons x nverts. The i-th polygon is formed by linking vertices with index in the i-th row of the sparse matrix.
2189 . Unlike poly_lines, here each row represent an one stroke drawing of the SOLID polygon, vertices
2190 . along this path may repeat
2191 polys_groups: the group (color) each polygon belongs to, this include all groups of the real points,
2192 . plus the random point group and the bounding box group
2193 poly_point_map: a matrix of dimension npolys x (n + nrandom), poly_point_map[i,j] != 0 if polygon i contains the point j.
2194 . If j < n, it is the original point, otherwise it is artificial point (forming the rectangle around a label) or random points.
2195 country_graph: shows which country is a neighbor of which country.
2196 . if country i and country j are neighbor, then the {i,j} entry is the total number of vertices that
2197 . belongs to i and j, and share an edge of the triangulation. In addition, {i,i} and {j,j} have values equal
2198 . to the number of vertices in each of the countries. If the input "grouping" has negative or zero value, then
2199 . country_graph = NULL.
2200
2201
2202 */
2203 real dist, avgdist;
2204 real *X;
2205 int N, nmax, i, j, k, igrp;
2206 int *groups, K = *nart;/* average number of points added per side of rectangle */
2207
2208 real avgsize[2], avgsz, h[2], p1, p0;
2209 real point[2];
2210 int nadded[2];
2211 int res;
2212 real delta[2];
2213 SparseMatrix graph = graph0;
2214 real bbox[4];
2215
2216 if (K < 0){
2217 K = (int) 10/(1+n/400.);/* 0 if n > 3600*/
2218 }
2219 *nart = 0;
2220 if (Verbose){
2221 int maxgp = grouping[0];
2222 int mingp = grouping[0];
2223 for (i = 0; i < n; i++) {
2224 maxgp = MAX(maxgp, grouping[i]);
2225 mingp = MIN(mingp, grouping[i]);
2226 }
2227 fprintf(stderr, "max grouping - min grouping + 1 = %d\n",maxgp - mingp + 1);
2228 }
2229
2230 if (!sizes){
2231 return make_map_internal(exclude_random, include_OK_points, n, dim, x, grouping, graph, bounding_box_margin, nrandom, nedgep,
2232 shore_depth_tol, edge_bridge_tol, xcombined, nverts, x_poly,
2233 npolys, poly_lines, polys, polys_groups, poly_point_map, country_graph, highlight_cluster, flag);
2234 } else {
2235
2236 /* add artificial node due to node sizes */
2237 avgsize[0] = 0;
2238 avgsize[1] = 0;
2239 for (i = 0; i < n; i++){
2240 for (j = 0; j < 2; j++) {
2241 avgsize[j] += sizes[i*dim+j];
2242 }
2243 }
2244 for (i = 0; i < 2; i++) avgsize[i] /= n;
2245 avgsz = 0.5*(avgsize[0] + avgsize[1]);
2246 if (Verbose) fprintf(stderr, "avgsize = {%f, %f}\n",avgsize[0], avgsize[1]);
2247
2248 nmax = 2*n;
2249 X = MALLOC(sizeof(real)*dim*(n+nmax));
2250 groups = MALLOC(sizeof(int)*(n+nmax));
2251 for (i = 0; i < n; i++) {
2252 groups[i] = grouping[i];
2253 for (j = 0; j < 2; j++){
2254 X[i*2+j] = x[i*dim+j];
2255 }
2256 }
2257 N = n;
2258
2259 if (shore_depth_tol < 0) {
2260 shore_depth_tol = -(shore_depth_tol)*avgsz;
2261 } else if (shore_depth_tol == 0){
2262 real area;
2263 get_boundingbox(n, dim, x, sizes, bbox);
2264 //shore_depth_tol = MIN(bbox[1] - bbox[0], bbox[3] - bbox[2])*0.05;
2265 area = (bbox[1] - bbox[0])*(bbox[3] - bbox[2]);
2266 shore_depth_tol = sqrt(area/(real) n);
2267 if (Verbose) fprintf(stderr,"setting shore length ======%f\n",shore_depth_tol);
2268 } else {
2269 /*
2270 get_boundingbox(n, dim, x, sizes, bbox);
2271 shore_depth_tol = MIN(bbox[1] - bbox[0], bbox[3] - bbox[2])*shore_depth_tol;
2272 */
2273
2274 }
2275
2276 /* add artificial points in an anti-clockwise fashion */
2277
2278 if (K > 0){
2279 delta[0] = .5*avgsize[0]/K; delta[1] = .5*avgsize[1]/K;/* small perturbation to make boundary between labels looks more fractal */
2280 } else {
2281 delta[0] = delta[1] = 0.;
2282 }
2283 for (i = 0; i < n; i++){
2284 igrp = grouping[i];
2285 for (j = 0; j < 2; j++) {
2286 if (avgsz == 0){
2287 nadded[j] = 0;
2288 } else {
2289 nadded[j] = (int) K*sizes[i*dim+j]/avgsz;
2290 }
2291 }
2292
2293 /*top: left to right */
2294 if (nadded[0] > 0){
2295 h[0] = sizes[i*dim]/nadded[0];
2296 point[0] = x[i*dim] - sizes[i*dim]/2;
2297 p1 = point[1] = x[i*dim+1] + sizes[i*dim + 1]/2;
2298 add_point(&N, igrp, &X, &nmax, point, &groups);
2299 for (k = 0; k < nadded[0] - 1; k++){
2300 point[0] += h[0];
2301 point[1] = p1 + (0.5-drand())*delta[1];
2302 add_point(&N, igrp, &X, &nmax, point, &groups);
2303 }
2304
2305 /* bot: right to left */
2306 point[0] = x[i*dim] + sizes[i*dim]/2;
2307 p1 = point[1] = x[i*dim+1] - sizes[i*dim + 1]/2;
2308 add_point(&N, igrp, &X, &nmax, point, &groups);
2309 for (k = 0; k < nadded[0] - 1; k++){
2310 point[0] -= h[0];
2311 point[1] = p1 + (0.5-drand())*delta[1];
2312 add_point(&N, igrp, &X, &nmax, point, &groups);
2313 }
2314 }
2315
2316 if (nadded[1] > 0){
2317 /* left: bot to top */
2318 h[1] = sizes[i*dim + 1]/nadded[1];
2319 p0 = point[0] = x[i*dim] - sizes[i*dim]/2;
2320 point[1] = x[i*dim+1] - sizes[i*dim + 1]/2;
2321 add_point(&N, igrp, &X, &nmax, point, &groups);
2322 for (k = 0; k < nadded[1] - 1; k++){
2323 point[0] = p0 + (0.5-drand())*delta[0];
2324 point[1] += h[1];
2325 add_point(&N, igrp, &X, &nmax, point, &groups);
2326 }
2327
2328 /* right: top to bot */
2329 p0 = point[0] = x[i*dim] + sizes[i*dim]/2;
2330 point[1] = x[i*dim+1] + sizes[i*dim + 1]/2;
2331 add_point(&N, igrp, &X, &nmax, point, &groups);
2332 for (k = 0; k < nadded[1] - 1; k++){
2333 point[0] = p0 + (0.5-drand())*delta[0];
2334 point[1] -= h[1];
2335 add_point(&N, igrp, &X, &nmax, point, &groups);
2336 }
2337 }
2338 *nart = N - n;
2339
2340 }/* done adding artificial points due to node size*/
2341
2342
2343 /* add artificial node due to edges */
2344 if (graph && edge_bridge_tol != 0){
2345 int *ia = graph->ia, *ja = graph->ja, nz = 0, jj;
2346 int KB;
2347
2348 graph = SparseMatrix_symmetrize(graph, TRUE);
2349 ia = graph->ia; ja = graph->ja;
2350 dist=avgdist = 0.;
2351 for (i = 0; i < n; i++){
2352 for (j = ia[i]; j < ia[i+1]; j++){
2353 jj = ja[j];
2354 if (jj <= i) continue;
2355 dist = distance(x, dim, i, jj);
2356 avgdist += dist;
2357 nz++;
2358 }
2359 }
2360 avgdist /= nz;
2361 if (edge_bridge_tol < 0){
2362 KB = (int) (-edge_bridge_tol);
2363 } else {
2364 KB = (int) (avgdist/edge_bridge_tol);
2365 }
2366
2367 assert(avgdist > 0);
2368 for (i = 0; i < n; i++){
2369 for (j = ia[i]; j < ia[i+1]; j++){
2370 jj = ja[j];
2371 if (jj <= i) continue;
2372 dist = distance(x, dim, i, jj);
2373 nadded[0] = (int) 2*KB*dist/avgdist;
2374
2375 /* half the line segment near i */
2376 h[0] = 0.5*(x[jj*dim] - x[i*dim])/nadded[0];
2377 h[1] = 0.5*(x[jj*dim+1] - x[i*dim+1])/nadded[0];
2378 point[0] = x[i*dim];
2379 point[1] = x[i*dim+1];
2380 for (k = 0; k < nadded[0] - 1; k++){
2381 point[0] += h[0];
2382 point[1] += h[1];
2383 add_point(&N, grouping[i], &X, &nmax, point, &groups);
2384 }
2385
2386 /* half the line segment near jj */
2387 h[0] = 0.5*(x[i*dim] - x[jj*dim])/nadded[0];
2388 h[1] = 0.5*(x[i*dim+1] - x[jj*dim+1])/nadded[0];
2389 point[0] = x[jj*dim];
2390 point[1] = x[jj*dim+1];
2391 for (k = 0; k < nadded[0] - 1; k++){
2392 point[0] += h[0];
2393 point[1] += h[1];
2394 add_point(&N, grouping[jj], &X, &nmax, point, &groups);
2395 }
2396 }
2397
2398 }/* done adding artifial points for edges */
2399 }
2400
2401 res = make_map_internal(exclude_random, include_OK_points, N, dim, X, groups, graph, bounding_box_margin, nrandom, nedgep,
2402 shore_depth_tol, edge_bridge_tol, xcombined, nverts, x_poly,
2403 npolys, poly_lines, polys, polys_groups, poly_point_map, country_graph, highlight_cluster, flag);
2404 if (graph != graph0) SparseMatrix_delete(graph);
2405 FREE(groups);
2406 FREE(X);
2407 }
2408
2409 return res;
2410
2411 }
2412