diff --git a/src/mesh_fix/CMakeLists.txt b/src/mesh_fix/CMakeLists.txt index 37e75602f5..073e912aaf 100644 --- a/src/mesh_fix/CMakeLists.txt +++ b/src/mesh_fix/CMakeLists.txt @@ -1,17 +1,3 @@ -################################################################################ -# General Informations -################################################################################ - -cmake_minimum_required(VERSION 3.0) -project(MeshFix) - -################################################################################ - -if(NOT CMAKE_BUILD_TYPE) - message(STATUS "No build type selected, default to Release") - set(CMAKE_BUILD_TYPE "Release") -endif() - ################################################################################ set(SOURCES diff --git a/src/mesh_fix/include/Kernel/basics.h b/src/mesh_fix/include/Kernel/basics.h index 1880a04cee..406076e00e 100644 --- a/src/mesh_fix/include/Kernel/basics.h +++ b/src/mesh_fix/include/Kernel/basics.h @@ -145,6 +145,12 @@ inline void p_swap(void **a, void **b) {void *t = *a; *a = *b; *b = t;} ///////////////////////////////////////////////////////////////////////////////////////////// +class Data { +public: + virtual ~Data() = default; +}; + + } //namespace T_MESH #endif //_BASICS_H diff --git a/src/mesh_fix/include/Kernel/graph.h b/src/mesh_fix/include/Kernel/graph.h index bac157229f..2fcd1f5968 100644 --- a/src/mesh_fix/include/Kernel/graph.h +++ b/src/mesh_fix/include/Kernel/graph.h @@ -39,7 +39,7 @@ namespace T_MESH //! Base class type for nodes of non-oriented graphs -class graphNode +class graphNode : public Data { public: @@ -62,7 +62,7 @@ class graphNode //! Base class type for edges of non-oriented graphs -class graphEdge +class graphEdge : public Data { public: diff --git a/src/mesh_fix/include/Kernel/jqsort.h b/src/mesh_fix/include/Kernel/jqsort.h index b151ea3ea5..57b4cc046d 100644 --- a/src/mesh_fix/include/Kernel/jqsort.h +++ b/src/mesh_fix/include/Kernel/jqsort.h @@ -45,6 +45,6 @@ namespace T_MESH { -extern void jqsort(void *v[], int numels, int (*comp)(const void *, const void *)); +extern void jqsort(Data *v[], int numels, int (*comp)(const Data *, const Data *)); } //namespace T_MESH diff --git a/src/mesh_fix/include/Kernel/list.h b/src/mesh_fix/include/Kernel/list.h index 06f9b802d7..ba2c77d723 100644 --- a/src/mesh_fix/include/Kernel/list.h +++ b/src/mesh_fix/include/Kernel/list.h @@ -31,7 +31,8 @@ #ifndef _JLIST_H #define _JLIST_H -#include +#include +#include "basics.h" namespace T_MESH { @@ -40,19 +41,18 @@ namespace T_MESH //! Generic node of a doubly likned list. - class Node { friend class List; // This is to make methods in 'List' able to modify n_prev and n_next public : - void *data; //!< Actual data stored in the node + Data *data; //!< Actual data stored in the node //! Creates an isolated node storing 'd' - Node(const void *d) {data=(void *)d; n_prev=n_next=NULL;} + Node(const void *d) {data=(Data *)d; n_prev=n_next=NULL;} //! Creates a new node storing 'd' and links it to a previous node 'p' and to a next one 'n'. - Node(const Node *p, const void *d, const Node *n); + Node(const Node *p, const Data *d, const Node *n); ~Node(); //!< Standard destructor inline Node *prev() const {return n_prev;} //!< Returns the previous node in the list, possibly NULL @@ -68,7 +68,7 @@ class Node //! Doubly linked list. -class List +class List : public Data { protected : @@ -82,10 +82,10 @@ class List List() {l_head = l_tail = NULL; l_numels = 0;} //! Creates a list containing an element 'd' (singleton) - List(const void *d) {l_head = l_tail = new Node(d); l_numels = 1;} + List(const Data *d) {l_head = l_tail = new Node(d); l_numels = 1;} //! Creates a list out of an array 'd' made of 'n' elements. - List(const void **d, int n); + List(const Data **d, int n); //! Creates a duplicated list. List(List& l) {l_head = l_tail = NULL; l_numels = 0; appendList(&l);} @@ -100,12 +100,12 @@ class List Node *tail() const {return l_tail;} //!< Gets the last node, NULL if empty. \n O(1). int numels() const {return l_numels;} //!< Gets the number of elements. \n O(1). - void appendHead(const void *d); //!< Appends a new node storing 'd' to the head. \n O(1). - void appendTail(const void *d); //!< Appends a new node storing 'd' to the tail. \n O(1). - void insertAfter(Node *n, const void *d); //! Inserts a new node storing 'd' right after 'n'. \n O(1). + void appendHead(const Data *d); //!< Appends a new node storing 'd' to the head. \n O(1). + void appendTail(const Data *d); //!< Appends a new node storing 'd' to the tail. \n O(1). + void insertAfter(Node *n, const Data *d); //! Inserts a new node storing 'd' right after 'n'. \n O(1). //! Deletes and removes the node containing 'd'. Returns its position, 0 if 'd' is not in the list. \n O(numels()). - int removeNode(const void *d); + int removeNode(const Data *d); //! Deletes and i'th node (starting from 0). Returns 0 if the list has less than i+1 nodes. \n O(numels()). int removeNode(int i); @@ -125,11 +125,12 @@ class List //! Moves node 'n' from this list to the end of 'l'. \n O(1). void moveNodeTo(Node *n, List *l); - void *popHead(); //!< Deletes and removes the first node. Returns its data. \n O(1). - void *popTail(); //!< Deletes and removes the last node. Returns its data. \n O(1). + Data *popHead(); //!< Deletes and removes the first node. Returns its data. \n O(1). + Data *popTail(); //!< Deletes and removes the last node. Returns its data. \n O(1). //! Deletes and removes the node 'n' from the list and frees data memory. \n O(1). - + + // NOTE: The following is not true after refactoring, void* has been replaced with Data* //! Warning. This method uses the free() function to to dispose the memory space //! used by the data stored in the node. This means that such data should have //! been allocated through malloc(), calloc() or realloc(), and not through the @@ -143,13 +144,13 @@ class List //! Deletes and removes the node storing 'd' and frees the memory occupied by 'd' itself. \n O(numels()). //! Warning. Read the comment for the method 'freeCell()' - void freeNode(void *d); + void freeNode(Data *d); //! Returns the node storing 'd'. NULL if not found. \n O(numels()). - Node *containsNode(const void *d) const; + Node *containsNode(const Data *d) const; //! Replaces old_n with new_n. The Node containing new_n is returned. \n O(numels()). - Node *replaceNode(const void *old_n, const void *new_n); + Node *replaceNode(const Data *old_n, const Data *new_n); //! Deletes and removes all the nodes and frees data memory. \n O(numels()). @@ -158,7 +159,7 @@ class List void removeNodes(); //!< Deletes and removes all the nodes. \n O(numels()). - void **toArray() const; //!< Creates an array out of the list. \n O(numels()). + Data **toArray() const; //!< Creates an array out of the list. \n O(numels()). //! Sorts the list using 'comp' as comparison function for two elements. \n O(numels()^2). @@ -167,7 +168,7 @@ class List //! the need to have a guaranteed O(NlogN) complexity, it is possible to implement a heap //! based on the 'abstractHeap' class. See the documentation of the standard 'qsort' library //! function for details on the prototype of the comparison function 'comp'. - int sort(int (*comp)(const void *, const void *)); + int sort(int (*comp)(const Data *, const Data *)); }; //! Convenience macro to scan the nodes of a list. diff --git a/src/mesh_fix/include/Kernel/point.h b/src/mesh_fix/include/Kernel/point.h index 7fa9bfda1a..049b6b72d7 100644 --- a/src/mesh_fix/include/Kernel/point.h +++ b/src/mesh_fix/include/Kernel/point.h @@ -68,7 +68,7 @@ PM_Rational orient2D(const PM_Rational& px, const PM_Rational& py, const PM_Rati //! of our version of the epsilon geometry for robust computation. -class Point +class Point : public Data { public : coord x,y,z; //!< Coordinates @@ -285,7 +285,7 @@ class Point }; //! Lexycographic comparison to be used with jqsort() or abstractHeap. -int xyzCompare(const void *p1, const void *p2); +int xyzCompare(const Data *p1, const Data *p2); //! Static point with DBL_MAX coordinates. extern const Point INFINITE_POINT; diff --git a/src/mesh_fix/include/TMesh/detectIntersections.h b/src/mesh_fix/include/TMesh/detectIntersections.h index 13870a00b6..9659890cf2 100644 --- a/src/mesh_fix/include/TMesh/detectIntersections.h +++ b/src/mesh_fix/include/TMesh/detectIntersections.h @@ -38,7 +38,7 @@ namespace T_MESH #define DI_MAX_NUMBER_OF_CELLS 10000 #define DI_EPSILON_POINT Point(1.0e-9, 1.0e-9, 1.0e-9) -class di_cell +class di_cell : public Data { public: Point mp, Mp; diff --git a/src/mesh_fix/include/TMesh/edge.h b/src/mesh_fix/include/TMesh/edge.h index 5e26f4ffdf..dba8b63163 100644 --- a/src/mesh_fix/include/TMesh/edge.h +++ b/src/mesh_fix/include/TMesh/edge.h @@ -48,7 +48,7 @@ namespace T_MESH //! assigning up to 256 different states to the edge. -class Edge +class Edge : public Data { public : @@ -237,14 +237,14 @@ class Edge }; //! Edge comparison based on length to be used with jqsort() or abstractHeap. -int edgeCompare(const void *a, const void *b); +int edgeCompare(const Data *a, const Data *b); //! Lexycographic edge comparison to be used with jqsort() or abstractHeap. -int lexEdgeCompare(const void *a, const void *b); +int lexEdgeCompare(const Data *a, const Data *b); //! Vertex-based edge comparison for qsort. //! Duplicated edges are contiguous in this sorting. -int vtxEdgeCompare(const void *a, const void *b); +int vtxEdgeCompare(const Data *a, const Data *b); } //namespace T_MESH diff --git a/src/mesh_fix/include/TMesh/marchIntersections.h b/src/mesh_fix/include/TMesh/marchIntersections.h index f7bc7ebb58..b1c822145c 100644 --- a/src/mesh_fix/include/TMesh/marchIntersections.h +++ b/src/mesh_fix/include/TMesh/marchIntersections.h @@ -42,7 +42,7 @@ namespace T_MESH // /////////////////////////////////////////////////////////////// -class mc_ints +class mc_ints : public Data { public: @@ -54,7 +54,7 @@ class mc_ints mc_ints(coord a, unsigned char b, Triangle *s) { ic = a; sg = b; v = NULL; source = s; } ~mc_ints() { if (v) delete(v); } - static int compare(const void *e1, const void *e2); + static int compare(const Data *e1, const Data *e2); }; @@ -64,7 +64,7 @@ class mc_ints // /////////////////////////////////////////////////////////////// -class mc_cell +class mc_cell : public Data { public: int x,y,z; // Coordinates (i.e. cell's position) @@ -94,7 +94,7 @@ private: // /////////////////////////////////////////////////////////////// -class mc_grid +class mc_grid : public Data { Point origin; // Origin for normalization coord norm; // Normalization factor diff --git a/src/mesh_fix/include/TMesh/tin.h b/src/mesh_fix/include/TMesh/tin.h index d32e32b02e..2f55e3d024 100644 --- a/src/mesh_fix/include/TMesh/tin.h +++ b/src/mesh_fix/include/TMesh/tin.h @@ -103,7 +103,8 @@ class Basic_TMesh //! keeps a pointer to the corresponding new element in the 'info' field. Basic_TMesh(const Triangle *t, const bool keep_ref = false); void init(const Triangle *t, const bool keep_ref = false); - + + //FIXED: //! Destructor. Frees the memory allocated for all the mesh elements. //! Warning! This method uses the freeNodes() method of the class List, //! which is not guaranteed to work correctly on systems other than diff --git a/src/mesh_fix/include/TMesh/triangle.h b/src/mesh_fix/include/TMesh/triangle.h index 42d5f4d147..710d5e3ef7 100644 --- a/src/mesh_fix/include/TMesh/triangle.h +++ b/src/mesh_fix/include/TMesh/triangle.h @@ -46,7 +46,7 @@ namespace T_MESH //! assigning up to 256 different states to the edge. -class Triangle +class Triangle : public Data { public : diff --git a/src/mesh_fix/src/Algorithms/checkAndRepair.cpp b/src/mesh_fix/src/Algorithms/checkAndRepair.cpp index 8ae28b6c8e..d524bb0715 100644 --- a/src/mesh_fix/src/Algorithms/checkAndRepair.cpp +++ b/src/mesh_fix/src/Algorithms/checkAndRepair.cpp @@ -196,7 +196,7 @@ Vertex *Basic_TMesh::checkGeometry() if (varr == NULL) TMesh::warning("checkGeometry: Not enough memory. Can't check for coincident vertices.\n"); else { - jqsort((void **)varr, V.numels(), xyzCompare); + jqsort((Data **)varr, V.numels(), xyzCompare); for (i=0; i<(V.numels()-1); i++) { v1 = ((Vertex *)varr[i]); @@ -220,7 +220,7 @@ Vertex *Basic_TMesh::checkGeometry() if (evarr == NULL) TMesh::warning("checkGeometry: Not enough memory. Can't check for coincident edges.\n"); else { - jqsort((void **)evarr, E.numels(), lexEdgeCompare); + jqsort((Data **)evarr, E.numels(), lexEdgeCompare); for (i=0; i<(E.numels()-1); i++) { if (!lexEdgeCompare(evarr[i], evarr[i+1])) @@ -377,7 +377,7 @@ bool Basic_TMesh::rebuildConnectivity(bool fixconnectivity) //!< AMF_CHANGE 1.1> } for (i=0; i #endif +#include "basics.h" + namespace T_MESH { @@ -68,15 +70,15 @@ void jqsort(void *v[], int numels, int(*comp)(const void *, const void *)) class compobj { - int(*comp)(const void *, const void *); + int(*comp)(const Data *, const Data *); public: - compobj(int(*c)(const void *, const void *)) { comp = c; } + compobj(int(*c)(const Data *, const Data *)) { comp = c; } - bool operator()(void *a, void *b) { return (comp(a, b) < 0); } + bool operator()(Data *a, Data *b) { return (comp(a, b) < 0); } }; -void jqsort(void *v[], int numels, int(*comp)(const void *, const void *)) +void jqsort(Data *v[], int numels, int(*comp)(const Data *, const Data *)) { compobj a(comp); std::sort(v, v + numels, a); diff --git a/src/mesh_fix/src/Kernel/list.cpp b/src/mesh_fix/src/Kernel/list.cpp index 7838970627..d5a0e37645 100644 --- a/src/mesh_fix/src/Kernel/list.cpp +++ b/src/mesh_fix/src/Kernel/list.cpp @@ -39,9 +39,9 @@ namespace T_MESH // Create a new node containing 'd', and link it to // // 'p' on the left (prev) and to 'n' on the right (next). // -Node::Node(const Node *p, const void *d, const Node *n) +Node::Node(const Node *p, const Data *d, const Node *n) { - data=(void *)d; + data=(Data *)d; if ((n_prev=(Node *)p) != NULL) n_prev->n_next = this; if ((n_next=(Node *)n) != NULL) n_next->n_prev = this; } @@ -58,7 +58,7 @@ Node::~Node() /////////// Constructor from list /////////////////// -List::List(const void **d, int n) +List::List(const Data **d, int n) { l_head = l_tail = NULL; l_numels = 0; for (int i=0; inext()); if (b == l_tail) l_tail = nn; @@ -141,25 +141,25 @@ void List::moveNodeTo(Node *n, List *l) //// Removes the first node and returns the corresponding data ///// -void *List::popHead() +Data *List::popHead() { - void *data = (l_head != NULL)?(l_head->data):(NULL); + Data *data = (l_head != NULL)?(l_head->data):(NULL); if (l_head != NULL) removeCell(l_head); return data; } //// Removes the last node and returns the corresponding data ///// -void *List::popTail() +Data *List::popTail() { - void *data = (l_tail != NULL)?(l_tail->data):(NULL); + Data *data = (l_tail != NULL)?(l_tail->data):(NULL); if (l_tail != NULL) removeCell(l_tail); return data; } //////////////////// Removes an element ////////////////// -int List::removeNode(const void *d) +int List::removeNode(const Data *d) { Node *tmp = l_head; int i=1; @@ -216,19 +216,19 @@ void List::removeCell(Node *n) void List::freeCell(Node *n) { - free(n->data); + delete(n->data); removeCell(n); } -void List::freeNode(void *d) +void List::freeNode(Data *d) { - free(d); + delete(d); removeNode(d); } //////////////////// Belonging check ///////////////// -Node *List::containsNode(const void *d) const +Node *List::containsNode(const Data *d) const { Node *tmp = l_head; @@ -241,10 +241,10 @@ Node *List::containsNode(const void *d) const //////////////////// Replaces a node ///////////////// -Node *List::replaceNode(const void *od, const void *nd) +Node *List::replaceNode(const Data *od, const Data *nd) { Node *tmp = containsNode(od); - if (tmp != NULL) {tmp->data = (void *)nd; return tmp;} + if (tmp != NULL) { tmp->data = (Data *)nd; return tmp;} appendTail(nd); return l_tail; } @@ -266,14 +266,14 @@ void List::removeNodes() ///// Conversion to array /////// -void **List::toArray() const +Data **List::toArray() const { Node *n = l_head; int i; - void **array; + Data **array; if (l_numels == 0) return NULL; - array = (void **)malloc(sizeof(void *)*l_numels); + array = (Data **)malloc(sizeof(Data *)*l_numels); if (array == NULL) return NULL; for (i=0; in_next) array[i] = n->data; @@ -282,9 +282,9 @@ void **List::toArray() const ///// Sorts the list ///////// -int List::sort(int (*comp)(const void *, const void *)) +int List::sort(int (*comp)(const Data *, const Data *)) { - void **array; + Data **array; int ne = l_numels-1; if (l_numels < 2) return 0; diff --git a/src/mesh_fix/src/Kernel/point.cpp b/src/mesh_fix/src/Kernel/point.cpp index a0bb3a342c..7d82b7f858 100644 --- a/src/mesh_fix/src/Kernel/point.cpp +++ b/src/mesh_fix/src/Kernel/point.cpp @@ -235,7 +235,7 @@ bool Point::operator<(const Point& s) const } // This can be used with jqsort -int xyzCompare(const void *a, const void *b) +int xyzCompare(const Data *a, const Data *b) { coord c; diff --git a/src/mesh_fix/src/TMesh/edge.cpp b/src/mesh_fix/src/TMesh/edge.cpp index 28f9510c54..cee1ff3eb7 100644 --- a/src/mesh_fix/src/TMesh/edge.cpp +++ b/src/mesh_fix/src/TMesh/edge.cpp @@ -36,7 +36,7 @@ namespace T_MESH //////// Length-based edge comparison for qsort ////////// -int edgeCompare(const void *a, const void *b) +int edgeCompare(const Data *a, const Data *b) { coord la = ((Edge *)a)->squaredLength(); coord lb = ((Edge *)b)->squaredLength(); @@ -50,7 +50,7 @@ int edgeCompare(const void *a, const void *b) //////// Lexycographic edge comparison for qsort ////////// -int lexEdgeCompare(const void *a, const void *b) +int lexEdgeCompare(const Data *a, const Data *b) { Vertex *va1 = ((Edge *)a)->v1; Vertex *va2 = ((Edge *)a)->v2; @@ -70,7 +70,7 @@ int lexEdgeCompare(const void *a, const void *b) //////// Vertex-based edge comparison for qsort ////////// -int vtxEdgeCompare(const void *a, const void *b) +int vtxEdgeCompare(const Data *a, const Data *b) { Vertex *va1 = ((Edge *)a)->v1; Vertex *va2 = ((Edge *)a)->v2; diff --git a/src/slic3r/Utils/FixModelByMeshFix.cpp b/src/slic3r/Utils/FixModelByMeshFix.cpp index eeb892b5ce..8063132082 100644 --- a/src/slic3r/Utils/FixModelByMeshFix.cpp +++ b/src/slic3r/Utils/FixModelByMeshFix.cpp @@ -33,6 +33,20 @@ namespace Slic3r { +class RepairCanceledException: public std::exception { +public: + const char* what() const throw () { + return "Model repair has been canceled"; + } +}; + +class RepairFailedException: public std::exception { +public: + const char* what() const throw () { + return "Model repair has failed"; + } +}; + namespace detail { using namespace T_MESH; @@ -158,6 +172,9 @@ public: } for (const auto &face : its.indices) { + if (face.x() == face.y() || face.y() == face.z() || face.z() == face.x()) { + continue; + } this->CreateIndexedTriangle(tmp, face.x(), face.y(), face.z()); } @@ -188,15 +205,19 @@ public: return out; } - bool meshclean_single_iteration(int inner_loops) { + bool meshclean_single_iteration(int inner_loops, const std::atomic &canceled) { bool ni, nd; Triangle *t; Node *m; nd = strongDegeneracyRemoval(inner_loops); + if (canceled) + throw RepairCanceledException(); deselectTriangles(); invertSelection(); ni = strongIntersectionRemoval(inner_loops); + if (canceled) + throw RepairCanceledException(); if (ni && nd) { FOREACHTRIANGLE(t, m) if (t->isExactlyDegenerate()) @@ -225,19 +246,10 @@ private: } -class RepairCanceledException: public std::exception { -public: - const char* what() const throw () { - return "Model repair has been canceled"; - } -}; - bool fix_model_by_meshfix(ModelObject &model_object, int volume_idx, wxProgressDialog &progress_dlg, const wxString &msg_header, std::string &fix_result) { - - std::mutex mutex; + std::mutex mtx; std::condition_variable condition; - std::unique_lock lock(mutex); struct Progress { std::string message; int percent = 0; @@ -256,8 +268,8 @@ bool fix_model_by_meshfix(ModelObject &model_object, int volume_idx, wxProgressD // (It seems like wxWidgets initialize the COM contex as single threaded and we need a multi-threaded context). bool success = false; size_t ivolume = 0; - auto on_progress = [&mutex, &condition, &ivolume, &volumes, &progress](const char *msg, unsigned prcnt) { - std::lock_guard lk(mutex); + auto on_progress = [&mtx, &condition, &ivolume, &volumes, &progress](const char *msg, unsigned prcnt) { + std::unique_lock lock(mtx); progress.message = msg; progress.percent = (int) floor((float(prcnt) + float(ivolume) * 100.f) / float(volumes.size())); progress.updated = true; @@ -269,62 +281,70 @@ bool fix_model_by_meshfix(ModelObject &model_object, int volume_idx, wxProgressD std::vector meshes_repaired; meshes_repaired.reserve(volumes.size()); for (ModelVolume *mv : volumes) { + std::vector parts = its_split(mv->mesh().its); + for (size_t part_idx = 0; part_idx < parts.size(); ++part_idx) { - detail::Basic_TMesh_Adapter tin { }; - on_progress(L("Loading source model"), 0); - if (canceled) - throw RepairCanceledException(); - tin.load_indexed_triangle_set(mv->mesh().its); - - on_progress(L("Join closest components"), 10); - if (canceled) - throw RepairCanceledException(); - joinClosestComponents(&tin); - tin.deselectTriangles(); - - // Keep only the largest component (i.e. with most triangles) - on_progress(L("Remove smallest components"), 20); - if (canceled) - throw RepairCanceledException(); - tin.removeSmallestComponents(); - - // Fill holes - on_progress(L("Fill holes"), 30); - if (canceled) - throw RepairCanceledException(); - if (tin.boundaries()) { - on_progress(L("Patch small holes"), 40); + detail::Basic_TMesh_Adapter tin { }; + on_progress(L("Loading source model"), 0); if (canceled) throw RepairCanceledException(); - tin.fillSmallBoundaries(0, true); - } - - on_progress(L("Geometry check"), 50); - if (canceled) - throw RepairCanceledException(); - // Run geometry correction - if (!tin.boundaries()) { - int iteration = 0; - on_progress(L("Iterative geometry correction"), 55); + tin.load_indexed_triangle_set(parts[part_idx]); + tin.boundaries(); + on_progress(L("Join closest components"), 10); + if (canceled) + throw RepairCanceledException(); + joinClosestComponents(&tin); tin.deselectTriangles(); - tin.invertSelection(); - bool fixed = false; - while (iteration < 10 && !fixed) { //default constants taken from TMesh library - fixed = tin.meshclean_single_iteration(3); - on_progress(L("Fixing geometry"), std::min(95, 60 + iteration * 8)); // majority of objects should finish in 4 iterations + tin.boundaries(); + // Keep only the largest component (i.e. with most triangles) + on_progress(L("Remove smallest components"), 20); + if (canceled) + throw RepairCanceledException(); + tin.removeSmallestComponents(); + + // Fill holes + on_progress(L("Check holes"), 30); + if (canceled) + throw RepairCanceledException(); + if (tin.boundaries()) { + on_progress(L("Patch small holes"), 40); if (canceled) throw RepairCanceledException(); - iteration++; + tin.fillSmallBoundaries(0, true); } + + on_progress(L("Geometry check"), 50); + if (canceled) + throw RepairCanceledException(); + // Run geometry correction + if (!tin.boundaries()) { + int iteration = 0; + on_progress(L("Iterative geometry correction"), 55); + tin.deselectTriangles(); + tin.invertSelection(); + bool fixed = false; + while (iteration < 10 && !fixed) { //default constants taken from TMesh library + fixed = tin.meshclean_single_iteration(3, canceled); + on_progress(L("Fixing geometry"), std::min(95, 60 + iteration * 8)); // majority of objects should finish in 4 iterations + if (canceled) + throw RepairCanceledException(); + iteration++; + } + } + + if (tin.boundaries() || tin.T.numels() == 0) { + throw RepairFailedException(); + } + parts[part_idx] = tin.to_indexed_triangle_set(); } - if (tin.boundaries() || tin.T.numels() == 0) { - meshes_repaired.emplace_back(std::move(mv->mesh().its)); - throw Slic3r::RuntimeError(L("Model repair failed")); + for (size_t part_idx = 1; part_idx < parts.size(); ++part_idx) { + its_merge(parts[0], parts[part_idx]); } - meshes_repaired.emplace_back(std::move(tin.to_indexed_triangle_set())); + meshes_repaired.emplace_back(std::move(parts[0])); } + for (size_t i = 0; i < volumes.size(); ++i) { volumes[i]->set_mesh(std::move(meshes_repaired[i])); volumes[i]->calculate_convex_hull(); @@ -345,7 +365,9 @@ bool fix_model_by_meshfix(ModelObject &model_object, int volume_idx, wxProgressD on_progress(ex.what(), 100); } }); + while (!finished) { + std::unique_lock lock(mtx); condition.wait_for(lock, std::chrono::milliseconds(250), [&progress] { return progress.updated; }); @@ -357,6 +379,8 @@ bool fix_model_by_meshfix(ModelObject &model_object, int volume_idx, wxProgressD progress.updated = false; } + worker_thread.join(); + if (canceled) { // Nothing to show. } else if (success) { @@ -364,7 +388,7 @@ bool fix_model_by_meshfix(ModelObject &model_object, int volume_idx, wxProgressD } else { fix_result = progress.message; } - worker_thread.join(); + return !canceled; }