Selaa lähdekoodia

fix bug in stb_connected_components adjacency list updating incorrectly handling avoiding adding the same connection twice

Sean Barrett 9 vuotta sitten
vanhempi
commit
7d0099ecc9
2 muutettua tiedostoa jossa 59 lisäystä ja 18 poistoa
  1. 21 15
      stb_connected_components.h
  2. 38 3
      tests/grid_reachability.c

+ 21 - 15
stb_connected_components.h

@@ -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
 //
 // Finds connected components on 2D grids for testing reachability between
@@ -37,6 +37,7 @@
 //
 // 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.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
@@ -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_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
 
 // 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
    // for simplicity we do the latter
    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 };
    int x = cx * STBCC__CLUSTER_SIZE_X;
    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));
       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)) {
-            stbcc__clumpid c = g->clump_for_node[y+j+dy][x+i+dx];
-            if (0 == (connected[c>>3] & (1 << (c & 7)))) {
-               connected[c>>3] |= 1 << (c & 7);
-               ++num_adj[g->clump_for_node[y+j][x+i]];
+            stbcc__clumpid src = g->clump_for_node[y+j][x+i];
+            stbcc__clumpid dest = g->clump_for_node[y+j+dy][x+i+dx];
+            if (0 == (connected[src][dest>>3] & (1 << (dest & 7)))) {
+               connected[src][dest>>3] |= 1 << (dest & 7);
+               ++num_adj[src];
                ++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)
 {
-   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 y = cy * STBCC__CLUSTER_SIZE_Y;
    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) {
       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];
-         if (0 == (connected[c>>3] & (1 << (c & 7)))) {
-            assert((c>>3) < sizeof(connected));
-            connected[c>>3] |= 1 << (c & 7);
+         stbcc__clumpid src = g->clump_for_node[y+j][x+i];
+         stbcc__clumpid dest = g->clump_for_node[y+j+dy][x+i+dx];
+         if (0 == (connected[src][dest>>3] & (1 << (dest & 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);
             if (g->cluster[cy][cx].rebuild_adjacency)
                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)
 {
-   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 y = cy * STBCC__CLUSTER_SIZE_Y;
    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) {
       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];
-         if (0 == (disconnected[c>>3] & (1 << (c & 7)))) {
-            disconnected[c>>3] |= 1 << (c & 7);
+         stbcc__clumpid src = g->clump_for_node[y+j][x+i];
+         stbcc__clumpid dest = g->clump_for_node[y+j+dy][x+i+dx];
+         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);
          }
       }

+ 38 - 3
tests/grid_reachability.c

@@ -96,14 +96,24 @@ void write_map(stbcc_grid *g, int w, int h, char *filename)
       for (i=0; i < w; ++i) {
          unsigned int c;
          c = stbcc_get_unique_id(g,i,j);
+         c = stb_rehash_improved(c)&0xffffff;
          if (c == STBCC_NULL_UNIQUE_ID)
             c = 0xff000000;
          else
             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;
       }
    }
-   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)
@@ -159,18 +169,43 @@ int main(int argc, char **argv)
       map[(stb_rand()%h)*w + stb_rand()%w] ^= 255;
    #endif
             
+   _mkdir("tests/output/stbcc");
+
    stbi_write_png("tests/output/stbcc/reference.png", w, h, 1, map, 0);
 
    //reference(map, w, h);
 
-   _mkdir("tests/output/stbcc");
-
    g = malloc(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");
    stbcc_init_grid(g, map, w, h);
    end_timer();
+   //g = stb_file("c:/x/clockwork_path.bin", 0);
    write_map(g, w, h, "tests/output/stbcc/base.png");
 
    for (i=0; i < 5000;) {