1 /* -*- mode: C -*- */
2 /*
3 IGraph R package.
4 Copyright (C) 2006-2012 Gabor Csardi <csardi.gabor@gmail.com>
5 334 Harvard street, Cambridge, MA 02139 USA
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 02110-1301 USA
21
22 */
23
24 #include "igraph_types.h"
25 #include "igraph_types_internal.h"
26 #include "igraph_memory.h"
27 #include "config.h"
28
29 #include <math.h>
30
31 /* internal function */
32
igraph_2dgrid_which(igraph_2dgrid_t * grid,igraph_real_t xc,igraph_real_t yc,long int * x,long int * y)33 int igraph_2dgrid_which(igraph_2dgrid_t *grid, igraph_real_t xc, igraph_real_t yc,
34 long int *x, long int *y) {
35
36 if (xc <= grid->minx) {
37 *x = 0;
38 } else if (xc >= grid->maxx) {
39 *x = grid->stepsx - 1;
40 } else {
41 *x = (long int) floor((xc - (grid->minx)) / (grid->deltax));
42 }
43
44 if (yc <= grid->miny) {
45 *y = 0;
46 } else if (yc >= grid->maxy) {
47 *y = grid->stepsy - 1;
48 } else {
49 *y = (long int) floor((yc - (grid->miny)) / (grid->deltay));
50 }
51
52 return 0;
53 }
54
igraph_2dgrid_init(igraph_2dgrid_t * grid,igraph_matrix_t * coords,igraph_real_t minx,igraph_real_t maxx,igraph_real_t deltax,igraph_real_t miny,igraph_real_t maxy,igraph_real_t deltay)55 int igraph_2dgrid_init(igraph_2dgrid_t *grid, igraph_matrix_t *coords,
56 igraph_real_t minx, igraph_real_t maxx, igraph_real_t deltax,
57 igraph_real_t miny, igraph_real_t maxy, igraph_real_t deltay) {
58 long int i;
59
60 grid->coords = coords;
61 grid->minx = minx;
62 grid->maxx = maxx;
63 grid->deltax = deltax;
64 grid->miny = miny;
65 grid->maxy = maxy;
66 grid->deltay = deltay;
67
68 grid->stepsx = (long int) ceil((maxx - minx) / deltax);
69 grid->stepsy = (long int) ceil((maxy - miny) / deltay);
70
71 IGRAPH_CHECK(igraph_matrix_init(&grid->startidx,
72 grid->stepsx, grid->stepsy));
73 IGRAPH_FINALLY(igraph_matrix_destroy, &grid->startidx);
74 IGRAPH_VECTOR_INIT_FINALLY(&grid->next, igraph_matrix_nrow(coords));
75 IGRAPH_VECTOR_INIT_FINALLY(&grid->prev, igraph_matrix_nrow(coords));
76
77 for (i = 0; i < igraph_vector_size(&grid->next); i++) {
78 VECTOR(grid->next)[i] = -1;
79 }
80
81 grid->massx = 0;
82 grid->massy = 0;
83 grid->vertices = 0;
84
85 IGRAPH_FINALLY_CLEAN(3);
86 return 0;
87 }
88
igraph_2dgrid_destroy(igraph_2dgrid_t * grid)89 void igraph_2dgrid_destroy(igraph_2dgrid_t *grid) {
90 igraph_matrix_destroy(&grid->startidx);
91 igraph_vector_destroy(&grid->next);
92 igraph_vector_destroy(&grid->prev);
93 }
94
igraph_2dgrid_add(igraph_2dgrid_t * grid,long int elem,igraph_real_t xc,igraph_real_t yc)95 void igraph_2dgrid_add(igraph_2dgrid_t *grid, long int elem,
96 igraph_real_t xc, igraph_real_t yc) {
97 long int x, y;
98 long int first;
99
100 MATRIX(*grid->coords, elem, 0) = xc;
101 MATRIX(*grid->coords, elem, 1) = yc;
102
103 /* add to cell */
104 igraph_2dgrid_which(grid, xc, yc, &x, &y);
105 first = (long int) MATRIX(grid->startidx, x, y);
106 VECTOR(grid->prev)[elem] = 0;
107 VECTOR(grid->next)[elem] = first;
108 if (first != 0) {
109 VECTOR(grid->prev)[first - 1] = elem + 1;
110 }
111 MATRIX(grid->startidx, x, y) = elem + 1;
112
113 grid->massx += xc;
114 grid->massy += yc;
115 grid->vertices += 1;
116 }
117
igraph_2dgrid_add2(igraph_2dgrid_t * grid,long int elem)118 void igraph_2dgrid_add2(igraph_2dgrid_t *grid, long int elem) {
119 long int x, y;
120 long int first;
121 igraph_real_t xc, yc;
122
123 xc = MATRIX(*grid->coords, elem, 0);
124 yc = MATRIX(*grid->coords, elem, 1);
125
126 /* add to cell */
127 igraph_2dgrid_which(grid, xc, yc, &x, &y);
128 first = (long int) MATRIX(grid->startidx, x, y);
129 VECTOR(grid->prev)[elem] = 0;
130 VECTOR(grid->next)[elem] = first;
131 if (first != 0) {
132 VECTOR(grid->prev)[first - 1] = elem + 1;
133 }
134 MATRIX(grid->startidx, x, y) = elem + 1;
135
136 grid->massx += xc;
137 grid->massy += yc;
138 grid->vertices += 1;
139 }
140
igraph_2dgrid_move(igraph_2dgrid_t * grid,long int elem,igraph_real_t xc,igraph_real_t yc)141 void igraph_2dgrid_move(igraph_2dgrid_t *grid, long int elem,
142 igraph_real_t xc, igraph_real_t yc) {
143 long int oldx, oldy;
144 long int newx, newy;
145 igraph_real_t oldxc = MATRIX(*grid->coords, elem, 0);
146 igraph_real_t oldyc = MATRIX(*grid->coords, elem, 1);
147 long int first;
148
149 xc = oldxc + xc; yc = oldyc + yc;
150
151 igraph_2dgrid_which(grid, oldxc, oldyc, &oldx, &oldy);
152 igraph_2dgrid_which(grid, xc, yc, &newx, &newy);
153 if (oldx != newx || oldy != newy) {
154 /* remove from this cell */
155 if (VECTOR(grid->prev)[elem] != 0) {
156 VECTOR(grid->next) [ (long int) VECTOR(grid->prev)[elem] - 1 ] =
157 VECTOR(grid->next)[elem];
158 } else {
159 MATRIX(grid->startidx, oldx, oldy) = VECTOR(grid->next)[elem];
160 }
161 if (VECTOR(grid->next)[elem] != 0) {
162 VECTOR(grid->prev)[ (long int) VECTOR(grid->next)[elem] - 1 ] =
163 VECTOR(grid->prev)[elem];
164 }
165
166 /* add to this cell */
167 first = (long int) MATRIX(grid->startidx, newx, newy);
168 VECTOR(grid->prev)[elem] = 0;
169 VECTOR(grid->next)[elem] = first;
170 if (first != 0) {
171 VECTOR(grid->prev)[first - 1] = elem + 1;
172 }
173 MATRIX(grid->startidx, newx, newy) = elem + 1;
174 }
175
176 grid->massx += -oldxc + xc;
177 grid->massy += -oldyc + yc;
178
179 MATRIX(*grid->coords, elem, 0) = xc;
180 MATRIX(*grid->coords, elem, 1) = yc;
181
182 }
183
igraph_2dgrid_getcenter(const igraph_2dgrid_t * grid,igraph_real_t * massx,igraph_real_t * massy)184 void igraph_2dgrid_getcenter(const igraph_2dgrid_t *grid,
185 igraph_real_t *massx, igraph_real_t *massy) {
186 *massx = (grid->massx) / (grid->vertices);
187 *massy = (grid->massy) / (grid->vertices);
188 }
189
igraph_2dgrid_in(const igraph_2dgrid_t * grid,long int elem)190 igraph_bool_t igraph_2dgrid_in(const igraph_2dgrid_t *grid, long int elem) {
191 return VECTOR(grid->next)[elem] != -1;
192 }
193
igraph_2dgrid_dist(const igraph_2dgrid_t * grid,long int e1,long int e2)194 igraph_real_t igraph_2dgrid_dist(const igraph_2dgrid_t *grid,
195 long int e1, long int e2) {
196 igraph_real_t x = MATRIX(*grid->coords, e1, 0) - MATRIX(*grid->coords, e2, 0);
197 igraph_real_t y = MATRIX(*grid->coords, e1, 1) - MATRIX(*grid->coords, e2, 1);
198
199 return sqrt(x * x + y * y);
200 }
201
igraph_2dgrid_dist2(const igraph_2dgrid_t * grid,long int e1,long int e2)202 igraph_real_t igraph_2dgrid_dist2(const igraph_2dgrid_t *grid,
203 long int e1, long int e2) {
204 igraph_real_t x = MATRIX(*grid->coords, e1, 0) - MATRIX(*grid->coords, e2, 0);
205 igraph_real_t y = MATRIX(*grid->coords, e1, 1) - MATRIX(*grid->coords, e2, 1);
206
207 return x * x + y * y;
208 }
209
igraph_i_2dgrid_addvertices(igraph_2dgrid_t * grid,igraph_vector_t * eids,igraph_integer_t vid,igraph_real_t r,long int x,long int y)210 int igraph_i_2dgrid_addvertices(igraph_2dgrid_t *grid, igraph_vector_t *eids,
211 igraph_integer_t vid, igraph_real_t r,
212 long int x, long int y) {
213 long int act;
214 igraph_real_t *v = VECTOR(grid->next);
215
216 r = r * r;
217 act = (long int) MATRIX(grid->startidx, x, y);
218 while (act != 0) {
219 if (igraph_2dgrid_dist2(grid, vid, act - 1) < r) {
220 IGRAPH_CHECK(igraph_vector_push_back(eids, act - 1));
221 }
222 act = (long int) v[act - 1];
223 }
224 return 0;
225 }
226
igraph_2dgrid_neighbors(igraph_2dgrid_t * grid,igraph_vector_t * eids,igraph_integer_t vid,igraph_real_t r)227 int igraph_2dgrid_neighbors(igraph_2dgrid_t *grid, igraph_vector_t *eids,
228 igraph_integer_t vid, igraph_real_t r) {
229 igraph_real_t xc = MATRIX(*grid->coords, (long int)vid, 0);
230 igraph_real_t yc = MATRIX(*grid->coords, (long int)vid, 1);
231 long int x, y;
232 igraph_vector_clear(eids);
233
234 igraph_2dgrid_which(grid, xc, yc, &x, &y);
235
236 /* this cell */
237 igraph_i_2dgrid_addvertices(grid, eids, vid, r, x, y);
238
239 /* left */
240 if (x != 0) {
241 igraph_i_2dgrid_addvertices(grid, eids, vid, r, x - 1, y);
242 }
243 /* right */
244 if (x != grid->stepsx - 1) {
245 igraph_i_2dgrid_addvertices(grid, eids, vid, r, x + 1, y);
246 }
247 /* up */
248 if (y != 0) {
249 igraph_i_2dgrid_addvertices(grid, eids, vid, r, x, y - 1);
250 }
251 /* down */
252 if (y != grid->stepsy - 1) {
253 igraph_i_2dgrid_addvertices(grid, eids, vid, r, x, y + 1);
254 }
255 /* up & left */
256 if (x != 0 && y != 0) {
257 igraph_i_2dgrid_addvertices(grid, eids, vid, r, x - 1, y - 1);
258 }
259 /* up & right */
260 if (x != grid->stepsx - 1 && y != 0) {
261 igraph_i_2dgrid_addvertices(grid, eids, vid, r, x + 1, y - 1);
262 }
263 /* down & left */
264 if (x != 0 && y != grid->stepsy - 1) {
265 igraph_i_2dgrid_addvertices(grid, eids, vid, r, x - 1, y + 1);
266 }
267 /* down & right */
268 if (x != grid->stepsx - 1 && y != grid->stepsy - 1) {
269 igraph_i_2dgrid_addvertices(grid, eids, vid, r, x - 1, y + 1);
270 }
271
272 return 0;
273 }
274
igraph_2dgrid_reset(igraph_2dgrid_t * grid,igraph_2dgrid_iterator_t * it)275 void igraph_2dgrid_reset(igraph_2dgrid_t *grid, igraph_2dgrid_iterator_t *it) {
276 /* Search for the first cell containing a vertex */
277 it->x = 0; it->y = 0; it->vid = (long int) MATRIX(grid->startidx, 0, 0);
278 while ( it->vid == 0 && (it->x < grid->stepsx - 1 || it->y < grid->stepsy - 1)) {
279 it->x += 1;
280 if (it->x == grid->stepsx) {
281 it->x = 0; it->y += 1;
282 }
283 it->vid = (long int) MATRIX(grid->startidx, it->x, it->y);
284 }
285 }
286
igraph_2dgrid_next(igraph_2dgrid_t * grid,igraph_2dgrid_iterator_t * it)287 igraph_integer_t igraph_2dgrid_next(igraph_2dgrid_t *grid,
288 igraph_2dgrid_iterator_t *it) {
289 long int ret = it->vid;
290
291 if (ret == 0) {
292 return 0;
293 }
294
295 /* First neighbor */
296 it->ncells = -1;
297 if (it->x != grid->stepsx - 1) {
298 it->ncells += 1;
299 it->nx[it->ncells] = it->x + 1;
300 it->ny[it->ncells] = it->y;
301 }
302 if (it->y != grid->stepsy - 1) {
303 it->ncells += 1;
304 it->nx[it->ncells] = it->x;
305 it->ny[it->ncells] = it->y + 1;
306 }
307 if (it->ncells == 1) {
308 it->ncells += 1;
309 it->nx[it->ncells] = it->x + 1;
310 it->ny[it->ncells] = it->y + 1;
311 }
312 it->ncells += 1;
313 it->nx[it->ncells] = it->x;
314 it->ny[it->ncells] = it->y;
315
316 it->nei = (long int) VECTOR(grid->next) [ ret - 1 ];
317 while (it->ncells > 0 && it->nei == 0 ) {
318 it->ncells -= 1;
319 it->nei = (long int) MATRIX(grid->startidx, it->nx[it->ncells], it->ny[it->ncells]);
320 }
321
322 /* Next vertex */
323 it->vid = (long int) VECTOR(grid->next)[ it->vid - 1 ];
324 while ( (it->x < grid->stepsx - 1 || it->y < grid->stepsy - 1) &&
325 it->vid == 0) {
326 it->x += 1;
327 if (it->x == grid->stepsx) {
328 it->x = 0; it->y += 1;
329 }
330 it->vid = (long int) MATRIX(grid->startidx, it->x, it->y);
331 }
332
333 return (igraph_integer_t) ret;
334 }
335
igraph_2dgrid_next_nei(igraph_2dgrid_t * grid,igraph_2dgrid_iterator_t * it)336 igraph_integer_t igraph_2dgrid_next_nei(igraph_2dgrid_t *grid,
337 igraph_2dgrid_iterator_t *it) {
338 long int ret = it->nei;
339
340 if (it->nei != 0) {
341 it->nei = (long int) VECTOR(grid->next) [ ret - 1 ];
342 }
343 while (it->ncells > 0 && it->nei == 0 ) {
344 it->ncells -= 1;
345 it->nei = (long int) MATRIX(grid->startidx, it->nx[it->ncells], it->ny[it->ncells]);
346 }
347
348 return (igraph_integer_t) ret;
349 }
350
351 /*-----------------------------------------------------------------------*/
352
igraph_i_layout_mergegrid_which(igraph_i_layout_mergegrid_t * grid,igraph_real_t xc,igraph_real_t yc,long int * x,long int * y)353 int igraph_i_layout_mergegrid_which(igraph_i_layout_mergegrid_t *grid,
354 igraph_real_t xc, igraph_real_t yc,
355 long int *x, long int *y) {
356 if (xc <= grid->minx) {
357 *x = 0;
358 } else if (xc >= grid->maxx) {
359 *x = grid->stepsx - 1;
360 } else {
361 *x = (long int) floor((xc - (grid->minx)) / (grid->deltax));
362 }
363
364 if (yc <= grid->miny) {
365 *y = 0;
366 } else if (yc >= grid->maxy) {
367 *y = grid->stepsy - 1;
368 } else {
369 *y = (long int) floor((yc - (grid->miny)) / (grid->deltay));
370 }
371
372 return 0;
373 }
374
igraph_i_layout_mergegrid_init(igraph_i_layout_mergegrid_t * grid,igraph_real_t minx,igraph_real_t maxx,long int stepsx,igraph_real_t miny,igraph_real_t maxy,long int stepsy)375 int igraph_i_layout_mergegrid_init(igraph_i_layout_mergegrid_t *grid,
376 igraph_real_t minx, igraph_real_t maxx, long int stepsx,
377 igraph_real_t miny, igraph_real_t maxy, long int stepsy) {
378 grid->minx = minx;
379 grid->maxx = maxx;
380 grid->stepsx = stepsx;
381 grid->deltax = (maxx - minx) / stepsx;
382 grid->miny = miny;
383 grid->maxy = maxy;
384 grid->stepsy = stepsy;
385 grid->deltay = (maxy - miny) / stepsy;
386
387 grid->data = igraph_Calloc(stepsx * stepsy, long int);
388 if (grid->data == 0) {
389 IGRAPH_ERROR("Cannot create grid", IGRAPH_ENOMEM);
390 }
391 return 0;
392 }
393
igraph_i_layout_mergegrid_destroy(igraph_i_layout_mergegrid_t * grid)394 void igraph_i_layout_mergegrid_destroy(igraph_i_layout_mergegrid_t *grid) {
395 igraph_Free(grid->data);
396 }
397
398 #define MAT(i,j) (grid->data[(grid->stepsy)*(j)+(i)])
399 #define DIST2(x2,y2) (sqrt(pow(x-(x2),2)+pow(y-(y2), 2)))
400
igraph_i_layout_merge_place_sphere(igraph_i_layout_mergegrid_t * grid,igraph_real_t x,igraph_real_t y,igraph_real_t r,long int id)401 int igraph_i_layout_merge_place_sphere(igraph_i_layout_mergegrid_t *grid,
402 igraph_real_t x, igraph_real_t y, igraph_real_t r,
403 long int id) {
404 long int cx, cy;
405 long int i, j;
406
407 igraph_i_layout_mergegrid_which(grid, x, y, &cx, &cy);
408
409 MAT(cx, cy) = id + 1;
410
411 #define DIST(i,j) (DIST2(grid->minx+(cx+(i))*grid->deltax, \
412 grid->miny+(cy+(j))*grid->deltay))
413
414 for (i = 0; cx + i < grid->stepsx && DIST(i, 0) < r; i++) {
415 for (j = 0; cy + j < grid->stepsy && DIST(i, j) < r; j++) {
416 MAT(cx + i, cy + j) = id + 1;
417 }
418 }
419
420 #undef DIST
421 #define DIST(i,j) (DIST2(grid->minx+(cx+(i))*grid->deltax, \
422 grid->miny+(cy-(j)+1)*grid->deltay))
423
424 for (i = 0; cx + i < grid->stepsx && DIST(i, 0) < r; i++) {
425 for (j = 1; cy - j > 0 && DIST(i, j) < r; j++) {
426 MAT(cx + i, cy - j) = id + 1;
427 }
428 }
429
430 #undef DIST
431 #define DIST(i,j) (DIST2(grid->minx+(cx-(i)+1)*grid->deltax, \
432 grid->miny+(cy+(j))*grid->deltay))
433
434 for (i = 1; cx - i > 0 && DIST(i, 0) < r; i++) {
435 for (j = 0; cy + j < grid->stepsy && DIST(i, j) < r; j++) {
436 MAT(cx - i, cy + j) = id + 1;
437 }
438 }
439
440 #undef DIST
441 #define DIST(i,j) (DIST2(grid->minx+(cx-(i)+1)*grid->deltax, \
442 grid->miny+(cy-(j)+1)*grid->deltay))
443
444 for (i = 1; cx - i > 0 && DIST(i, 0) < r; i++) {
445 for (j = 1; cy - j > 0 && DIST(i, j) < r; j++) {
446 MAT(cx - i, cy - j) = id + 1;
447 }
448 }
449
450 #undef DIST
451 #undef DIST2
452
453 return 0;
454 }
455
igraph_i_layout_mergegrid_get(igraph_i_layout_mergegrid_t * grid,igraph_real_t x,igraph_real_t y)456 long int igraph_i_layout_mergegrid_get(igraph_i_layout_mergegrid_t *grid,
457 igraph_real_t x, igraph_real_t y) {
458 long int cx, cy;
459 long int res;
460
461 if (x <= grid->minx || x >= grid->maxx ||
462 y <= grid->miny || y >= grid->maxy) {
463 res = -1;
464 } else {
465 igraph_i_layout_mergegrid_which(grid, x, y, &cx, &cy);
466 res = MAT(cx, cy) - 1;
467 }
468
469 return res;
470 }
471
472 #define DIST2(x2,y2) (sqrt(pow(x-(x2),2)+pow(y-(y2), 2)))
473
igraph_i_layout_mergegrid_get_sphere(igraph_i_layout_mergegrid_t * grid,igraph_real_t x,igraph_real_t y,igraph_real_t r)474 long int igraph_i_layout_mergegrid_get_sphere(igraph_i_layout_mergegrid_t *grid,
475 igraph_real_t x, igraph_real_t y, igraph_real_t r) {
476 long int cx, cy;
477 long int i, j;
478 long int ret;
479
480 if (x - r <= grid->minx || x + r >= grid->maxx ||
481 y - r <= grid->miny || y + r >= grid->maxy) {
482 ret = -1;
483 } else {
484 igraph_i_layout_mergegrid_which(grid, x, y, &cx, &cy);
485
486 ret = MAT(cx, cy) - 1;
487
488 #define DIST(i,j) (DIST2(grid->minx+(cx+(i))*grid->deltax, \
489 grid->miny+(cy+(j))*grid->deltay))
490
491 for (i = 0; ret < 0 && cx + i < grid->stepsx && DIST(i, 0) < r; i++) {
492 for (j = 0; ret < 0 && cy + j < grid->stepsy && DIST(i, j) < r; j++) {
493 ret = MAT(cx + i, cy + j) - 1;
494 }
495 }
496
497 #undef DIST
498 #define DIST(i,j) (DIST2(grid->minx+(cx+(i))*grid->deltax, \
499 grid->miny+(cy-(j)+1)*grid->deltay))
500
501 for (i = 0; ret < 0 && cx + i < grid->stepsx && DIST(i, 0) < r; i++) {
502 for (j = 1; ret < 0 && cy - j > 0 && DIST(i, j) < r; j++) {
503 ret = MAT(cx + i, cy - j) - 1;
504 }
505 }
506
507 #undef DIST
508 #define DIST(i,j) (DIST2(grid->minx+(cx-(i)+1)*grid->deltax, \
509 grid->miny+(cy+(j))*grid->deltay))
510
511 for (i = 1; ret < 0 && cx - i > 0 && DIST(i, 0) < r; i++) {
512 for (j = 0; ret < 0 && cy + j < grid->stepsy && DIST(i, j) < r; j++) {
513 ret = MAT(cx - i, cy + j) - 1;
514 }
515 }
516
517 #undef DIST
518 #define DIST(i,j) (DIST2(grid->minx+(cx-(i)+1)*grid->deltax, \
519 grid->miny+(cy-(j)+1)*grid->deltay))
520
521 for (i = 1; ret < 0 && cx + i > 0 && DIST(i, 0) < r; i++) {
522 for (j = 1; ret < 0 && cy + i > 0 && DIST(i, j) < r; j++) {
523 ret = MAT(cx - i, cy - j) - 1;
524 }
525 }
526
527 #undef DIST
528
529 }
530
531 return ret;
532 }
533
534 /* int print_grid(igraph_i_layout_mergegrid_t *grid) { */
535 /* long int i,j; */
536
537 /* for (i=0; i<grid->stepsx; i++) { */
538 /* for (j=0; j<grid->stepsy; j++) { */
539 /* printf("%li ", MAT(i,j)-1); */
540 /* } */
541 /* printf("\n"); */
542 /* } */
543 /* } */
544