Prusa Slicer 2.6.0
Loading...
Searching...
No Matches
HashTableEdges Struct Reference
+ Collaboration diagram for HashTableEdges:

Public Member Functions

 HashTableEdges (size_t number_of_faces)
 
 ~HashTableEdges ()
 
void insert_edge_exact (stl_file *stl, const HashEdge &edge)
 
void insert_edge_nearby (stl_file *stl, const HashEdge &edge)
 

Public Attributes

std::vector< HashEdge * > heads
 
HashEdgetail
 
int M
 
boost::object_pool< HashEdgepool
 
size_t malloced = 0
 
size_t freed = 0
 
size_t collisions = 0
 

Private Member Functions

template<typename MatchNeighbors >
void insert_edge (stl_file *stl, const HashEdge &edge, MatchNeighbors match_neighbors)
 

Static Private Member Functions

static size_t hash_size_from_nr_faces (const size_t nr_faces)
 
static bool edges_equal (const HashEdge &edge_a, const HashEdge &edge_b)
 
static void record_neighbors (stl_file *stl, const HashEdge &edge_a, const HashEdge &edge_b)
 
static void match_neighbors_nearby (stl_file *stl, const HashEdge &edge_a, const HashEdge &edge_b)
 

Detailed Description

Constructor & Destructor Documentation

◆ HashTableEdges()

HashTableEdges::HashTableEdges ( size_t  number_of_faces)
inline
124 {
125 this->M = (int)hash_size_from_nr_faces(number_of_faces);
126 this->heads.assign(this->M, nullptr);
127 this->tail = pool.construct();
128 this->tail->next = this->tail;
129 for (int i = 0; i < this->M; ++ i)
130 this->heads[i] = this->tail;
131 }
HashEdge * next
Definition connect.cpp:52
static size_t hash_size_from_nr_faces(const size_t nr_faces)
Definition connect.cpp:164
int M
Definition connect.cpp:154
std::vector< HashEdge * > heads
Definition connect.cpp:152
HashEdge * tail
Definition connect.cpp:153
boost::object_pool< HashEdge > pool
Definition connect.cpp:155

References hash_size_from_nr_faces(), heads, M, HashEdge::next, pool, and tail.

+ Here is the call graph for this function:

◆ ~HashTableEdges()

HashTableEdges::~HashTableEdges ( )
inline
132 {
133#ifndef NDEBUG
134 for (int i = 0; i < this->M; ++ i)
135 for (HashEdge *temp = this->heads[i]; temp != this->tail; temp = temp->next)
136 ++ this->freed;
137 this->tail = nullptr;
138#endif /* NDEBUG */
139 }
Definition connect.cpp:39
size_t freed
Definition connect.cpp:159

References freed, heads, M, HashEdge::next, and tail.

Member Function Documentation

◆ edges_equal()

static bool HashTableEdges::edges_equal ( const HashEdge edge_a,
const HashEdge edge_b 
)
inlinestaticprivate
238 {
239 return edge_a.facet_number != edge_b.facet_number && edge_a == edge_b;
240 }
int facet_number
Definition connect.cpp:48

References HashEdge::facet_number.

Referenced by insert_edge().

+ Here is the caller graph for this function:

◆ hash_size_from_nr_faces()

static size_t HashTableEdges::hash_size_from_nr_faces ( const size_t  nr_faces)
inlinestaticprivate
165 {
166 // Good primes for addressing a cca. 30 bit space.
167 // https://planetmath.org/goodhashtableprimes
168 static std::vector<uint32_t> primes{ 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469, 12582917, 25165843, 50331653, 100663319, 201326611, 402653189, 805306457, 1610612741 };
169 // Find a prime number for 50% filling of the shared triangle edges in the mesh.
170 auto it = std::upper_bound(primes.begin(), primes.end(), nr_faces * 3 * 2 - 1);
171 return (it == primes.end()) ? primes.back() : *it;
172 }

