Fixed a regression bug in admesh: bad hashing.

Also the hash table size for admesh was made adaptive based on the number
of faces.
This commit is contained in:
bubnikv 2018-09-25 16:05:26 +02:00
parent 6260e43f61
commit 47b2d363f0
3 changed files with 30 additions and 16 deletions

View file

@ -25,6 +25,9 @@
#include <string.h>
#include <math.h>
#include <algorithm>
#include <vector>
#include <boost/detail/endian.hpp>
#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<uint32_t> 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");

View file

@ -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.

View file

@ -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;