fix bug in stb_connected_components adjacency list updating incorrectly handling avoiding adding the same connection twice
This commit is contained in:
parent
dca0a37ff4
commit
7d0099ecc9
@ -1,4 +1,4 @@
|
|||||||
// stb_connected_components - v0.94 - public domain connected components on grids
|
// stb_connected_components - v0.95 - public domain connected components on grids
|
||||||
// http://github.com/nothings/stb
|
// http://github.com/nothings/stb
|
||||||
//
|
//
|
||||||
// Finds connected components on 2D grids for testing reachability between
|
// Finds connected components on 2D grids for testing reachability between
|
||||||
@ -37,6 +37,7 @@
|
|||||||
//
|
//
|
||||||
// CHANGELOG
|
// CHANGELOG
|
||||||
//
|
//
|
||||||
|
// 0.95 (2016-10-16) Bugfix if multiple clumps in one cluster connect to same clump in another
|
||||||
// 0.94 (2016-04-17) Bugfix & optimize worst case (checkerboard & random)
|
// 0.94 (2016-04-17) Bugfix & optimize worst case (checkerboard & random)
|
||||||
// 0.93 (2016-04-16) Reduce memory by 10x for 1Kx1K map; small speedup
|
// 0.93 (2016-04-16) Reduce memory by 10x for 1Kx1K map; small speedup
|
||||||
// 0.92 (2016-04-16) Compute sqrt(N) cluster size by default
|
// 0.92 (2016-04-16) Compute sqrt(N) cluster size by default
|
||||||
@ -201,6 +202,8 @@ typedef unsigned char stbcc__verify_max_clumps[STBCC__MAX_CLUMPS_PER_CLUSTER < (
|
|||||||
|
|
||||||
#define STBCC__MAX_EXITS_PER_CLUSTER (STBCC__CLUSTER_SIZE_X + STBCC__CLUSTER_SIZE_Y) // 64 for 32x32
|
#define STBCC__MAX_EXITS_PER_CLUSTER (STBCC__CLUSTER_SIZE_X + STBCC__CLUSTER_SIZE_Y) // 64 for 32x32
|
||||||
#define STBCC__MAX_EXITS_PER_CLUMP (STBCC__CLUSTER_SIZE_X + STBCC__CLUSTER_SIZE_Y) // 64 for 32x32
|
#define STBCC__MAX_EXITS_PER_CLUMP (STBCC__CLUSTER_SIZE_X + STBCC__CLUSTER_SIZE_Y) // 64 for 32x32
|
||||||
|
#define STBCC__MAX_EDGE_CLUMPS_PER_CLUSTER (STBCC__MAX_EXITS_PER_CLUMP)
|
||||||
|
|
||||||
// 2^19 * 2^6 => 2^25 exits => 2^26 => 64MB for 1024x1024
|
// 2^19 * 2^6 => 2^25 exits => 2^26 => 64MB for 1024x1024
|
||||||
|
|
||||||
// Logic for above on 4x4 grid:
|
// Logic for above on 4x4 grid:
|
||||||
@ -409,7 +412,7 @@ static void stbcc__build_all_connections_for_cluster(stbcc_grid *g, int cx, int
|
|||||||
// the data into temporary data structures, or just count the sizes, so
|
// the data into temporary data structures, or just count the sizes, so
|
||||||
// for simplicity we do the latter
|
// for simplicity we do the latter
|
||||||
stbcc__cluster *cluster = &g->cluster[cy][cx];
|
stbcc__cluster *cluster = &g->cluster[cy][cx];
|
||||||
unsigned char connected[STBCC__MAX_CLUMPS_PER_CLUSTER/8];
|
unsigned char connected[STBCC__MAX_EDGE_CLUMPS_PER_CLUSTER][STBCC__MAX_EDGE_CLUMPS_PER_CLUSTER/8]; // 64 x 8 => 1KB
|
||||||
unsigned char num_adj[STBCC__MAX_CLUMPS_PER_CLUSTER] = { 0 };
|
unsigned char num_adj[STBCC__MAX_CLUMPS_PER_CLUSTER] = { 0 };
|
||||||
int x = cx * STBCC__CLUSTER_SIZE_X;
|
int x = cx * STBCC__CLUSTER_SIZE_X;
|
||||||
int y = cy * STBCC__CLUSTER_SIZE_Y;
|
int y = cy * STBCC__CLUSTER_SIZE_Y;
|
||||||
@ -460,10 +463,11 @@ static void stbcc__build_all_connections_for_cluster(stbcc_grid *g, int cx, int
|
|||||||
memset(connected, 0, sizeof(connected));
|
memset(connected, 0, sizeof(connected));
|
||||||
for (k=0; k < n; ++k) {
|
for (k=0; k < n; ++k) {
|
||||||
if (STBCC__MAP_OPEN(g, x+i, y+j) && STBCC__MAP_OPEN(g, x+i+dx, y+j+dy)) {
|
if (STBCC__MAP_OPEN(g, x+i, y+j) && STBCC__MAP_OPEN(g, x+i+dx, y+j+dy)) {
|
||||||
stbcc__clumpid c = g->clump_for_node[y+j+dy][x+i+dx];
|
stbcc__clumpid src = g->clump_for_node[y+j][x+i];
|
||||||
if (0 == (connected[c>>3] & (1 << (c & 7)))) {
|
stbcc__clumpid dest = g->clump_for_node[y+j+dy][x+i+dx];
|
||||||
connected[c>>3] |= 1 << (c & 7);
|
if (0 == (connected[src][dest>>3] & (1 << (dest & 7)))) {
|
||||||
++num_adj[g->clump_for_node[y+j][x+i]];
|
connected[src][dest>>3] |= 1 << (dest & 7);
|
||||||
|
++num_adj[src];
|
||||||
++total;
|
++total;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -707,7 +711,7 @@ static void stbcc__remove_clump_connection(stbcc_grid *g, int x1, int y1, int x2
|
|||||||
|
|
||||||
static void stbcc__add_connections_to_adjacent_cluster(stbcc_grid *g, int cx, int cy, int dx, int dy)
|
static void stbcc__add_connections_to_adjacent_cluster(stbcc_grid *g, int cx, int cy, int dx, int dy)
|
||||||
{
|
{
|
||||||
unsigned char connected[STBCC__MAX_CLUMPS_PER_CLUSTER/8] = { 0 };
|
unsigned char connected[STBCC__MAX_EDGE_CLUMPS_PER_CLUSTER][STBCC__MAX_EDGE_CLUMPS_PER_CLUSTER/8] = { 0 };
|
||||||
int x = cx * STBCC__CLUSTER_SIZE_X;
|
int x = cx * STBCC__CLUSTER_SIZE_X;
|
||||||
int y = cy * STBCC__CLUSTER_SIZE_Y;
|
int y = cy * STBCC__CLUSTER_SIZE_Y;
|
||||||
int step_x, step_y=0, i, j, k, n;
|
int step_x, step_y=0, i, j, k, n;
|
||||||
@ -753,10 +757,11 @@ static void stbcc__add_connections_to_adjacent_cluster(stbcc_grid *g, int cx, in
|
|||||||
|
|
||||||
for (k=0; k < n; ++k) {
|
for (k=0; k < n; ++k) {
|
||||||
if (STBCC__MAP_OPEN(g, x+i, y+j) && STBCC__MAP_OPEN(g, x+i+dx, y+j+dy)) {
|
if (STBCC__MAP_OPEN(g, x+i, y+j) && STBCC__MAP_OPEN(g, x+i+dx, y+j+dy)) {
|
||||||
stbcc__clumpid c = g->clump_for_node[y+j+dy][x+i+dx];
|
stbcc__clumpid src = g->clump_for_node[y+j][x+i];
|
||||||
if (0 == (connected[c>>3] & (1 << (c & 7)))) {
|
stbcc__clumpid dest = g->clump_for_node[y+j+dy][x+i+dx];
|
||||||
assert((c>>3) < sizeof(connected));
|
if (0 == (connected[src][dest>>3] & (1 << (dest & 7)))) {
|
||||||
connected[c>>3] |= 1 << (c & 7);
|
assert((dest>>3) < sizeof(connected));
|
||||||
|
connected[src][dest>>3] |= 1 << (dest & 7);
|
||||||
stbcc__add_clump_connection(g, x+i, y+j, x+i+dx, y+j+dy);
|
stbcc__add_clump_connection(g, x+i, y+j, x+i+dx, y+j+dy);
|
||||||
if (g->cluster[cy][cx].rebuild_adjacency)
|
if (g->cluster[cy][cx].rebuild_adjacency)
|
||||||
break;
|
break;
|
||||||
@ -769,7 +774,7 @@ static void stbcc__add_connections_to_adjacent_cluster(stbcc_grid *g, int cx, in
|
|||||||
|
|
||||||
static void stbcc__remove_connections_to_adjacent_cluster(stbcc_grid *g, int cx, int cy, int dx, int dy)
|
static void stbcc__remove_connections_to_adjacent_cluster(stbcc_grid *g, int cx, int cy, int dx, int dy)
|
||||||
{
|
{
|
||||||
unsigned char disconnected[STBCC__MAX_CLUMPS_PER_CLUSTER/8] = { 0 };
|
unsigned char disconnected[STBCC__MAX_EDGE_CLUMPS_PER_CLUSTER][STBCC__MAX_EDGE_CLUMPS_PER_CLUSTER/8] = { 0 };
|
||||||
int x = cx * STBCC__CLUSTER_SIZE_X;
|
int x = cx * STBCC__CLUSTER_SIZE_X;
|
||||||
int y = cy * STBCC__CLUSTER_SIZE_Y;
|
int y = cy * STBCC__CLUSTER_SIZE_Y;
|
||||||
int step_x, step_y=0, i, j, k, n;
|
int step_x, step_y=0, i, j, k, n;
|
||||||
@ -812,9 +817,10 @@ static void stbcc__remove_connections_to_adjacent_cluster(stbcc_grid *g, int cx,
|
|||||||
|
|
||||||
for (k=0; k < n; ++k) {
|
for (k=0; k < n; ++k) {
|
||||||
if (STBCC__MAP_OPEN(g, x+i, y+j) && STBCC__MAP_OPEN(g, x+i+dx, y+j+dy)) {
|
if (STBCC__MAP_OPEN(g, x+i, y+j) && STBCC__MAP_OPEN(g, x+i+dx, y+j+dy)) {
|
||||||
stbcc__clumpid c = g->clump_for_node[y+j+dy][x+i+dx];
|
stbcc__clumpid src = g->clump_for_node[y+j][x+i];
|
||||||
if (0 == (disconnected[c>>3] & (1 << (c & 7)))) {
|
stbcc__clumpid dest = g->clump_for_node[y+j+dy][x+i+dx];
|
||||||
disconnected[c>>3] |= 1 << (c & 7);
|
if (0 == (disconnected[src][dest>>3] & (1 << (dest & 7)))) {
|
||||||
|
disconnected[src][dest>>3] |= 1 << (dest & 7);
|
||||||
stbcc__remove_clump_connection(g, x+i, y+j, x+i+dx, y+j+dy);
|
stbcc__remove_clump_connection(g, x+i, y+j, x+i+dx, y+j+dy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,14 +96,24 @@ void write_map(stbcc_grid *g, int w, int h, char *filename)
|
|||||||
for (i=0; i < w; ++i) {
|
for (i=0; i < w; ++i) {
|
||||||
unsigned int c;
|
unsigned int c;
|
||||||
c = stbcc_get_unique_id(g,i,j);
|
c = stbcc_get_unique_id(g,i,j);
|
||||||
|
c = stb_rehash_improved(c)&0xffffff;
|
||||||
if (c == STBCC_NULL_UNIQUE_ID)
|
if (c == STBCC_NULL_UNIQUE_ID)
|
||||||
c = 0xff000000;
|
c = 0xff000000;
|
||||||
else
|
else
|
||||||
c = (~c)^0x555555;
|
c = (~c)^0x555555;
|
||||||
|
if (i % 32 == 0 || j %32 == 0) {
|
||||||
|
int r = (c >> 16) & 255;
|
||||||
|
int g = (c >> 8) & 255;
|
||||||
|
int b = c & 255;
|
||||||
|
r = (r+130)/2;
|
||||||
|
g = (g+130)/2;
|
||||||
|
b = (b+130)/2;
|
||||||
|
c = 0xff000000 + (r<<16) + (g<<8) + b;
|
||||||
|
}
|
||||||
color[j][i] = c;
|
color[j][i] = c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stbi_write_png(filename, w, h, 4, color, 0);
|
stbi_write_png(filename, w, h, 4, color, 4*w);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_connected(stbcc_grid *g)
|
void test_connected(stbcc_grid *g)
|
||||||
@ -159,18 +169,43 @@ int main(int argc, char **argv)
|
|||||||
map[(stb_rand()%h)*w + stb_rand()%w] ^= 255;
|
map[(stb_rand()%h)*w + stb_rand()%w] ^= 255;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
_mkdir("tests/output/stbcc");
|
||||||
|
|
||||||
stbi_write_png("tests/output/stbcc/reference.png", w, h, 1, map, 0);
|
stbi_write_png("tests/output/stbcc/reference.png", w, h, 1, map, 0);
|
||||||
|
|
||||||
//reference(map, w, h);
|
//reference(map, w, h);
|
||||||
|
|
||||||
_mkdir("tests/output/stbcc");
|
|
||||||
|
|
||||||
g = malloc(stbcc_grid_sizeof());
|
g = malloc(stbcc_grid_sizeof());
|
||||||
printf("Size: %d\n", stbcc_grid_sizeof());
|
printf("Size: %d\n", stbcc_grid_sizeof());
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
memset(map, 0, w*h);
|
||||||
|
stbcc_init_grid(g, map, w, h);
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
char **s = stb_stringfile("c:/x/clockwork_update.txt", &n);
|
||||||
|
write_map(g, w, h, "tests/output/stbcc/base.png");
|
||||||
|
for (i=1; i < n; i += 1) {
|
||||||
|
int x,y,t;
|
||||||
|
sscanf(s[i], "%d %d %d", &x, &y, &t);
|
||||||
|
if (i == 571678)
|
||||||
|
write_map(g, w, h, stb_sprintf("tests/output/stbcc/clockwork_good.png", i));
|
||||||
|
stbcc_update_grid(g, x, y, t);
|
||||||
|
if (i == 571678)
|
||||||
|
write_map(g, w, h, stb_sprintf("tests/output/stbcc/clockwork_bad.png", i));
|
||||||
|
//if (i > 571648 && i <= 571712)
|
||||||
|
//write_map(g, w, h, stb_sprintf("tests/output/stbcc/clockwork_%06d.png", i));
|
||||||
|
}
|
||||||
|
write_map(g, w, h, stb_sprintf("tests/output/stbcc/clockwork_%06d.png", i-1));
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
start_timer("init");
|
start_timer("init");
|
||||||
stbcc_init_grid(g, map, w, h);
|
stbcc_init_grid(g, map, w, h);
|
||||||
end_timer();
|
end_timer();
|
||||||
|
//g = stb_file("c:/x/clockwork_path.bin", 0);
|
||||||
write_map(g, w, h, "tests/output/stbcc/base.png");
|
write_map(g, w, h, "tests/output/stbcc/base.png");
|
||||||
|
|
||||||
for (i=0; i < 5000;) {
|
for (i=0; i < 5000;) {
|
||||||
|
Loading…
Reference in New Issue
Block a user