Referenced by HashTableEdges().

+ Here is the caller graph for this function:

◆ insert_edge()

template<typename MatchNeighbors >
void HashTableEdges::insert_edge ( stl_file stl,
const HashEdge edge,
MatchNeighbors  match_neighbors 
)
inlineprivate
178 {
179 int chain_number = edge.hash(this->M);
180 HashEdge *link = this->heads[chain_number];
181 if (link == this->tail) {
182 // This list doesn't have any edges currently in it. Add this one.
183 HashEdge *new_edge = pool.construct(edge);
184#ifndef NDEBUG
185 ++ this->malloced;
186#endif /* NDEBUG */
187 new_edge->next = this->tail;
188 this->heads[chain_number] = new_edge;
189 } else if (edges_equal(edge, *link)) {
190 // This is a match. Record result in neighbors list.
191 match_neighbors(edge, *link);
192 // Delete the matched edge from the list.
193 this->heads[chain_number] = link->next;
194 // pool.destroy(link);
195#ifndef NDEBUG
196 ++ this->freed;
197#endif /* NDEBUG */
198 } else {
199 // Continue through the rest of the list.
200 for (;;) {
201 if (link->next == this->tail) {
202 // This is the last item in the list. Insert a new edge.
203 HashEdge *new_edge = pool.construct();
204#ifndef NDEBUG
205 ++ this->malloced;
206#endif /* NDEBUG */
207 *new_edge = edge;
208 new_edge->next = this->tail;
209 link->next = new_edge;
210#ifndef NDEBUG
211 ++ this->collisions;
212#endif /* NDEBUG */
213 break;
214 }
215 if (edges_equal(edge, *link->next)) {
216 // This is a match. Record result in neighbors list.
217 match_neighbors(edge, *link->next);
218 // Delete the matched edge from the list.
219 HashEdge *temp = link->next;
220 link->next = link->next->next;
221 // pool.destroy(temp);
222#ifndef NDEBUG
223 ++ this->freed;
224#endif /* NDEBUG */
225 break;
226 }
227 // This is not a match. Go to the next link.
228 link = link->next;
229#ifndef NDEBUG
230 ++ this->collisions;
231#endif /* NDEBUG */
232 }
233 }
234 }
int hash(int M) const
Definition connect.cpp:45
static bool edges_equal(const HashEdge &edge_a, const HashEdge &edge_b)
Definition connect.cpp:237
size_t collisions
Definition connect.cpp:160
size_t malloced
Definition connect.cpp:158

References collisions, edges_equal(), freed, HashEdge::hash(), malloced, HashEdge::next, pool, and tail.

Referenced by insert_edge_exact(), and insert_edge_nearby().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ insert_edge_exact()

void HashTableEdges::insert_edge_exact ( stl_file stl,
const HashEdge edge 
)
inline
142 {
143 this->insert_edge(stl, edge, [stl](const HashEdge& edge1, const HashEdge& edge2) { record_neighbors(stl, edge1, edge2); });
144 }
void insert_edge(stl_file *stl, const HashEdge &edge, MatchNeighbors match_neighbors)
Definition connect.cpp:177
static void record_neighbors(stl_file *stl, const HashEdge &edge_a, const HashEdge &edge_b)
Definition connect.cpp:243

References insert_edge(), and record_neighbors().

Referenced by stl_check_facets_exact(), and stl_fill_holes().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ insert_edge_nearby()

void HashTableEdges::insert_edge_nearby ( stl_file stl,
const HashEdge edge 
)
inline
147 {
148 this->insert_edge(stl, edge, [stl](const HashEdge& edge1, const HashEdge& edge2) { match_neighbors_nearby(stl, edge1, edge2); });
149 }
static void match_neighbors_nearby(stl_file *stl, const HashEdge &edge_a, const HashEdge &edge_b)
Definition connect.cpp:277

