MeshFix integration

This commit is contained in:
PavelMikus 2022-05-31 16:04:44 +02:00
parent d4dc4bb8f6
commit e3541bb4fe
18 changed files with 162 additions and 142 deletions

View File

@ -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 set(SOURCES

View File

@ -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 } //namespace T_MESH
#endif //_BASICS_H #endif //_BASICS_H

View File

@ -39,7 +39,7 @@ namespace T_MESH
//! Base class type for nodes of non-oriented graphs //! Base class type for nodes of non-oriented graphs
class graphNode class graphNode : public Data
{ {
public: public:
@ -62,7 +62,7 @@ class graphNode
//! Base class type for edges of non-oriented graphs //! Base class type for edges of non-oriented graphs
class graphEdge class graphEdge : public Data
{ {
public: public:

View File

@ -45,6 +45,6 @@
namespace T_MESH 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 } //namespace T_MESH

View File

@ -32,6 +32,7 @@
#define _JLIST_H #define _JLIST_H
#include <stdio.h> #include <stdio.h>
#include "basics.h"
namespace T_MESH namespace T_MESH
{ {
@ -40,19 +41,18 @@ namespace T_MESH
//! Generic node of a doubly likned list. //! Generic node of a doubly likned list.
class Node class Node
{ {
friend class List; // This is to make methods in 'List' able to modify n_prev and n_next friend class List; // This is to make methods in 'List' able to modify n_prev and n_next
public : public :
void *data; //!< Actual data stored in the node Data *data; //!< Actual data stored in the node
//! Creates an isolated node storing 'd' //! 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'. //! 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 ~Node(); //!< Standard destructor
inline Node *prev() const {return n_prev;} //!< Returns the previous node in the list, possibly NULL 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. //! Doubly linked list.
class List class List : public Data
{ {
protected : protected :
@ -82,10 +82,10 @@ class List
List() {l_head = l_tail = NULL; l_numels = 0;} List() {l_head = l_tail = NULL; l_numels = 0;}
//! Creates a list containing an element 'd' (singleton) //! 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. //! 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. //! Creates a duplicated list.
List(List& l) {l_head = l_tail = NULL; l_numels = 0; appendList(&l);} 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). 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). 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 appendHead(const Data *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 appendTail(const Data *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 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()). //! 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()). //! 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); int removeNode(int i);
@ -125,11 +125,12 @@ class List
//! Moves node 'n' from this list to the end of 'l'. \n O(1). //! Moves node 'n' from this list to the end of 'l'. \n O(1).
void moveNodeTo(Node *n, List *l); void moveNodeTo(Node *n, List *l);
void *popHead(); //!< Deletes and removes the first node. Returns its data. \n O(1). Data *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 *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). //! 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 //! 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 //! 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 //! 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()). //! 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()' //! 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()). //! 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()). //! 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()). //! 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 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). //! 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 //! 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 //! based on the 'abstractHeap' class. See the documentation of the standard 'qsort' library
//! function for details on the prototype of the comparison function 'comp'. //! 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. //! Convenience macro to scan the nodes of a list.

View File

@ -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. //! of our version of the epsilon geometry for robust computation.
class Point class Point : public Data
{ {
public : public :
coord x,y,z; //!< Coordinates coord x,y,z; //!< Coordinates
@ -285,7 +285,7 @@ class Point
}; };
//! Lexycographic comparison to be used with jqsort() or abstractHeap. //! 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. //! Static point with DBL_MAX coordinates.
extern const Point INFINITE_POINT; extern const Point INFINITE_POINT;

View File

@ -38,7 +38,7 @@ namespace T_MESH
#define DI_MAX_NUMBER_OF_CELLS 10000 #define DI_MAX_NUMBER_OF_CELLS 10000
#define DI_EPSILON_POINT Point(1.0e-9, 1.0e-9, 1.0e-9) #define DI_EPSILON_POINT Point(1.0e-9, 1.0e-9, 1.0e-9)
class di_cell class di_cell : public Data
{ {
public: public:
Point mp, Mp; Point mp, Mp;

View File

@ -48,7 +48,7 @@ namespace T_MESH
//! assigning up to 256 different states to the edge. //! assigning up to 256 different states to the edge.
class Edge class Edge : public Data
{ {
public : public :
@ -237,14 +237,14 @@ class Edge
}; };
//! Edge comparison based on length to be used with jqsort() or abstractHeap. //! 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. //! 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. //! Vertex-based edge comparison for qsort.
//! Duplicated edges are contiguous in this sorting. //! 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 } //namespace T_MESH

View File

@ -42,7 +42,7 @@ namespace T_MESH
// //
/////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////
class mc_ints class mc_ints : public Data
{ {
public: 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(coord a, unsigned char b, Triangle *s) { ic = a; sg = b; v = NULL; source = s; }
~mc_ints() { if (v) delete(v); } ~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: public:
int x,y,z; // Coordinates (i.e. cell's position) 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 Point origin; // Origin for normalization
coord norm; // Normalization factor coord norm; // Normalization factor

View File

@ -104,6 +104,7 @@ class Basic_TMesh
Basic_TMesh(const Triangle *t, const bool keep_ref = false); Basic_TMesh(const Triangle *t, const bool keep_ref = false);
void init(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. //! Destructor. Frees the memory allocated for all the mesh elements.
//! Warning! This method uses the freeNodes() method of the class List, //! Warning! This method uses the freeNodes() method of the class List,
//! which is not guaranteed to work correctly on systems other than //! which is not guaranteed to work correctly on systems other than

View File

@ -46,7 +46,7 @@ namespace T_MESH
//! assigning up to 256 different states to the edge. //! assigning up to 256 different states to the edge.
class Triangle class Triangle : public Data
{ {
public : public :

View File

@ -196,7 +196,7 @@ Vertex *Basic_TMesh::checkGeometry()
if (varr == NULL) TMesh::warning("checkGeometry: Not enough memory. Can't check for coincident vertices.\n"); if (varr == NULL) TMesh::warning("checkGeometry: Not enough memory. Can't check for coincident vertices.\n");
else else
{ {
jqsort((void **)varr, V.numels(), xyzCompare); jqsort((Data **)varr, V.numels(), xyzCompare);
for (i=0; i<(V.numels()-1); i++) for (i=0; i<(V.numels()-1); i++)
{ {
v1 = ((Vertex *)varr[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"); if (evarr == NULL) TMesh::warning("checkGeometry: Not enough memory. Can't check for coincident edges.\n");
else else
{ {
jqsort((void **)evarr, E.numels(), lexEdgeCompare); jqsort((Data **)evarr, E.numels(), lexEdgeCompare);
for (i=0; i<(E.numels()-1); i++) for (i=0; i<(E.numels()-1); i++)
{ {
if (!lexEdgeCompare(evarr[i], evarr[i+1])) 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<V.numels(); i++) delete(var[i]); for (i=0; i<V.numels(); i++) delete(var[i]);
delete var; delete [] var;
delete [] triangles; delete [] triangles;
if(fixconnectivity) return fixConnectivity(); if(fixconnectivity) return fixConnectivity();

View File

@ -33,7 +33,7 @@
namespace T_MESH namespace T_MESH
{ {
int mc_ints::compare(const void *e1, const void *e2) int mc_ints::compare(const Data *e1, const Data *e2)
{ {
mc_ints *a = (mc_ints *)e1; mc_ints *a = (mc_ints *)e1;
mc_ints *b = (mc_ints *)e2; mc_ints *b = (mc_ints *)e2;

View File

@ -35,6 +35,8 @@
#include <algorithm> #include <algorithm>
#endif #endif
#include "basics.h"
namespace T_MESH namespace T_MESH
{ {
@ -68,15 +70,15 @@ void jqsort(void *v[], int numels, int(*comp)(const void *, const void *))
class compobj class compobj
{ {
int(*comp)(const void *, const void *); int(*comp)(const Data *, const Data *);
public: 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); compobj a(comp);
std::sort(v, v + numels, a); std::sort(v, v + numels, a);

View File

@ -39,9 +39,9 @@ namespace T_MESH
// Create a new node containing 'd', and link it to // // Create a new node containing 'd', and link it to //
// 'p' on the left (prev) and to 'n' on the right (next). // // '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_prev=(Node *)p) != NULL) n_prev->n_next = this;
if ((n_next=(Node *)n) != NULL) n_next->n_prev = this; if ((n_next=(Node *)n) != NULL) n_next->n_prev = this;
} }
@ -58,7 +58,7 @@ Node::~Node()
/////////// Constructor from list /////////////////// /////////// 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; l_head = l_tail = NULL; l_numels = 0;
for (int i=0; i<n; i++) appendTail(d[i]); for (int i=0; i<n; i++) appendTail(d[i]);
@ -73,21 +73,21 @@ List::~List()
////////////////// Append an element ////////////////// ////////////////// Append an element //////////////////
void List::appendHead(const void *d) void List::appendHead(const Data *d)
{ {
l_head = new Node(NULL, d, l_head); l_head = new Node(NULL, d, l_head);
if (l_tail == NULL) l_tail = l_head; if (l_tail == NULL) l_tail = l_head;
l_numels++; l_numels++;
} }
void List::appendTail(const void *d) void List::appendTail(const Data *d)
{ {
l_tail = new Node(l_tail, d, NULL); l_tail = new Node(l_tail, d, NULL);
if (l_head == NULL) l_head = l_tail; if (l_head == NULL) l_head = l_tail;
l_numels++; l_numels++;
} }
void List::insertAfter(Node *b, const void *d) void List::insertAfter(Node *b, const Data *d)
{ {
Node *nn = new Node(b, d, b->next()); Node *nn = new Node(b, d, b->next());
if (b == l_tail) l_tail = nn; 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 ///// //// 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); if (l_head != NULL) removeCell(l_head);
return data; return data;
} }
//// Removes the last node and returns the corresponding 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); if (l_tail != NULL) removeCell(l_tail);
return data; return data;
} }
//////////////////// Removes an element ////////////////// //////////////////// Removes an element //////////////////
int List::removeNode(const void *d) int List::removeNode(const Data *d)
{ {
Node *tmp = l_head; Node *tmp = l_head;
int i=1; int i=1;
@ -216,19 +216,19 @@ void List::removeCell(Node *n)
void List::freeCell(Node *n) void List::freeCell(Node *n)
{ {
free(n->data); delete(n->data);
removeCell(n); removeCell(n);
} }
void List::freeNode(void *d) void List::freeNode(Data *d)
{ {
free(d); delete(d);
removeNode(d); removeNode(d);
} }
//////////////////// Belonging check ///////////////// //////////////////// Belonging check /////////////////
Node *List::containsNode(const void *d) const Node *List::containsNode(const Data *d) const
{ {
Node *tmp = l_head; Node *tmp = l_head;
@ -241,10 +241,10 @@ Node *List::containsNode(const void *d) const
//////////////////// Replaces a node ///////////////// //////////////////// 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); Node *tmp = containsNode(od);
if (tmp != NULL) {tmp->data = (void *)nd; return tmp;} if (tmp != NULL) { tmp->data = (Data *)nd; return tmp;}
appendTail(nd); appendTail(nd);
return l_tail; return l_tail;
} }
@ -266,14 +266,14 @@ void List::removeNodes()
///// Conversion to array /////// ///// Conversion to array ///////
void **List::toArray() const Data **List::toArray() const
{ {
Node *n = l_head; Node *n = l_head;
int i; int i;
void **array; Data **array;
if (l_numels == 0) return NULL; 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; if (array == NULL) return NULL;
for (i=0; i<l_numels; i++, n=n->n_next) array[i] = n->data; for (i=0; i<l_numels; i++, n=n->n_next) array[i] = n->data;
@ -282,9 +282,9 @@ void **List::toArray() const
///// Sorts the list ///////// ///// 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; int ne = l_numels-1;
if (l_numels < 2) return 0; if (l_numels < 2) return 0;

View File

@ -235,7 +235,7 @@ bool Point::operator<(const Point& s) const
} }
// This can be used with jqsort // This can be used with jqsort
int xyzCompare(const void *a, const void *b) int xyzCompare(const Data *a, const Data *b)
{ {
coord c; coord c;

View File

@ -36,7 +36,7 @@ namespace T_MESH
//////// Length-based edge comparison for qsort ////////// //////// 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 la = ((Edge *)a)->squaredLength();
coord lb = ((Edge *)b)->squaredLength(); coord lb = ((Edge *)b)->squaredLength();
@ -50,7 +50,7 @@ int edgeCompare(const void *a, const void *b)
//////// Lexycographic edge comparison for qsort ////////// //////// 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 *va1 = ((Edge *)a)->v1;
Vertex *va2 = ((Edge *)a)->v2; Vertex *va2 = ((Edge *)a)->v2;
@ -70,7 +70,7 @@ int lexEdgeCompare(const void *a, const void *b)
//////// Vertex-based edge comparison for qsort ////////// //////// 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 *va1 = ((Edge *)a)->v1;
Vertex *va2 = ((Edge *)a)->v2; Vertex *va2 = ((Edge *)a)->v2;

View File

@ -33,6 +33,20 @@
namespace Slic3r { 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 { namespace detail {
using namespace T_MESH; using namespace T_MESH;
@ -158,6 +172,9 @@ public:
} }
for (const auto &face : its.indices) { 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()); this->CreateIndexedTriangle(tmp, face.x(), face.y(), face.z());
} }
@ -188,15 +205,19 @@ public:
return out; return out;
} }
bool meshclean_single_iteration(int inner_loops) { bool meshclean_single_iteration(int inner_loops, const std::atomic<bool> &canceled) {
bool ni, nd; bool ni, nd;
Triangle *t; Triangle *t;
Node *m; Node *m;
nd = strongDegeneracyRemoval(inner_loops); nd = strongDegeneracyRemoval(inner_loops);
if (canceled)
throw RepairCanceledException();
deselectTriangles(); deselectTriangles();
invertSelection(); invertSelection();
ni = strongIntersectionRemoval(inner_loops); ni = strongIntersectionRemoval(inner_loops);
if (canceled)
throw RepairCanceledException();
if (ni && nd) { if (ni && nd) {
FOREACHTRIANGLE(t, m) FOREACHTRIANGLE(t, m)
if (t->isExactlyDegenerate()) 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, bool fix_model_by_meshfix(ModelObject &model_object, int volume_idx, wxProgressDialog &progress_dlg,
const wxString &msg_header, std::string &fix_result) { const wxString &msg_header, std::string &fix_result) {
std::mutex mtx;
std::mutex mutex;
std::condition_variable condition; std::condition_variable condition;
std::unique_lock<std::mutex> lock(mutex);
struct Progress { struct Progress {
std::string message; std::string message;
int percent = 0; 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). // (It seems like wxWidgets initialize the COM contex as single threaded and we need a multi-threaded context).
bool success = false; bool success = false;
size_t ivolume = 0; size_t ivolume = 0;
auto on_progress = [&mutex, &condition, &ivolume, &volumes, &progress](const char *msg, unsigned prcnt) { auto on_progress = [&mtx, &condition, &ivolume, &volumes, &progress](const char *msg, unsigned prcnt) {
std::lock_guard<std::mutex> lk(mutex); std::unique_lock<std::mutex> lock(mtx);
progress.message = msg; progress.message = msg;
progress.percent = (int) floor((float(prcnt) + float(ivolume) * 100.f) / float(volumes.size())); progress.percent = (int) floor((float(prcnt) + float(ivolume) * 100.f) / float(volumes.size()));
progress.updated = true; progress.updated = true;
@ -269,19 +281,21 @@ bool fix_model_by_meshfix(ModelObject &model_object, int volume_idx, wxProgressD
std::vector<TriangleMesh> meshes_repaired; std::vector<TriangleMesh> meshes_repaired;
meshes_repaired.reserve(volumes.size()); meshes_repaired.reserve(volumes.size());
for (ModelVolume *mv : volumes) { for (ModelVolume *mv : volumes) {
std::vector<indexed_triangle_set> parts = its_split(mv->mesh().its);
for (size_t part_idx = 0; part_idx < parts.size(); ++part_idx) {
detail::Basic_TMesh_Adapter tin { }; detail::Basic_TMesh_Adapter tin { };
on_progress(L("Loading source model"), 0); on_progress(L("Loading source model"), 0);
if (canceled) if (canceled)
throw RepairCanceledException(); throw RepairCanceledException();
tin.load_indexed_triangle_set(mv->mesh().its); tin.load_indexed_triangle_set(parts[part_idx]);
tin.boundaries();
on_progress(L("Join closest components"), 10); on_progress(L("Join closest components"), 10);
if (canceled) if (canceled)
throw RepairCanceledException(); throw RepairCanceledException();
joinClosestComponents(&tin); joinClosestComponents(&tin);
tin.deselectTriangles(); tin.deselectTriangles();
tin.boundaries();
// Keep only the largest component (i.e. with most triangles) // Keep only the largest component (i.e. with most triangles)
on_progress(L("Remove smallest components"), 20); on_progress(L("Remove smallest components"), 20);
if (canceled) if (canceled)
@ -289,7 +303,7 @@ bool fix_model_by_meshfix(ModelObject &model_object, int volume_idx, wxProgressD
tin.removeSmallestComponents(); tin.removeSmallestComponents();
// Fill holes // Fill holes
on_progress(L("Fill holes"), 30); on_progress(L("Check holes"), 30);
if (canceled) if (canceled)
throw RepairCanceledException(); throw RepairCanceledException();
if (tin.boundaries()) { if (tin.boundaries()) {
@ -310,7 +324,7 @@ bool fix_model_by_meshfix(ModelObject &model_object, int volume_idx, wxProgressD
tin.invertSelection(); tin.invertSelection();
bool fixed = false; bool fixed = false;
while (iteration < 10 && !fixed) { //default constants taken from TMesh library while (iteration < 10 && !fixed) { //default constants taken from TMesh library
fixed = tin.meshclean_single_iteration(3); 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 on_progress(L("Fixing geometry"), std::min(95, 60 + iteration * 8)); // majority of objects should finish in 4 iterations
if (canceled) if (canceled)
throw RepairCanceledException(); throw RepairCanceledException();
@ -319,12 +333,18 @@ bool fix_model_by_meshfix(ModelObject &model_object, int volume_idx, wxProgressD
} }
if (tin.boundaries() || tin.T.numels() == 0) { if (tin.boundaries() || tin.T.numels() == 0) {
meshes_repaired.emplace_back(std::move(mv->mesh().its)); throw RepairFailedException();
throw Slic3r::RuntimeError(L("Model repair failed")); }
parts[part_idx] = tin.to_indexed_triangle_set();
} }
meshes_repaired.emplace_back(std::move(tin.to_indexed_triangle_set())); 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(parts[0]));
}
for (size_t i = 0; i < volumes.size(); ++i) { for (size_t i = 0; i < volumes.size(); ++i) {
volumes[i]->set_mesh(std::move(meshes_repaired[i])); volumes[i]->set_mesh(std::move(meshes_repaired[i]));
volumes[i]->calculate_convex_hull(); 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); on_progress(ex.what(), 100);
} }
}); });
while (!finished) { while (!finished) {
std::unique_lock<std::mutex> lock(mtx);
condition.wait_for(lock, std::chrono::milliseconds(250), [&progress] { condition.wait_for(lock, std::chrono::milliseconds(250), [&progress] {
return progress.updated; return progress.updated;
}); });
@ -357,6 +379,8 @@ bool fix_model_by_meshfix(ModelObject &model_object, int volume_idx, wxProgressD
progress.updated = false; progress.updated = false;
} }
worker_thread.join();
if (canceled) { if (canceled) {
// Nothing to show. // Nothing to show.
} else if (success) { } else if (success) {
@ -364,7 +388,7 @@ bool fix_model_by_meshfix(ModelObject &model_object, int volume_idx, wxProgressD
} else { } else {
fix_result = progress.message; fix_result = progress.message;
} }
worker_thread.join();
return !canceled; return !canceled;
} }