Prusa Slicer 2.6.0
Loading...
Searching...
No Matches
connect.cpp File Reference
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <vector>
#include <boost/predef/other/endian.h>
#include <boost/log/trivial.hpp>
#include <boost/pool/object_pool.hpp>
#include "stl.h"
+ Include dependency graph for connect.cpp:

Go to the source code of this file.

Classes

struct  HashEdge
 
struct  HashTableEdges
 

Macros

#define BOOST_POOL_NO_MT
 

Functions

void stl_check_facets_exact (stl_file *stl)
 
void stl_check_facets_nearby (stl_file *stl, float tolerance)
 
void stl_remove_unconnected_facets (stl_file *stl)
 
void stl_fill_holes (stl_file *stl)
 
void stl_add_facet (stl_file *stl, const stl_facet *new_facet)
 

Macro Definition Documentation

◆ BOOST_POOL_NO_MT

#define BOOST_POOL_NO_MT

Function Documentation

◆ stl_add_facet()

void stl_add_facet ( stl_file stl,
const stl_facet new_facet 
)
734{
735 assert(stl->facet_start.size() == stl->stats.number_of_facets);
736 assert(stl->neighbors_start.size() == stl->stats.number_of_facets);
737 stl->facet_start.emplace_back(*new_facet);
738 // note that the normal vector is not set here, just initialized to 0.
739 stl->facet_start[stl->stats.number_of_facets].normal = stl_normal::Zero();
740 stl->neighbors_start.emplace_back();
741 ++ stl->stats.facets_added;
742 ++ stl->stats.number_of_facets;
743}
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
uint32_t number_of_facets
Definition stl.h:95
int facets_added
Definition stl.h:124

References stl_file::facet_start, stl_stats::facets_added, stl_file::neighbors_start, stl_stats::number_of_facets, and stl_file::stats.

Referenced by stl_fill_holes().

+ Here is the caller graph for this function:

◆ stl_check_facets_exact()

void stl_check_facets_exact ( stl_file stl)
433{
434 assert(stl->facet_start.size() == stl->neighbors_start.size());
435
436 stl->stats.connected_edges = 0;
440
441 // If any two of the three vertices are found to be exactally the same, call them degenerate and remove the facet.
442 // Do it before the next step, as the next step stores references to the face indices in the hash tables and removing a facet
443 // will break the references.
444 for (uint32_t i = 0; i < stl->stats.number_of_facets;) {
445 stl_facet &facet = stl->facet_start[i];
446 if (facet.vertex[0] == facet.vertex[1] || facet.vertex[1] == facet.vertex[2] || facet.vertex[0] == facet.vertex[2]) {
447 // Remove the degenerate facet.
448 facet = stl->facet_start[-- stl->stats.number_of_facets];
449 stl->facet_start.pop_back();
450 stl->neighbors_start.pop_back();
451 stl->stats.facets_removed += 1;
452 stl->stats.degenerate_facets += 1;
453 } else
454 ++ i;
455 }
456
457 // Initialize hash table.
458 HashTableEdges hash_table(stl->stats.number_of_facets);
459 for (auto &neighbor : stl->neighbors_start)
460 neighbor.reset();
461
462 // Connect neighbor edges.
463 for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
464 const stl_facet &facet = stl->facet_start[i];
465 for (int j = 0; j < 3; ++ j) {
466 HashEdge edge;
467 edge.facet_number = i;
468 edge.which_edge = j;
469 edge.load_exact(stl, &facet.vertex[j], &facet.vertex[(j + 1) % 3]);
470 hash_table.insert_edge_exact(stl, edge);
471 }
472 }
473
474#if 0
475 printf("Number of faces: %d, number of manifold edges: %d, number of connected edges: %d, number of unconnected edges: %d\r\n",
478#endif
479}
Definition connect.cpp:39
int facet_number
Definition connect.cpp:48
int which_edge
Definition connect.cpp:51
void load_exact(stl_file *stl, const stl_vertex *a, const stl_vertex *b)
Definition connect.cpp:54
Definition connect.cpp:123
Definition stl.h:48
stl_vertex vertex[3]
Definition stl.h:50
int connected_facets_1_edge
Definition stl.h:108
int connected_edges
Definition stl.h:106
int degenerate_facets
Definition stl.h:120
int facets_removed
Definition stl.h:122
int connected_facets_2_edge
Definition stl.h:109
int connected_facets_3_edge
Definition stl.h:110
unsigned __int32 uint32_t
Definition unistd.h:79

