mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-05-08 16:09:09 +08:00
Clean up and fix TriangleMesh::split and relatives
This commit is contained in:
parent
62539bc35b
commit
19dc89bfab
@ -61,7 +61,7 @@ Model& Model::assign_copy(Model &&rhs)
|
|||||||
this->objects = std::move(rhs.objects);
|
this->objects = std::move(rhs.objects);
|
||||||
for (ModelObject *model_object : this->objects)
|
for (ModelObject *model_object : this->objects)
|
||||||
model_object->set_model(this);
|
model_object->set_model(this);
|
||||||
rhs.objects.clear();
|
rhs.objects.clear();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -651,7 +651,7 @@ ModelObject& ModelObject::assign_copy(ModelObject &&rhs)
|
|||||||
for (ModelInstance *model_instance : this->instances)
|
for (ModelInstance *model_instance : this->instances)
|
||||||
model_instance->set_model_object(this);
|
model_instance->set_model_object(this);
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelObject::assign_new_unique_ids_recursive()
|
void ModelObject::assign_new_unique_ids_recursive()
|
||||||
@ -970,8 +970,8 @@ Polygon ModelObject::convex_hull_2d(const Transform3d &trafo_instance)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::sort(pts.begin(), pts.end(), [](const Point& a, const Point& b) { return a(0) < b(0) || (a(0) == b(0) && a(1) < b(1)); });
|
std::sort(pts.begin(), pts.end(), [](const Point& a, const Point& b) { return a(0) < b(0) || (a(0) == b(0) && a(1) < b(1)); });
|
||||||
pts.erase(std::unique(pts.begin(), pts.end(), [](const Point& a, const Point& b) { return a(0) == b(0) && a(1) == b(1); }), pts.end());
|
pts.erase(std::unique(pts.begin(), pts.end(), [](const Point& a, const Point& b) { return a(0) == b(0) && a(1) == b(1); }), pts.end());
|
||||||
|
|
||||||
Polygon hull;
|
Polygon hull;
|
||||||
int n = (int)pts.size();
|
int n = (int)pts.size();
|
||||||
@ -1291,11 +1291,11 @@ void ModelObject::split(ModelObjectPtrs* new_objects)
|
|||||||
|
|
||||||
// XXX: this seems to be the only real usage of m_model, maybe refactor this so that it's not needed?
|
// XXX: this seems to be the only real usage of m_model, maybe refactor this so that it's not needed?
|
||||||
ModelObject* new_object = m_model->add_object();
|
ModelObject* new_object = m_model->add_object();
|
||||||
new_object->name = this->name;
|
new_object->name = this->name;
|
||||||
new_object->config = this->config;
|
new_object->config = this->config;
|
||||||
new_object->instances.reserve(this->instances.size());
|
new_object->instances.reserve(this->instances.size());
|
||||||
for (const ModelInstance *model_instance : this->instances)
|
for (const ModelInstance *model_instance : this->instances)
|
||||||
new_object->add_instance(*model_instance);
|
new_object->add_instance(*model_instance);
|
||||||
ModelVolume* new_vol = new_object->add_volume(*volume, std::move(*mesh));
|
ModelVolume* new_vol = new_object->add_volume(*volume, std::move(*mesh));
|
||||||
#if !ENABLE_VOLUMES_CENTERING_FIXES
|
#if !ENABLE_VOLUMES_CENTERING_FIXES
|
||||||
new_vol->center_geometry();
|
new_vol->center_geometry();
|
||||||
@ -1467,9 +1467,9 @@ int ModelVolume::extruder_id() const
|
|||||||
|
|
||||||
bool ModelVolume::is_splittable() const
|
bool ModelVolume::is_splittable() const
|
||||||
{
|
{
|
||||||
// the call mesh.has_multiple_patches() is expensive, so cache the value to calculate it only once
|
// the call mesh.is_splittable() is expensive, so cache the value to calculate it only once
|
||||||
if (m_is_splittable == -1)
|
if (m_is_splittable == -1)
|
||||||
m_is_splittable = (int)mesh.has_multiple_patches();
|
m_is_splittable = (int)mesh.is_splittable();
|
||||||
|
|
||||||
return m_is_splittable == 1;
|
return m_is_splittable == 1;
|
||||||
}
|
}
|
||||||
|
@ -338,113 +338,78 @@ void TriangleMesh::rotate(double angle, Point* center)
|
|||||||
this->translate(c(0), c(1), 0);
|
this->translate(c(0), c(1), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TriangleMesh::has_multiple_patches() const
|
/**
|
||||||
|
* Calculates whether or not the mesh is splittable.
|
||||||
|
*/
|
||||||
|
bool TriangleMesh::is_splittable() const
|
||||||
{
|
{
|
||||||
// we need neighbors
|
std::vector<bool> visited;
|
||||||
if (!this->repaired)
|
find_unvisited_neighbors(visited);
|
||||||
throw std::runtime_error("split() requires repair()");
|
|
||||||
|
|
||||||
if (this->stl.stats.number_of_facets == 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
std::vector<int> facet_queue(this->stl.stats.number_of_facets, 0);
|
// Try finding an unvisited facet. If there are none, the mesh is not splittable.
|
||||||
std::vector<char> facet_visited(this->stl.stats.number_of_facets, false);
|
auto it = std::find(visited.begin(), visited.end(), false);
|
||||||
int facet_queue_cnt = 1;
|
return it != visited.end();
|
||||||
facet_queue[0] = 0;
|
|
||||||
facet_visited[0] = true;
|
|
||||||
while (facet_queue_cnt > 0) {
|
|
||||||
int facet_idx = facet_queue[-- facet_queue_cnt];
|
|
||||||
facet_visited[facet_idx] = true;
|
|
||||||
for (int j = 0; j < 3; ++ j) {
|
|
||||||
int neighbor_idx = this->stl.neighbors_start[facet_idx].neighbor[j];
|
|
||||||
if (neighbor_idx != -1 && ! facet_visited[neighbor_idx])
|
|
||||||
facet_queue[facet_queue_cnt ++] = neighbor_idx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If any of the face was not visited at the first time, return "multiple bodies".
|
|
||||||
for (int facet_idx = 0; facet_idx < this->stl.stats.number_of_facets; ++ facet_idx)
|
|
||||||
if (! facet_visited[facet_idx])
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t TriangleMesh::number_of_patches() const
|
/**
|
||||||
|
* Visit all unvisited neighboring facets that are reachable from the first unvisited facet,
|
||||||
|
* and return them.
|
||||||
|
*
|
||||||
|
* @param facet_visited A reference to a vector of booleans. Contains whether or not a
|
||||||
|
* facet with the same index has been visited.
|
||||||
|
* @return A deque with all newly visited facets.
|
||||||
|
*/
|
||||||
|
std::deque<uint32_t> TriangleMesh::find_unvisited_neighbors(std::vector<bool> &facet_visited) const
|
||||||
{
|
{
|
||||||
// we need neighbors
|
// If the visited list is empty, populate it with false for every facet.
|
||||||
if (!this->repaired)
|
if (facet_visited.empty()) {
|
||||||
throw std::runtime_error("split() requires repair()");
|
facet_visited = std::vector<bool>(this->stl.stats.number_of_facets, false);
|
||||||
|
}
|
||||||
if (this->stl.stats.number_of_facets == 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
std::vector<int> facet_queue(this->stl.stats.number_of_facets, 0);
|
// Find the first unvisited facet.
|
||||||
std::vector<char> facet_visited(this->stl.stats.number_of_facets, false);
|
std::queue<int> facet_queue;
|
||||||
int facet_queue_cnt = 0;
|
auto facet = std::find(facet_visited.begin(), facet_visited.end(), false);
|
||||||
size_t num_bodies = 0;
|
if (facet != facet_visited.end())
|
||||||
for (;;) {
|
facet_queue.push(facet - facet_visited.begin());
|
||||||
// Find a seeding triangle for a new body.
|
|
||||||
int facet_idx = 0;
|
// Traverse all reachable neighbors and mark them as visited.
|
||||||
for (; facet_idx < this->stl.stats.number_of_facets; ++ facet_idx)
|
std::deque<uint32_t> facets;
|
||||||
if (! facet_visited[facet_idx]) {
|
while (!facet_queue.empty()) {
|
||||||
// A seed triangle was found.
|
int facet_idx = facet_queue.front();
|
||||||
facet_queue[facet_queue_cnt ++] = facet_idx;
|
facet_queue.pop();
|
||||||
facet_visited[facet_idx] = true;
|
|
||||||
break;
|
if (facet_idx != -1 && !facet_visited[facet_idx]) {
|
||||||
}
|
|
||||||
if (facet_idx == this->stl.stats.number_of_facets)
|
|
||||||
// No seed found.
|
|
||||||
break;
|
|
||||||
++ num_bodies;
|
|
||||||
while (facet_queue_cnt > 0) {
|
|
||||||
int facet_idx = facet_queue[-- facet_queue_cnt];
|
|
||||||
facet_visited[facet_idx] = true;
|
facet_visited[facet_idx] = true;
|
||||||
for (int j = 0; j < 3; ++ j) {
|
|
||||||
int neighbor_idx = this->stl.neighbors_start[facet_idx].neighbor[j];
|
facets.emplace_back(facet_idx);
|
||||||
if (neighbor_idx != -1 && ! facet_visited[neighbor_idx])
|
for (int facet : this->stl.neighbors_start[facet_idx].neighbor)
|
||||||
facet_queue[facet_queue_cnt ++] = neighbor_idx;
|
facet_queue.push(facet);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return num_bodies;
|
return facets;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Splits a mesh into multiple meshes when possible.
|
||||||
|
*
|
||||||
|
* @return A TriangleMeshPtrs with the newly created meshes.
|
||||||
|
*/
|
||||||
TriangleMeshPtrs TriangleMesh::split() const
|
TriangleMeshPtrs TriangleMesh::split() const
|
||||||
{
|
{
|
||||||
TriangleMeshPtrs meshes;
|
// Make sure we're not operating on a broken mesh.
|
||||||
std::vector<unsigned char> facet_visited(this->stl.stats.number_of_facets, false);
|
|
||||||
|
|
||||||
// we need neighbors
|
|
||||||
if (!this->repaired)
|
if (!this->repaired)
|
||||||
throw std::runtime_error("split() requires repair()");
|
throw std::runtime_error("split() requires repair()");
|
||||||
|
|
||||||
// loop while we have remaining facets
|
// Loop while we have remaining facets.
|
||||||
|
std::vector<bool> facet_visited;
|
||||||
|
TriangleMeshPtrs meshes;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
// get the first facet
|
std::deque<uint32_t> facets = find_unvisited_neighbors(facet_visited);
|
||||||
std::queue<int> facet_queue;
|
if (facets.empty())
|
||||||
std::deque<int> facets;
|
|
||||||
for (int facet_idx = 0; facet_idx < this->stl.stats.number_of_facets; ++ facet_idx) {
|
|
||||||
if (! facet_visited[facet_idx]) {
|
|
||||||
// if facet was not seen put it into queue and start searching
|
|
||||||
facet_queue.push(facet_idx);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (facet_queue.empty())
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
while (! facet_queue.empty()) {
|
// Create a new mesh for the part that was just split off.
|
||||||
int facet_idx = facet_queue.front();
|
|
||||||
facet_queue.pop();
|
|
||||||
if (! facet_visited[facet_idx]) {
|
|
||||||
facets.emplace_back(facet_idx);
|
|
||||||
for (int j = 0; j < 3; ++ j)
|
|
||||||
facet_queue.push(this->stl.neighbors_start[facet_idx].neighbor[j]);
|
|
||||||
facet_visited[facet_idx] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TriangleMesh* mesh = new TriangleMesh;
|
TriangleMesh* mesh = new TriangleMesh;
|
||||||
meshes.emplace_back(mesh);
|
meshes.emplace_back(mesh);
|
||||||
mesh->stl.stats.type = inmemory;
|
mesh->stl.stats.type = inmemory;
|
||||||
@ -453,8 +418,9 @@ TriangleMeshPtrs TriangleMesh::split() const
|
|||||||
stl_clear_error(&mesh->stl);
|
stl_clear_error(&mesh->stl);
|
||||||
stl_allocate(&mesh->stl);
|
stl_allocate(&mesh->stl);
|
||||||
|
|
||||||
|
// Assign the facets to the new mesh.
|
||||||
bool first = true;
|
bool first = true;
|
||||||
for (std::deque<int>::const_iterator facet = facets.begin(); facet != facets.end(); ++ facet) {
|
for (auto facet = facets.begin(); facet != facets.end(); ++ facet) {
|
||||||
mesh->stl.facet_start[facet - facets.begin()] = this->stl.facet_start[*facet];
|
mesh->stl.facet_start[facet - facets.begin()] = this->stl.facet_start[*facet];
|
||||||
stl_facet_stats(&mesh->stl, this->stl.facet_start[*facet], first);
|
stl_facet_stats(&mesh->stl, this->stl.facet_start[*facet], first);
|
||||||
}
|
}
|
||||||
|
@ -68,12 +68,8 @@ public:
|
|||||||
size_t facets_count() const { return this->stl.stats.number_of_facets; }
|
size_t facets_count() const { return this->stl.stats.number_of_facets; }
|
||||||
bool empty() const { return this->facets_count() == 0; }
|
bool empty() const { return this->facets_count() == 0; }
|
||||||
|
|
||||||
// Returns true, if there are two and more connected patches in the mesh.
|
bool is_splittable() const;
|
||||||
// Returns false, if one or zero connected patch is in the mesh.
|
std::deque<uint32_t> find_unvisited_neighbors(std::vector<bool> &facet_visited) const;
|
||||||
bool has_multiple_patches() const;
|
|
||||||
|
|
||||||
// Count disconnected triangle patches.
|
|
||||||
size_t number_of_patches() const;
|
|
||||||
|
|
||||||
stl_file stl;
|
stl_file stl;
|
||||||
bool repaired;
|
bool repaired;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user