References insert_edge(), and match_neighbors_nearby().

Referenced by stl_check_facets_nearby().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ match_neighbors_nearby()

static void HashTableEdges::match_neighbors_nearby ( stl_file stl,
const HashEdge edge_a,
const HashEdge edge_b 
)
inlinestaticprivate
278 {
279 record_neighbors(stl, edge_a, edge_b);
280
281 // Which vertices to change
282 int facet1 = -1;
283 int facet2 = -1;
284 int vertex1, vertex2;
285 stl_vertex new_vertex1, new_vertex2;
286 {
287 int v1a; // pair 1, facet a
288 int v1b; // pair 1, facet b
289 int v2a; // pair 2, facet a
290 int v2b; // pair 2, facet b
291 // Find first pair.
292 if (edge_a.which_edge < 3) {
293 v1a = edge_a.which_edge;
294 v2a = (edge_a.which_edge + 1) % 3;
295 } else {
296 v2a = edge_a.which_edge % 3;
297 v1a = (edge_a.which_edge + 1) % 3;
298 }
299 if (edge_b.which_edge < 3) {
300 v1b = edge_b.which_edge;
301 v2b = (edge_b.which_edge + 1) % 3;
302 } else {
303 v2b = edge_b.which_edge % 3;
304 v1b = (edge_b.which_edge + 1) % 3;
305 }
306
307 // Of the first pair, which vertex, if any, should be changed
308 if (stl->facet_start[edge_a.facet_number].vertex[v1a] != stl->facet_start[edge_b.facet_number].vertex[v1b]) {
309 // These facets are different.
310 if ( (stl->neighbors_start[edge_a.facet_number].neighbor[v1a] == -1)
311 && (stl->neighbors_start[edge_a.facet_number].neighbor[(v1a + 2) % 3] == -1)) {
312 // This vertex has no neighbors. This is a good one to change.
313 facet1 = edge_a.facet_number;
314 vertex1 = v1a;
315 new_vertex1 = stl->facet_start[edge_b.facet_number].vertex[v1b];
316 } else {
317 facet1 = edge_b.facet_number;
318 vertex1 = v1b;
319 new_vertex1 = stl->facet_start[edge_a.facet_number].vertex[v1a];
320 }
321 }
322
323 // Of the second pair, which vertex, if any, should be changed.
324 if (stl->facet_start[edge_a.facet_number].vertex[v2a] == stl->facet_start[edge_b.facet_number].vertex[v2b]) {
325 // These facets are different.
326 if ( (stl->neighbors_start[edge_a.facet_number].neighbor[v2a] == -1)
327 && (stl->neighbors_start[edge_a.facet_number].neighbor[(v2a + 2) % 3] == -1)) {
328 // This vertex has no neighbors. This is a good one to change.
329 facet2 = edge_a.facet_number;
330 vertex2 = v2a;
331 new_vertex2 = stl->facet_start[edge_b.facet_number].vertex[v2b];
332 } else {
333 facet2 = edge_b.facet_number;
334 vertex2 = v2b;
335 new_vertex2 = stl->facet_start[edge_a.facet_number].vertex[v2a];
336 }
337 }
338 }
339
340 auto change_vertices = [stl](int facet_num, int vnot, stl_vertex new_vertex)
341 {
342 int first_facet = facet_num;
343 bool direction = false;
344
345 for (;;) {
346 int pivot_vertex;
347 int next_edge;
348 if (vnot > 2) {
349 if (direction) {
350 pivot_vertex = (vnot + 1) % 3;
351 next_edge = vnot % 3;
352 }
353 else {
354 pivot_vertex = (vnot + 2) % 3;
355 next_edge = pivot_vertex;
356 }
357 direction = !direction;
358 }
359 else {
360 if (direction) {
361 pivot_vertex = (vnot + 2) % 3;
362 next_edge = pivot_vertex;
363 }
364 else {
365 pivot_vertex = (vnot + 1) % 3;
366 next_edge = vnot;
367 }
368 }
369 #if 0
370 if (stl->facet_start[facet_num].vertex[pivot_vertex](0) == new_vertex(0) &&
371 stl->facet_start[facet_num].vertex[pivot_vertex](1) == new_vertex(1) &&
372 stl->facet_start[facet_num].vertex[pivot_vertex](2) == new_vertex(2))
373 printf("Changing vertex %f,%f,%f: Same !!!\r\n", new_vertex(0), new_vertex(1), new_vertex(2));
374 else {
375 if (stl->facet_start[facet_num].vertex[pivot_vertex](0) != new_vertex(0))
376 printf("Changing coordinate x, vertex %e (0x%08x) to %e(0x%08x)\r\n",
377 stl->facet_start[facet_num].vertex[pivot_vertex](0),
378 *reinterpret_cast<const int*>(&stl->facet_start[facet_num].vertex[pivot_vertex](0)),
379 new_vertex(0),
380 *reinterpret_cast<const int*>(&new_vertex(0)));
381 if (stl->facet_start[facet_num].vertex[pivot_vertex](1) != new_vertex(1))
382 printf("Changing coordinate x, vertex %e (0x%08x) to %e(0x%08x)\r\n",
383 stl->facet_start[facet_num].vertex[pivot_vertex](1),
384 *reinterpret_cast<const int*>(&stl->facet_start[facet_num].vertex[pivot_vertex](1)),
385 new_vertex(1),
386 *reinterpret_cast<const int*>(&new_vertex(1)));
387 if (stl->facet_start[facet_num].vertex[pivot_vertex](2) != new_vertex(2))
388 printf("Changing coordinate x, vertex %e (0x%08x) to %e(0x%08x)\r\n",
389 stl->facet_start[facet_num].vertex[pivot_vertex](2),
390 *reinterpret_cast<const int*>(&stl->facet_start[facet_num].vertex[pivot_vertex](2)),
391 new_vertex(2),
392 *reinterpret_cast<const int*>(&new_vertex(2)));
393 }
394 #endif
395 stl->facet_start[facet_num].vertex[pivot_vertex] = new_vertex;
396 vnot = stl->neighbors_start[facet_num].which_vertex_not[next_edge];
397 facet_num = stl->neighbors_start[facet_num].neighbor[next_edge];
398 if (facet_num == -1)
399 break;
400
401 if (facet_num == first_facet) {
402 // back to the beginning
403 BOOST_LOG_TRIVIAL(info) << "Back to the first facet changing vertices: probably a mobius part. Try using a smaller tolerance or don't do a nearby check.";
404 return;
405 }
406 }
407 };
408
409 if (facet1 != -1) {
410 int vnot1 = (facet1 == edge_a.facet_number) ?
411 (edge_a.which_edge + 2) % 3 :
412 (edge_b.which_edge + 2) % 3;
413 if (((vnot1 + 2) % 3) == vertex1)
414 vnot1 += 3;
415 change_vertices(facet1, vnot1, new_vertex1);
416 }
417 if (facet2 != -1) {
418 int vnot2 = (facet2 == edge_a.facet_number) ?
419 (edge_a.which_edge + 2) % 3 :
420 (edge_b.which_edge + 2) % 3;
421 if (((vnot2 + 2) % 3) == vertex2)
422 vnot2 += 3;
423 change_vertices(facet2, vnot2, new_vertex2);
424 }
425 stl->stats.edges_fixed += 2;
426 }
int which_edge
Definition connect.cpp:51
std::vector< stl_facet > facet_start
Definition stl.h:150
stl_stats stats
Definition stl.h:153
std::vector< stl_neighbors > neighbors_start
Definition stl.h:151
int edges_fixed
Definition stl.h:118

