mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-14 19:26:04 +08:00
MeshFix integration
This commit is contained in:
parent
d4dc4bb8f6
commit
e3541bb4fe
@ -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
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
||||
|
@ -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
|
||||
|
@ -31,7 +31,8 @@
|
||||
#ifndef _JLIST_H
|
||||
#define _JLIST_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdio.h>
|
||||
#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.
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -46,7 +46,7 @@ namespace T_MESH
|
||||
//! assigning up to 256 different states to the edge.
|
||||
|
||||
|
||||
class Triangle
|
||||
class Triangle : public Data
|
||||
{
|
||||
public :
|
||||
|
||||
|
@ -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<V.numels(); i++) delete(var[i]);
|
||||
delete var;
|
||||
delete [] var;
|
||||
delete [] triangles;
|
||||
|
||||
if(fixconnectivity) return fixConnectivity();
|
||||
|
@ -33,7 +33,7 @@
|
||||
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 *b = (mc_ints *)e2;
|
||||
|
@ -35,6 +35,8 @@
|
||||
#include <algorithm>
|
||||
#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);
|
||||
|
@ -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; i<n; i++) appendTail(d[i]);
|
||||
@ -73,21 +73,21 @@ List::~List()
|
||||
|
||||
////////////////// Append an element //////////////////
|
||||
|
||||
void List::appendHead(const void *d)
|
||||
void List::appendHead(const Data *d)
|
||||
{
|
||||
l_head = new Node(NULL, d, l_head);
|
||||
if (l_tail == NULL) l_tail = l_head;
|
||||
l_numels++;
|
||||
}
|
||||
|
||||
void List::appendTail(const void *d)
|
||||
void List::appendTail(const Data *d)
|
||||
{
|
||||
l_tail = new Node(l_tail, d, NULL);
|
||||
if (l_head == NULL) l_head = l_tail;
|
||||
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());
|
||||
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; i<l_numels; i++, n=n->n_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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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<bool> &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<std::mutex> 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<std::mutex> lk(mutex);
|
||||
auto on_progress = [&mtx, &condition, &ivolume, &volumes, &progress](const char *msg, unsigned prcnt) {
|
||||
std::unique_lock<std::mutex> 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<TriangleMesh> meshes_repaired;
|
||||
meshes_repaired.reserve(volumes.size());
|
||||
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 { };
|
||||
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<std::mutex> 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;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user