/* -*- mode: C -*- */ /* IGraph R package. Copyright (C) 2006-2012 Gabor Csardi 334 Harvard street, Cambridge, MA 02139 USA This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "igraph_types.h" #include "igraph_types_internal.h" #include "igraph_memory.h" #include "config.h" #include /* internal function */ int igraph_2dgrid_which(igraph_2dgrid_t *grid, igraph_real_t xc, igraph_real_t yc, long int *x, long int *y) { if (xc <= grid->minx) { *x = 0; } else if (xc >= grid->maxx) { *x = grid->stepsx - 1; } else { *x = (long int) floor((xc - (grid->minx)) / (grid->deltax)); } if (yc <= grid->miny) { *y = 0; } else if (yc >= grid->maxy) { *y = grid->stepsy - 1; } else { *y = (long int) floor((yc - (grid->miny)) / (grid->deltay)); } return 0; } int 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) { long int i; grid->coords = coords; grid->minx = minx; grid->maxx = maxx; grid->deltax = deltax; grid->miny = miny; grid->maxy = maxy; grid->deltay = deltay; grid->stepsx = (long int) ceil((maxx - minx) / deltax); grid->stepsy = (long int) ceil((maxy - miny) / deltay); IGRAPH_CHECK(igraph_matrix_init(&grid->startidx, grid->stepsx, grid->stepsy)); IGRAPH_FINALLY(igraph_matrix_destroy, &grid->startidx); IGRAPH_VECTOR_INIT_FINALLY(&grid->next, igraph_matrix_nrow(coords)); IGRAPH_VECTOR_INIT_FINALLY(&grid->prev, igraph_matrix_nrow(coords)); for (i = 0; i < igraph_vector_size(&grid->next); i++) { VECTOR(grid->next)[i] = -1; } grid->massx = 0; grid->massy = 0; grid->vertices = 0; IGRAPH_FINALLY_CLEAN(3); return 0; } void igraph_2dgrid_destroy(igraph_2dgrid_t *grid) { igraph_matrix_destroy(&grid->startidx); igraph_vector_destroy(&grid->next); igraph_vector_destroy(&grid->prev); } void igraph_2dgrid_add(igraph_2dgrid_t *grid, long int elem, igraph_real_t xc, igraph_real_t yc) { long int x, y; long int first; MATRIX(*grid->coords, elem, 0) = xc; MATRIX(*grid->coords, elem, 1) = yc; /* add to cell */ igraph_2dgrid_which(grid, xc, yc, &x, &y); first = (long int) MATRIX(grid->startidx, x, y); VECTOR(grid->prev)[elem] = 0; VECTOR(grid->next)[elem] = first; if (first != 0) { VECTOR(grid->prev)[first - 1] = elem + 1; } MATRIX(grid->startidx, x, y) = elem + 1; grid->massx += xc; grid->massy += yc; grid->vertices += 1; } void igraph_2dgrid_add2(igraph_2dgrid_t *grid, long int elem) { long int x, y; long int first; igraph_real_t xc, yc; xc = MATRIX(*grid->coords, elem, 0); yc = MATRIX(*grid->coords, elem, 1); /* add to cell */ igraph_2dgrid_which(grid, xc, yc, &x, &y); first = (long int) MATRIX(grid->startidx, x, y); VECTOR(grid->prev)[elem] = 0; VECTOR(grid->next)[elem] = first; if (first != 0) { VECTOR(grid->prev)[first - 1] = elem + 1; } MATRIX(grid->startidx, x, y) = elem + 1; grid->massx += xc; grid->massy += yc; grid->vertices += 1; } void igraph_2dgrid_move(igraph_2dgrid_t *grid, long int elem, igraph_real_t xc, igraph_real_t yc) { long int oldx, oldy; long int newx, newy; igraph_real_t oldxc = MATRIX(*grid->coords, elem, 0); igraph_real_t oldyc = MATRIX(*grid->coords, elem, 1); long int first; xc = oldxc + xc; yc = oldyc + yc; igraph_2dgrid_which(grid, oldxc, oldyc, &oldx, &oldy); igraph_2dgrid_which(grid, xc, yc, &newx, &newy); if (oldx != newx || oldy != newy) { /* remove from this cell */ if (VECTOR(grid->prev)[elem] != 0) { VECTOR(grid->next) [ (long int) VECTOR(grid->prev)[elem] - 1 ] = VECTOR(grid->next)[elem]; } else { MATRIX(grid->startidx, oldx, oldy) = VECTOR(grid->next)[elem]; } if (VECTOR(grid->next)[elem] != 0) { VECTOR(grid->prev)[ (long int) VECTOR(grid->next)[elem] - 1 ] = VECTOR(grid->prev)[elem]; } /* add to this cell */ first = (long int) MATRIX(grid->startidx, newx, newy); VECTOR(grid->prev)[elem] = 0; VECTOR(grid->next)[elem] = first; if (first != 0) { VECTOR(grid->prev)[first - 1] = elem + 1; } MATRIX(grid->startidx, newx, newy) = elem + 1; } grid->massx += -oldxc + xc; grid->massy += -oldyc + yc; MATRIX(*grid->coords, elem, 0) = xc; MATRIX(*grid->coords, elem, 1) = yc; } void igraph_2dgrid_getcenter(const igraph_2dgrid_t *grid, igraph_real_t *massx, igraph_real_t *massy) { *massx = (grid->massx) / (grid->vertices); *massy = (grid->massy) / (grid->vertices); } igraph_bool_t igraph_2dgrid_in(const igraph_2dgrid_t *grid, long int elem) { return VECTOR(grid->next)[elem] != -1; } igraph_real_t igraph_2dgrid_dist(const igraph_2dgrid_t *grid, long int e1, long int e2) { igraph_real_t x = MATRIX(*grid->coords, e1, 0) - MATRIX(*grid->coords, e2, 0); igraph_real_t y = MATRIX(*grid->coords, e1, 1) - MATRIX(*grid->coords, e2, 1); return sqrt(x * x + y * y); } igraph_real_t igraph_2dgrid_dist2(const igraph_2dgrid_t *grid, long int e1, long int e2) { igraph_real_t x = MATRIX(*grid->coords, e1, 0) - MATRIX(*grid->coords, e2, 0); igraph_real_t y = MATRIX(*grid->coords, e1, 1) - MATRIX(*grid->coords, e2, 1); return x * x + y * y; } int 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) { long int act; igraph_real_t *v = VECTOR(grid->next); r = r * r; act = (long int) MATRIX(grid->startidx, x, y); while (act != 0) { if (igraph_2dgrid_dist2(grid, vid, act - 1) < r) { IGRAPH_CHECK(igraph_vector_push_back(eids, act - 1)); } act = (long int) v[act - 1]; } return 0; } int igraph_2dgrid_neighbors(igraph_2dgrid_t *grid, igraph_vector_t *eids, igraph_integer_t vid, igraph_real_t r) { igraph_real_t xc = MATRIX(*grid->coords, (long int)vid, 0); igraph_real_t yc = MATRIX(*grid->coords, (long int)vid, 1); long int x, y; igraph_vector_clear(eids); igraph_2dgrid_which(grid, xc, yc, &x, &y); /* this cell */ igraph_i_2dgrid_addvertices(grid, eids, vid, r, x, y); /* left */ if (x != 0) { igraph_i_2dgrid_addvertices(grid, eids, vid, r, x - 1, y); } /* right */ if (x != grid->stepsx - 1) { igraph_i_2dgrid_addvertices(grid, eids, vid, r, x + 1, y); } /* up */ if (y != 0) { igraph_i_2dgrid_addvertices(grid, eids, vid, r, x, y - 1); } /* down */ if (y != grid->stepsy - 1) { igraph_i_2dgrid_addvertices(grid, eids, vid, r, x, y + 1); } /* up & left */ if (x != 0 && y != 0) { igraph_i_2dgrid_addvertices(grid, eids, vid, r, x - 1, y - 1); } /* up & right */ if (x != grid->stepsx - 1 && y != 0) { igraph_i_2dgrid_addvertices(grid, eids, vid, r, x + 1, y - 1); } /* down & left */ if (x != 0 && y != grid->stepsy - 1) { igraph_i_2dgrid_addvertices(grid, eids, vid, r, x - 1, y + 1); } /* down & right */ if (x != grid->stepsx - 1 && y != grid->stepsy - 1) { igraph_i_2dgrid_addvertices(grid, eids, vid, r, x - 1, y + 1); } return 0; } void igraph_2dgrid_reset(igraph_2dgrid_t *grid, igraph_2dgrid_iterator_t *it) { /* Search for the first cell containing a vertex */ it->x = 0; it->y = 0; it->vid = (long int) MATRIX(grid->startidx, 0, 0); while ( it->vid == 0 && (it->x < grid->stepsx - 1 || it->y < grid->stepsy - 1)) { it->x += 1; if (it->x == grid->stepsx) { it->x = 0; it->y += 1; } it->vid = (long int) MATRIX(grid->startidx, it->x, it->y); } } igraph_integer_t igraph_2dgrid_next(igraph_2dgrid_t *grid, igraph_2dgrid_iterator_t *it) { long int ret = it->vid; if (ret == 0) { return 0; } /* First neighbor */ it->ncells = -1; if (it->x != grid->stepsx - 1) { it->ncells += 1; it->nx[it->ncells] = it->x + 1; it->ny[it->ncells] = it->y; } if (it->y != grid->stepsy - 1) { it->ncells += 1; it->nx[it->ncells] = it->x; it->ny[it->ncells] = it->y + 1; } if (it->ncells == 1) { it->ncells += 1; it->nx[it->ncells] = it->x + 1; it->ny[it->ncells] = it->y + 1; } it->ncells += 1; it->nx[it->ncells] = it->x; it->ny[it->ncells] = it->y; it->nei = (long int) VECTOR(grid->next) [ ret - 1 ]; while (it->ncells > 0 && it->nei == 0 ) { it->ncells -= 1; it->nei = (long int) MATRIX(grid->startidx, it->nx[it->ncells], it->ny[it->ncells]); } /* Next vertex */ it->vid = (long int) VECTOR(grid->next)[ it->vid - 1 ]; while ( (it->x < grid->stepsx - 1 || it->y < grid->stepsy - 1) && it->vid == 0) { it->x += 1; if (it->x == grid->stepsx) { it->x = 0; it->y += 1; } it->vid = (long int) MATRIX(grid->startidx, it->x, it->y); } return (igraph_integer_t) ret; } igraph_integer_t igraph_2dgrid_next_nei(igraph_2dgrid_t *grid, igraph_2dgrid_iterator_t *it) { long int ret = it->nei; if (it->nei != 0) { it->nei = (long int) VECTOR(grid->next) [ ret - 1 ]; } while (it->ncells > 0 && it->nei == 0 ) { it->ncells -= 1; it->nei = (long int) MATRIX(grid->startidx, it->nx[it->ncells], it->ny[it->ncells]); } return (igraph_integer_t) ret; } /*-----------------------------------------------------------------------*/ int 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) { if (xc <= grid->minx) { *x = 0; } else if (xc >= grid->maxx) { *x = grid->stepsx - 1; } else { *x = (long int) floor((xc - (grid->minx)) / (grid->deltax)); } if (yc <= grid->miny) { *y = 0; } else if (yc >= grid->maxy) { *y = grid->stepsy - 1; } else { *y = (long int) floor((yc - (grid->miny)) / (grid->deltay)); } return 0; } int 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) { grid->minx = minx; grid->maxx = maxx; grid->stepsx = stepsx; grid->deltax = (maxx - minx) / stepsx; grid->miny = miny; grid->maxy = maxy; grid->stepsy = stepsy; grid->deltay = (maxy - miny) / stepsy; grid->data = igraph_Calloc(stepsx * stepsy, long int); if (grid->data == 0) { IGRAPH_ERROR("Cannot create grid", IGRAPH_ENOMEM); } return 0; } void igraph_i_layout_mergegrid_destroy(igraph_i_layout_mergegrid_t *grid) { igraph_Free(grid->data); } #define MAT(i,j) (grid->data[(grid->stepsy)*(j)+(i)]) #define DIST2(x2,y2) (sqrt(pow(x-(x2),2)+pow(y-(y2), 2))) int 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) { long int cx, cy; long int i, j; igraph_i_layout_mergegrid_which(grid, x, y, &cx, &cy); MAT(cx, cy) = id + 1; #define DIST(i,j) (DIST2(grid->minx+(cx+(i))*grid->deltax, \ grid->miny+(cy+(j))*grid->deltay)) for (i = 0; cx + i < grid->stepsx && DIST(i, 0) < r; i++) { for (j = 0; cy + j < grid->stepsy && DIST(i, j) < r; j++) { MAT(cx + i, cy + j) = id + 1; } } #undef DIST #define DIST(i,j) (DIST2(grid->minx+(cx+(i))*grid->deltax, \ grid->miny+(cy-(j)+1)*grid->deltay)) for (i = 0; cx + i < grid->stepsx && DIST(i, 0) < r; i++) { for (j = 1; cy - j > 0 && DIST(i, j) < r; j++) { MAT(cx + i, cy - j) = id + 1; } } #undef DIST #define DIST(i,j) (DIST2(grid->minx+(cx-(i)+1)*grid->deltax, \ grid->miny+(cy+(j))*grid->deltay)) for (i = 1; cx - i > 0 && DIST(i, 0) < r; i++) { for (j = 0; cy + j < grid->stepsy && DIST(i, j) < r; j++) { MAT(cx - i, cy + j) = id + 1; } } #undef DIST #define DIST(i,j) (DIST2(grid->minx+(cx-(i)+1)*grid->deltax, \ grid->miny+(cy-(j)+1)*grid->deltay)) for (i = 1; cx - i > 0 && DIST(i, 0) < r; i++) { for (j = 1; cy - j > 0 && DIST(i, j) < r; j++) { MAT(cx - i, cy - j) = id + 1; } } #undef DIST #undef DIST2 return 0; } long int igraph_i_layout_mergegrid_get(igraph_i_layout_mergegrid_t *grid, igraph_real_t x, igraph_real_t y) { long int cx, cy; long int res; if (x <= grid->minx || x >= grid->maxx || y <= grid->miny || y >= grid->maxy) { res = -1; } else { igraph_i_layout_mergegrid_which(grid, x, y, &cx, &cy); res = MAT(cx, cy) - 1; } return res; } #define DIST2(x2,y2) (sqrt(pow(x-(x2),2)+pow(y-(y2), 2))) long int igraph_i_layout_mergegrid_get_sphere(igraph_i_layout_mergegrid_t *grid, igraph_real_t x, igraph_real_t y, igraph_real_t r) { long int cx, cy; long int i, j; long int ret; if (x - r <= grid->minx || x + r >= grid->maxx || y - r <= grid->miny || y + r >= grid->maxy) { ret = -1; } else { igraph_i_layout_mergegrid_which(grid, x, y, &cx, &cy); ret = MAT(cx, cy) - 1; #define DIST(i,j) (DIST2(grid->minx+(cx+(i))*grid->deltax, \ grid->miny+(cy+(j))*grid->deltay)) for (i = 0; ret < 0 && cx + i < grid->stepsx && DIST(i, 0) < r; i++) { for (j = 0; ret < 0 && cy + j < grid->stepsy && DIST(i, j) < r; j++) { ret = MAT(cx + i, cy + j) - 1; } } #undef DIST #define DIST(i,j) (DIST2(grid->minx+(cx+(i))*grid->deltax, \ grid->miny+(cy-(j)+1)*grid->deltay)) for (i = 0; ret < 0 && cx + i < grid->stepsx && DIST(i, 0) < r; i++) { for (j = 1; ret < 0 && cy - j > 0 && DIST(i, j) < r; j++) { ret = MAT(cx + i, cy - j) - 1; } } #undef DIST #define DIST(i,j) (DIST2(grid->minx+(cx-(i)+1)*grid->deltax, \ grid->miny+(cy+(j))*grid->deltay)) for (i = 1; ret < 0 && cx - i > 0 && DIST(i, 0) < r; i++) { for (j = 0; ret < 0 && cy + j < grid->stepsy && DIST(i, j) < r; j++) { ret = MAT(cx - i, cy + j) - 1; } } #undef DIST #define DIST(i,j) (DIST2(grid->minx+(cx-(i)+1)*grid->deltax, \ grid->miny+(cy-(j)+1)*grid->deltay)) for (i = 1; ret < 0 && cx + i > 0 && DIST(i, 0) < r; i++) { for (j = 1; ret < 0 && cy + i > 0 && DIST(i, j) < r; j++) { ret = MAT(cx - i, cy - j) - 1; } } #undef DIST } return ret; } /* int print_grid(igraph_i_layout_mergegrid_t *grid) { */ /* long int i,j; */ /* for (i=0; istepsx; i++) { */ /* for (j=0; jstepsy; j++) { */ /* printf("%li ", MAT(i,j)-1); */ /* } */ /* printf("\n"); */ /* } */ /* } */