haskell-igraph-0.8.0: igraph/src/igraph_grid.c
/* -*- mode: C -*- */
/*
IGraph R package.
Copyright (C) 2006-2012 Gabor Csardi <csardi.gabor@gmail.com>
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 <math.h>
/* 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; i<grid->stepsx; i++) { */
/* for (j=0; j<grid->stepsy; j++) { */
/* printf("%li ", MAT(i,j)-1); */
/* } */
/* printf("\n"); */
/* } */
/* } */