References stl_stats::connected_edges, stl_stats::connected_facets_1_edge, stl_stats::connected_facets_2_edge, stl_stats::connected_facets_3_edge, stl_stats::degenerate_facets, HashEdge::facet_number, stl_file::facet_start, stl_stats::facets_removed, HashTableEdges::insert_edge_exact(), HashEdge::load_exact(), stl_file::neighbors_start, stl_stats::number_of_facets, stl_file::stats, stl_facet::vertex, and HashEdge::which_edge.

Referenced by stl_repair(), and Slic3r::trianglemesh_repair_on_import().

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

◆ stl_check_facets_nearby()

void stl_check_facets_nearby ( stl_file stl,
float  tolerance 
)
482{
486
488 // No need to check any further. All facets are connected.
489 return;
490
491 HashTableEdges hash_table(stl->stats.number_of_facets);
492 for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
493 //FIXME is the copy necessary?
494 stl_facet facet = stl->facet_start[i];
495 for (int j = 0; j < 3; j++) {
496 if (stl->neighbors_start[i].neighbor[j] == -1) {
497 HashEdge edge;
498 edge.facet_number = i;
499 edge.which_edge = j;
500 if (edge.load_nearby(stl, facet.vertex[j], facet.vertex[(j + 1) % 3], tolerance))
501 // Only insert edges that have different keys.
502 hash_table.insert_edge_nearby(stl, edge);
503 }
504 }
505 }
506}
bool load_nearby(const stl_file *stl, const stl_vertex &a, const stl_vertex &b, float tolerance)
Definition connect.cpp:87

References stl_stats::connected_facets_1_edge, stl_stats::connected_facets_2_edge, stl_stats::connected_facets_3_edge, HashEdge::facet_number, stl_file::facet_start, HashTableEdges::insert_edge_nearby(), HashEdge::load_nearby(), stl_file::neighbors_start, stl_stats::number_of_facets, stl_file::stats, stl_facet::vertex, and HashEdge::which_edge.

Referenced by stl_repair(), and Slic3r::trianglemesh_repair_on_import().

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

◆ stl_fill_holes()

void stl_fill_holes ( stl_file stl)
653{
654 // Insert all unconnected edges into hash list.
655 HashTableEdges hash_table(stl->stats.number_of_facets);
656 for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
657 stl_facet facet = stl->facet_start[i];
658 for (int j = 0; j < 3; ++ j) {
659 if(stl->neighbors_start[i].neighbor[j] != -1)
660 continue;
661 HashEdge edge;
662 edge.facet_number = i;
663 edge.which_edge = j;
664 edge.load_exact(stl, &facet.vertex[j], &facet.vertex[(j + 1) % 3]);
665 hash_table.insert_edge_exact(stl, edge);
666 }
667 }
668
669 for (uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
670 stl_facet facet = stl->facet_start[i];
671 int neighbors_initial[3] = { stl->neighbors_start[i].neighbor[0], stl->neighbors_start[i].neighbor[1], stl->neighbors_start[i].neighbor[2] };
672 int first_facet = i;
673 for (int j = 0; j < 3; ++ j) {
674 if (stl->neighbors_start[i].neighbor[j] != -1)
675 continue;
676
677 stl_facet new_facet;
678 new_facet.vertex[0] = facet.vertex[j];
679 new_facet.vertex[1] = facet.vertex[(j + 1) % 3];
680 bool direction = neighbors_initial[(j + 2) % 3] == -1;
681 int facet_num = i;
682 int vnot = (j + 2) % 3;
683
684 for (;;) {
685 int pivot_vertex = 0;
686 int next_edge = 0;
687 if (vnot > 2) {
688 if (direction) {
689 pivot_vertex = (vnot + 1) % 3;
690 next_edge = vnot % 3;
691 } else {
692 pivot_vertex = (vnot + 2) % 3;
693 next_edge = pivot_vertex;
694 }
695 direction = ! direction;
696 } else {
697 if(direction == 0) {
698 pivot_vertex = (vnot + 1) % 3;
699 next_edge = vnot;
700 } else {
701 pivot_vertex = (vnot + 2) % 3;
702 next_edge = pivot_vertex;
703 }
704 }
705
706 int next_facet = stl->neighbors_start[facet_num].neighbor[next_edge];
707 if (next_facet == -1) {
708 new_facet.vertex[2] = stl->facet_start[facet_num].vertex[vnot % 3];
709 stl_add_facet(stl, &new_facet);
710 for (int k = 0; k < 3; ++ k) {
711 HashEdge edge;
712 edge.facet_number = stl->stats.number_of_facets - 1;
713 edge.which_edge = k;
714 edge.load_exact(stl, &new_facet.vertex[k], &new_facet.vertex[(k + 1) % 3]);
715 hash_table.insert_edge_exact(stl, edge);
716 }
717 break;
718 }
719
720 vnot = stl->neighbors_start[facet_num].which_vertex_not[next_edge];
721 facet_num = next_facet;
722
723 if (facet_num == first_facet) {
724 // back to the beginning
725 BOOST_LOG_TRIVIAL(info) << "Back to the first facet filling holes: probably a mobius part. Try using a smaller tolerance or don't do a nearby check.";
726 return;
727 }
728 }
729 }
730 }
731}
void stl_add_facet(stl_file *stl, const stl_facet *new_facet)
Definition connect.cpp:733