References stl_stats::edges_fixed, HashEdge::facet_number, stl_file::facet_start, stl_file::neighbors_start, record_neighbors(), stl_file::stats, and HashEdge::which_edge.

Referenced by insert_edge_nearby().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ record_neighbors()

static void HashTableEdges::record_neighbors ( stl_file stl,
const HashEdge edge_a,
const HashEdge edge_b 
)
inlinestaticprivate
244 {
245 // Facet a's neighbor is facet b
246 stl->neighbors_start[edge_a.facet_number].neighbor[edge_a.which_edge % 3] = edge_b.facet_number; /* sets the .neighbor part */
247 stl->neighbors_start[edge_a.facet_number].which_vertex_not[edge_a.which_edge % 3] = (edge_b.which_edge + 2) % 3; /* sets the .which_vertex_not part */
248
249 // Facet b's neighbor is facet a
250 stl->neighbors_start[edge_b.facet_number].neighbor[edge_b.which_edge % 3] = edge_a.facet_number; /* sets the .neighbor part */
251 stl->neighbors_start[edge_b.facet_number].which_vertex_not[edge_b.which_edge % 3] = (edge_a.which_edge + 2) % 3; /* sets the .which_vertex_not part */
252
253 if ((edge_a.which_edge < 3 && edge_b.which_edge < 3) || (edge_a.which_edge > 2 && edge_b.which_edge > 2)) {
254 // These facets are oriented in opposite directions, their normals are probably messed up.
255 stl->neighbors_start[edge_a.facet_number].which_vertex_not[edge_a.which_edge % 3] += 3;
256 stl->neighbors_start[edge_b.facet_number].which_vertex_not[edge_b.which_edge % 3] += 3;
257 }
258
259 // Count successful connects:
260 // Total connects:
261 stl->stats.connected_edges += 2;
262 // Count individual connects:
263 switch (stl->neighbors_start[edge_a.facet_number].num_neighbors()) {
264 case 1: ++ stl->stats.connected_facets_1_edge; break;
265 case 2: ++ stl->stats.connected_facets_2_edge; break;
266 case 3: ++ stl->stats.connected_facets_3_edge; break;
267 default: assert(false);
268 }
269 switch (stl->neighbors_start[edge_b.facet_number].num_neighbors()) {
270 case 1: ++ stl->stats.connected_facets_1_edge; break;
271 case 2: ++ stl->stats.connected_facets_2_edge; break;
272 case 3: ++ stl->stats.connected_facets_3_edge; break;
273 default: assert(false);
274 }
275 }
int connected_facets_1_edge
Definition stl.h:108
int connected_edges
Definition stl.h:106
int connected_facets_2_edge
Definition stl.h:109
int connected_facets_3_edge
Definition stl.h:110

References stl_stats::connected_edges, stl_stats::connected_facets_1_edge, stl_stats::connected_facets_2_edge, stl_stats::connected_facets_3_edge, HashEdge::facet_number, stl_file::neighbors_start, stl_file::stats, and HashEdge::which_edge.

Referenced by insert_edge_exact(), and match_neighbors_nearby().

+ Here is the caller graph for this function:

Member Data Documentation

◆ collisions

size_t HashTableEdges::collisions = 0

Referenced by insert_edge().

◆ freed

size_t HashTableEdges::freed = 0

Referenced by ~HashTableEdges(), and insert_edge().

◆ heads

std::vector<HashEdge*> HashTableEdges::heads

Referenced by HashTableEdges(), and ~HashTableEdges().

◆ M

int HashTableEdges::M

Referenced by HashTableEdges(), and ~HashTableEdges().

◆ malloced

size_t HashTableEdges::malloced = 0

Referenced by insert_edge().

◆ pool

boost::object_pool<HashEdge> HashTableEdges::pool

Referenced by HashTableEdges(), and insert_edge().

◆ tail

HashEdge* HashTableEdges::tail

The documentation for this struct was generated from the following file: