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:
parent
6260e43f61
commit
47b2d363f0
3 changed files with 30 additions and 16 deletions
|
@ -25,6 +25,9 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include <boost/detail/endian.hpp>
|
#include <boost/detail/endian.hpp>
|
||||||
|
|
||||||
#include "stl.h"
|
#include "stl.h"
|
||||||
|
@ -125,11 +128,11 @@ stl_load_edge_exact(stl_file *stl, stl_hash_edge *edge,
|
||||||
std::swap(a, b);
|
std::swap(a, b);
|
||||||
edge->which_edge += 3; /* this edge is loaded backwards */
|
edge->which_edge += 3; /* this edge is loaded backwards */
|
||||||
}
|
}
|
||||||
memcpy(&edge->key[0], a->data(), sizeof(stl_vertex));
|
memcpy(&edge->key[0], a->data(), sizeof(stl_vertex));
|
||||||
memcpy(&edge->key[sizeof(stl_vertex)], b->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.
|
// Switch negative zeros to positive zeros, so memcmp will consider them to be equal.
|
||||||
for (size_t i = 0; i < 6; ++ i) {
|
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
|
#ifdef BOOST_LITTLE_ENDIAN
|
||||||
if (p[0] == 0 && p[1] == 0 && p[2] == 0 && p[3] == 0x80)
|
if (p[0] == 0 && p[1] == 0 && p[2] == 0 && p[3] == 0x80)
|
||||||
// Negative zero, switch to positive zero.
|
// 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
|
static void
|
||||||
stl_initialize_facet_check_exact(stl_file *stl) {
|
stl_initialize_facet_check_exact(stl_file *stl) {
|
||||||
int i;
|
int i;
|
||||||
|
@ -152,10 +165,9 @@ stl_initialize_facet_check_exact(stl_file *stl) {
|
||||||
stl->stats.freed = 0;
|
stl->stats.freed = 0;
|
||||||
stl->stats.collisions = 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 */
|
/* initialize neighbors list to -1 to mark unconnected edges */
|
||||||
stl->neighbors_start[i].neighbor[0] = -1;
|
stl->neighbors_start[i].neighbor[0] = -1;
|
||||||
stl->neighbors_start[i].neighbor[1] = -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[1] < vertex2[1]) :
|
(vertex1[1] < vertex2[1]) :
|
||||||
(vertex1[2] < vertex2[2]))) {
|
(vertex1[2] < vertex2[2]))) {
|
||||||
memcpy(&edge->key[0], vertex1.data(), sizeof(stl_vertex));
|
memcpy(&edge->key[0], vertex1.data(), sizeof(stl_vertex));
|
||||||
memcpy(&edge->key[sizeof(stl_vertex)], vertex2.data(), sizeof(stl_vertex));
|
memcpy(&edge->key[3], vertex2.data(), sizeof(stl_vertex));
|
||||||
} else {
|
} else {
|
||||||
memcpy(&edge->key[0], vertex2.data(), sizeof(stl_vertex));
|
memcpy(&edge->key[0], vertex2.data(), sizeof(stl_vertex));
|
||||||
memcpy(&edge->key[sizeof(stl_vertex)], vertex1.data(), sizeof(stl_vertex));
|
memcpy(&edge->key[3], vertex1.data(), sizeof(stl_vertex));
|
||||||
edge->which_edge += 3; /* this edge is loaded backwards */
|
edge->which_edge += 3; /* this edge is loaded backwards */
|
||||||
}
|
}
|
||||||
return 1;
|
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 = STL_MAX((stl->stats.bounding_diameter / 500000.0), tolerance);*/
|
||||||
/* tolerance *= 0.5;*/
|
/* 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));
|
stl->heads = (stl_hash_edge**)calloc(stl->M, sizeof(*stl->heads));
|
||||||
if(stl->heads == NULL) perror("stl_initialize_facet_check_nearby");
|
if(stl->heads == NULL) perror("stl_initialize_facet_check_nearby");
|
||||||
|
|
|
@ -65,11 +65,11 @@ typedef struct {
|
||||||
|
|
||||||
typedef struct stl_hash_edge {
|
typedef struct stl_hash_edge {
|
||||||
// Key of a hash edge: sorted vertices of the 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.
|
// 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 memcmp(key, rhs.key, sizeof(key)) == 0; }
|
||||||
bool operator!=(const stl_hash_edge &rhs) { return ! (*this == rhs); }
|
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.
|
// Index of a facet owning this edge.
|
||||||
int facet_number;
|
int facet_number;
|
||||||
// Index of this edge inside the facet with an index of facet_number.
|
// Index of this edge inside the facet with an index of facet_number.
|
||||||
|
|
|
@ -108,21 +108,23 @@ void TriangleMesh::repair()
|
||||||
BOOST_LOG_TRIVIAL(debug) << "TriangleMesh::repair() started";
|
BOOST_LOG_TRIVIAL(debug) << "TriangleMesh::repair() started";
|
||||||
|
|
||||||
// checking exact
|
// 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_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_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);
|
stl.stats.facets_w_3_bad_edge = (stl.stats.number_of_facets - stl.stats.connected_facets_1_edge);
|
||||||
|
|
||||||
// checking nearby
|
// checking nearby
|
||||||
//int last_edges_fixed = 0;
|
//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;
|
float increment = stl.stats.bounding_diameter / 10000.0;
|
||||||
int iterations = 2;
|
int iterations = 2;
|
||||||
if (stl.stats.connected_facets_3_edge < stl.stats.number_of_facets) {
|
if (stl.stats.connected_facets_3_edge < stl.stats.number_of_facets) {
|
||||||
for (int i = 0; i < iterations; i++) {
|
for (int i = 0; i < iterations; i++) {
|
||||||
if (stl.stats.connected_facets_3_edge < stl.stats.number_of_facets) {
|
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);
|
//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);
|
//printf(" Fixed %d edges.\n", stl.stats.edges_fixed - last_edges_fixed);
|
||||||
//last_edges_fixed = stl.stats.edges_fixed;
|
//last_edges_fixed = stl.stats.edges_fixed;
|
||||||
tolerance += increment;
|
tolerance += increment;
|
||||||
|
|
Loading…
Reference in a new issue