References HashEdge::facet_number, stl_file::facet_start, HashTableEdges::insert_edge_exact(), HashEdge::load_exact(), stl_file::neighbors_start, stl_stats::number_of_facets, stl_file::stats, stl_add_facet(), stl_facet::vertex, and HashEdge::which_edge.

Referenced by stl_repair(), and Slic3r::trianglemesh_repair_on_import().

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

◆ stl_remove_unconnected_facets()

void stl_remove_unconnected_facets ( stl_file stl)
509{
510 // A couple of things need to be done here. One is to remove any completely unconnected facets (0 edges connected) since these are
511 // useless and could be completely wrong. The second thing that needs to be done is to remove any degenerate facets that were created during
512 // stl_check_facets_nearby().
513 auto remove_facet = [stl](int facet_number)
514 {
515 ++ stl->stats.facets_removed;
516 /* Update list of connected edges */
517 stl_neighbors &neighbors = stl->neighbors_start[facet_number];
518 // Update statistics on unconnected triangle edges.
519 switch (neighbors.num_neighbors()) {
520 case 3: -- stl->stats.connected_facets_3_edge; // fall through
521 case 2: -- stl->stats.connected_facets_2_edge; // fall through
522 case 1: -- stl->stats.connected_facets_1_edge; // fall through
523 case 0: break;
524 default: assert(false);
525 }
526
527 if (facet_number < int(-- stl->stats.number_of_facets)) {
528 // Removing a face, which was not the last one.
529 // Copy the face and neighborship from the last face to facet_number.
530 stl->facet_start[facet_number] = stl->facet_start[stl->stats.number_of_facets];
531 neighbors = stl->neighbors_start[stl->stats.number_of_facets];
532 // Update neighborship of faces, which used to point to the last face, now moved to facet_number.
533 for (int i = 0; i < 3; ++ i)
534 if (neighbors.neighbor[i] != -1) {
535 int &other_face_idx = stl->neighbors_start[neighbors.neighbor[i]].neighbor[(neighbors.which_vertex_not[i] + 1) % 3];
536 if (other_face_idx != stl->stats.number_of_facets) {
537 BOOST_LOG_TRIVIAL(info) << "in remove_facet: neighbor = " << other_face_idx << " numfacets = " << stl->stats.number_of_facets << " this is wrong";
538 return;
539 }
540 other_face_idx = facet_number;
541 }
542 }
543
544 stl->facet_start.pop_back();
545 stl->neighbors_start.pop_back();
546 };
547
548 auto remove_degenerate = [stl, remove_facet](int facet)
549 {
550 // Update statistics on face connectivity after one edge was disconnected on the facet "facet_num".
551 auto update_connects_remove_1 = [stl](int facet_num) {
552 switch (stl->neighbors_start[facet_num].num_neighbors()) {
553 case 0: assert(false); break;
554 case 1: -- stl->stats.connected_facets_1_edge; break;
555 case 2: -- stl->stats.connected_facets_2_edge; break;
556 case 3: -- stl->stats.connected_facets_3_edge; break;
557 default: assert(false);
558 }
559 };
560
561 int edge_to_collapse = 0;
562 if (stl->facet_start[facet].vertex[0] == stl->facet_start[facet].vertex[1]) {
563 if (stl->facet_start[facet].vertex[1] == stl->facet_start[facet].vertex[2]) {
564 // All 3 vertices are equal. Collapse the edge with no neighbor if it exists.
565 const int *nbr = stl->neighbors_start[facet].neighbor;
566 edge_to_collapse = (nbr[0] == -1) ? 0 : (nbr[1] == -1) ? 1 : 2;
567 } else {
568 edge_to_collapse = 0;
569 }
570 } else if (stl->facet_start[facet].vertex[1] == stl->facet_start[facet].vertex[2]) {
571 edge_to_collapse = 1;
572 } else if (stl->facet_start[facet].vertex[2] == stl->facet_start[facet].vertex[0]) {
573 edge_to_collapse = 2;
574 } else {
575 // No degenerate. Function shouldn't have been called.
576 return;
577 }
578
579 int edge[3] = { (edge_to_collapse + 1) % 3, (edge_to_collapse + 2) % 3, edge_to_collapse };
580 int neighbor[] = {
581 stl->neighbors_start[facet].neighbor[edge[0]],
582 stl->neighbors_start[facet].neighbor[edge[1]],
583 stl->neighbors_start[facet].neighbor[edge[2]]
584 };
585 int vnot[] = {
586 stl->neighbors_start[facet].which_vertex_not[edge[0]],
587 stl->neighbors_start[facet].which_vertex_not[edge[1]],
588 stl->neighbors_start[facet].which_vertex_not[edge[2]]
589 };
590
591 // Update statistics on edge connectivity.
592 if ((neighbor[0] == -1) && (neighbor[1] != -1))
593 update_connects_remove_1(neighbor[1]);
594 if ((neighbor[1] == -1) && (neighbor[0] != -1))
595 update_connects_remove_1(neighbor[0]);
596
597 if (neighbor[0] >= 0) {
598 if (neighbor[1] >= 0) {
599 // Adjust the "flip" flag for the which_vertex_not values.
600 if (vnot[0] > 2) {
601 if (vnot[1] > 2) {
602 // The face to be removed has its normal flipped compared to the left & right neighbors, therefore after removing this face
603 // the two remaining neighbors will be oriented correctly.
604 vnot[0] -= 3;
605 vnot[1] -= 3;
606 } else
607 // One neighbor has its normal inverted compared to the face to be removed, the other is oriented equally.
608 // After removal, the two neighbors will have their normals flipped.
609 vnot[1] += 3;
610 } else if (vnot[1] > 2)
611 // One neighbor has its normal inverted compared to the face to be removed, the other is oriented equally.
612 // After removal, the two neighbors will have their normals flipped.
613 vnot[0] += 3;
614 }
615 stl->neighbors_start[neighbor[0]].neighbor[(vnot[0] + 1) % 3] = (neighbor[0] == neighbor[1]) ? -1 : neighbor[1];
616 stl->neighbors_start[neighbor[0]].which_vertex_not[(vnot[0] + 1) % 3] = vnot[1];
617 }
618 if (neighbor[1] >= 0) {
619 stl->neighbors_start[neighbor[1]].neighbor[(vnot[1] + 1) % 3] = (neighbor[0] == neighbor[1]) ? -1 : neighbor[0];
620 stl->neighbors_start[neighbor[1]].which_vertex_not[(vnot[1] + 1) % 3] = vnot[0];
621 }
622 if (neighbor[2] >= 0) {
623 update_connects_remove_1(neighbor[2]);
624 stl->neighbors_start[neighbor[2]].neighbor[(vnot[2] + 1) % 3] = -1;
625 }
626
627 remove_facet(facet);
628 };
629
630 // remove degenerate facets
631 for (uint32_t i = 0; i < stl->stats.number_of_facets;)
632 if (stl->facet_start[i].vertex[0] == stl->facet_start[i].vertex[1] ||
633 stl->facet_start[i].vertex[0] == stl->facet_start[i].vertex[2] ||
634 stl->facet_start[i].vertex[1] == stl->facet_start[i].vertex[2]) {
636// assert(stl_validate(stl));
637 } else
638 ++ i;
639
641 // There are some faces with no connected edge at all. Remove completely unconnected facets.
642 for (uint32_t i = 0; i < stl->stats.number_of_facets;)
643 if (stl->neighbors_start[i].num_neighbors() == 0) {
644 // This facet is completely unconnected. Remove it.
645 remove_facet(i);
646 assert(stl_validate(stl));
647 } else
648 ++ i;
649 }
650}
bool remove_degenerate(Polygons &polys)
Definition Polygon.cpp:505
bool stl_validate(const stl_file *stl, const indexed_triangle_set &its)
Definition shared.cpp:237
Definition stl.h:72
char which_vertex_not[3]
Definition stl.h:87
int neighbor[3]
Definition stl.h:85
int num_neighbors() const
Definition stl.h:82

References stl_stats::connected_facets_1_edge, stl_stats::connected_facets_2_edge, stl_stats::connected_facets_3_edge, stl_file::facet_start, stl_stats::facets_removed, stl_neighbors::neighbor, stl_file::neighbors_start, stl_neighbors::num_neighbors(), stl_stats::number_of_facets, stl_file::stats, stl_validate(), and stl_neighbors::which_vertex_not.

Referenced by stl_repair(), and Slic3r::trianglemesh_repair_on_import().

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