From 47b2d363f058c326eb3f7c4aa4ef0405d808d97a Mon Sep 17 00:00:00 2001 From: bubnikv Date: Tue, 25 Sep 2018 16:05:26 +0200 Subject: [PATCH] Fixed a regression bug in admesh: bad hashing. Also the hash table size for admesh was made adaptive based on the number of faces. --- src/admesh/connect.cpp | 34 +++++++++++++++++++++++----------- src/admesh/stl.h | 4 ++-- src/libslic3r/TriangleMesh.cpp | 8 +++++--- 3 files changed, 30 insertions(+), 16 deletions(-) diff --git a/src/admesh/connect.cpp b/src/admesh/connect.cpp index da5b66720..166eec330 100644 --- a/src/admesh/connect.cpp +++ b/src/admesh/connect.cpp @@ -25,6 +25,9 @@ #include #include +#include +#include + #include #include "stl.h" @@ -125,11 +128,11 @@ stl_load_edge_exact(stl_file *stl, stl_hash_edge *edge, std::swap(a, b); edge->which_edge += 3; /* this edge is loaded backwards */ } - memcpy(&edge->key[0], a->data(), sizeof(stl_vertex)); - memcpy(&edge->key[sizeof(stl_vertex)], b->data(), sizeof(stl_vertex)); + memcpy(&edge->key[0], a->data(), sizeof(stl_vertex)); + memcpy(&edge->key[3], b->data(), sizeof(stl_vertex)); // Switch negative zeros to positive zeros, so memcmp will consider them to be equal. for (size_t i = 0; i < 6; ++ i) { - unsigned char *p = edge->key + i * 4; + unsigned char *p = (unsigned char*)(edge->key + i); #ifdef BOOST_LITTLE_ENDIAN if (p[0] == 0 && p[1] == 0 && p[2] == 0 && p[3] == 0x80) // Negative zero, switch to positive zero. @@ -142,6 +145,16 @@ stl_load_edge_exact(stl_file *stl, stl_hash_edge *edge, } } +static inline size_t hash_size_from_nr_faces(const size_t nr_faces) +{ + // Good primes for addressing a cca. 30 bit space. + // https://planetmath.org/goodhashtableprimes + static std::vector primes{ 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469, 12582917, 25165843, 50331653, 100663319, 201326611, 402653189, 805306457, 1610612741 }; + // Find a prime number for 50% filling of the shared triangle edges in the mesh. + auto it = std::upper_bound(primes.begin(), primes.end(), nr_faces * 3 * 2 - 1); + return (it == primes.end()) ? primes.back() : *it; +} + static void stl_initialize_facet_check_exact(stl_file *stl) { int i; @@ -152,10 +165,9 @@ stl_initialize_facet_check_exact(stl_file *stl) { stl->stats.freed = 0; stl->stats.collisions = 0; + stl->M = hash_size_from_nr_faces(stl->stats.number_of_facets); - stl->M = 81397; - - for(i = 0; i < stl->stats.number_of_facets ; i++) { + for (i = 0; i < stl->stats.number_of_facets ; i++) { /* initialize neighbors list to -1 to mark unconnected edges */ stl->neighbors_start[i].neighbor[0] = -1; stl->neighbors_start[i].neighbor[1] = -1; @@ -296,11 +308,11 @@ static int stl_load_edge_nearby(stl_file *stl, stl_hash_edge *edge, stl_vertex * ((vertex1[1] != vertex2[1]) ? (vertex1[1] < vertex2[1]) : (vertex1[2] < vertex2[2]))) { - memcpy(&edge->key[0], vertex1.data(), sizeof(stl_vertex)); - memcpy(&edge->key[sizeof(stl_vertex)], vertex2.data(), sizeof(stl_vertex)); + memcpy(&edge->key[0], vertex1.data(), sizeof(stl_vertex)); + memcpy(&edge->key[3], vertex2.data(), sizeof(stl_vertex)); } else { - memcpy(&edge->key[0], vertex2.data(), sizeof(stl_vertex)); - memcpy(&edge->key[sizeof(stl_vertex)], vertex1.data(), sizeof(stl_vertex)); + memcpy(&edge->key[0], vertex2.data(), sizeof(stl_vertex)); + memcpy(&edge->key[3], vertex1.data(), sizeof(stl_vertex)); edge->which_edge += 3; /* this edge is loaded backwards */ } return 1; @@ -338,7 +350,7 @@ static void stl_initialize_facet_check_nearby(stl_file *stl) /* tolerance = STL_MAX((stl->stats.bounding_diameter / 500000.0), tolerance);*/ /* tolerance *= 0.5;*/ - stl->M = 81397; + stl->M = hash_size_from_nr_faces(stl->stats.number_of_facets); stl->heads = (stl_hash_edge**)calloc(stl->M, sizeof(*stl->heads)); if(stl->heads == NULL) perror("stl_initialize_facet_check_nearby"); diff --git a/src/admesh/stl.h b/src/admesh/stl.h index 096430d15..9898f3e64 100644 --- a/src/admesh/stl.h +++ b/src/admesh/stl.h @@ -65,11 +65,11 @@ typedef struct { typedef struct stl_hash_edge { // Key of a hash edge: sorted vertices of the edge. - unsigned char key[2 * sizeof(stl_vertex)]; + uint32_t key[6]; // Compare two keys. bool operator==(const stl_hash_edge &rhs) { return memcmp(key, rhs.key, sizeof(key)) == 0; } bool operator!=(const stl_hash_edge &rhs) { return ! (*this == rhs); } - int hash(int M) const { return ((key[0] / 23 + key[1] / 19 + key[2] / 17 + key[3] /13 + key[4] / 11 + key[5] / 7 ) % M); } + int hash(int M) const { return ((key[0] / 11 + key[1] / 7 + key[2] / 3) ^ (key[3] / 11 + key[4] / 7 + key[5] / 3)) % M; } // Index of a facet owning this edge. int facet_number; // Index of this edge inside the facet with an index of facet_number. diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index c56b66de3..665351c39 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -108,21 +108,23 @@ void TriangleMesh::repair() BOOST_LOG_TRIVIAL(debug) << "TriangleMesh::repair() started"; // checking exact - stl_check_facets_exact(&stl); + BOOST_LOG_TRIVIAL(trace) << "\tstl_check_faces_exact"; + stl_check_facets_exact(&stl); stl.stats.facets_w_1_bad_edge = (stl.stats.connected_facets_2_edge - stl.stats.connected_facets_3_edge); stl.stats.facets_w_2_bad_edge = (stl.stats.connected_facets_1_edge - stl.stats.connected_facets_2_edge); stl.stats.facets_w_3_bad_edge = (stl.stats.number_of_facets - stl.stats.connected_facets_1_edge); // checking nearby //int last_edges_fixed = 0; - float tolerance = stl.stats.shortest_edge; + float tolerance = stl.stats.shortest_edge; float increment = stl.stats.bounding_diameter / 10000.0; int iterations = 2; if (stl.stats.connected_facets_3_edge < stl.stats.number_of_facets) { for (int i = 0; i < iterations; i++) { if (stl.stats.connected_facets_3_edge < stl.stats.number_of_facets) { //printf("Checking nearby. Tolerance= %f Iteration=%d of %d...", tolerance, i + 1, iterations); - stl_check_facets_nearby(&stl, tolerance); + BOOST_LOG_TRIVIAL(trace) << "\tstl_check_faces_nearby"; + stl_check_facets_nearby(&stl, tolerance); //printf(" Fixed %d edges.\n", stl.stats.edges_fixed - last_edges_fixed); //last_edges_fixed = stl.stats.edges_fixed; tolerance += increment;