Skip to content

Commit

Permalink
Fix normal direction when exporting STL (#6406)
Browse files Browse the repository at this point in the history
The export function does not depend on Model/ModelObject::mesh() family of functions,
changing them might break the already too brittle code.
  • Loading branch information
lukasmatena committed Apr 26, 2021
1 parent d1cfdcb commit 978b359
Show file tree
Hide file tree
Showing 6 changed files with 42 additions and 26 deletions.
12 changes: 0 additions & 12 deletions src/libslic3r/Model.cpp
Expand Up @@ -833,18 +833,6 @@ indexed_triangle_set ModelObject::raw_indexed_triangle_set() const
return out;
}

// Non-transformed (non-rotated, non-scaled, non-translated) sum of all object volumes.
TriangleMesh ModelObject::full_raw_mesh() const
{
TriangleMesh mesh;
for (const ModelVolume *v : this->volumes)
{
TriangleMesh vol_mesh(v->mesh());
vol_mesh.transform(v->get_matrix());
mesh.merge(vol_mesh);
}
return mesh;
}

const BoundingBoxf3& ModelObject::raw_mesh_bounding_box() const
{
Expand Down
2 changes: 0 additions & 2 deletions src/libslic3r/Model.hpp
Expand Up @@ -289,8 +289,6 @@ class ModelObject final : public ObjectBase
TriangleMesh raw_mesh() const;
// The same as above, but producing a lightweight indexed_triangle_set.
indexed_triangle_set raw_indexed_triangle_set() const;
// Non-transformed (non-rotated, non-scaled, non-translated) sum of all object volumes.
TriangleMesh full_raw_mesh() const;
// A transformed snug bounding box around the non-modifier object volumes, without the translation applied.
// This bounding box is only used for the actual slicing.
const BoundingBoxf3& raw_bounding_box() const;
Expand Down
1 change: 1 addition & 0 deletions src/libslic3r/PrintObject.cpp
Expand Up @@ -2207,6 +2207,7 @@ std::vector<ExPolygons> PrintObject::slice_volumes(
TriangleMesh vol_mesh(model_volume.mesh());
vol_mesh.transform(model_volume.get_matrix(), true);
mesh.merge(vol_mesh);
mesh.repair(false);
}
if (mesh.stl.stats.number_of_facets > 0) {
mesh.transform(m_trafo, true);
Expand Down
19 changes: 12 additions & 7 deletions src/libslic3r/TriangleMesh.cpp
Expand Up @@ -357,10 +357,14 @@ void TriangleMesh::transform(const Transform3d& t, bool fix_left_handed)
its_transform(its, t);
if (fix_left_handed && t.matrix().block(0, 0, 3, 3).determinant() < 0.) {
// Left handed transformation is being applied. It is a good idea to flip the faces and their normals.
this->repair(false);
stl_reverse_all_facets(&stl);
this->its.clear();
this->require_shared_vertices();
// As for the assert: the repair function would fix the normals, reversing would
// break them again. The caller should provide a mesh that does not need repair.
// The repair call is left here so things don't break more than they were.
assert(this->repaired);
this->repair(false);
stl_reverse_all_facets(&stl);
this->its.clear();
this->require_shared_vertices();
}
}

Expand All @@ -369,11 +373,12 @@ void TriangleMesh::transform(const Matrix3d& m, bool fix_left_handed)
stl_transform(&stl, m);
its_transform(its, m);
if (fix_left_handed && m.determinant() < 0.) {
// Left handed transformation is being applied. It is a good idea to flip the faces and their normals.
// See comments in function above.
assert(this->repaired);
this->repair(false);
stl_reverse_all_facets(&stl);
this->its.clear();
this->require_shared_vertices();
this->its.clear();
this->require_shared_vertices();
}
}

Expand Down
1 change: 0 additions & 1 deletion src/slic3r/GUI/GLCanvas3D.cpp
@@ -1,7 +1,6 @@
#include "libslic3r/libslic3r.h"
#include "GLCanvas3D.hpp"

#include "admesh/stl.h"
#include "libslic3r/ClipperUtils.hpp"
#include "libslic3r/PrintConfig.hpp"
#include "libslic3r/GCode/ThumbnailData.hpp"
Expand Down
33 changes: 29 additions & 4 deletions src/slic3r/GUI/Plater.cpp
Expand Up @@ -5085,27 +5085,52 @@ void Plater::export_stl(bool extended, bool selection_only)
if (selection_only && (obj_idx == -1 || selection.is_wipe_tower()))
return;

// Following lambda generates a combined mesh for export with normals pointing outwards.
auto mesh_to_export = [](const ModelObject* mo, bool instances) -> TriangleMesh {
TriangleMesh mesh;
for (const ModelVolume *v : mo->volumes)
if (v->is_model_part()) {
TriangleMesh vol_mesh(v->mesh());
vol_mesh.repair();
vol_mesh.transform(v->get_matrix(), true);
mesh.merge(vol_mesh);
}
mesh.repair();
if (instances) {
TriangleMesh vols_mesh(mesh);
mesh = TriangleMesh();
for (const ModelInstance *i : mo->instances) {
TriangleMesh m = vols_mesh;
m.transform(i->get_matrix(), true);
mesh.merge(m);
}
}
mesh.repair();
return mesh;
};

TriangleMesh mesh;
if (p->printer_technology == ptFFF) {
if (selection_only) {
const ModelObject* model_object = p->model.objects[obj_idx];
if (selection.get_mode() == Selection::Instance)
{
if (selection.is_single_full_object())
mesh = model_object->mesh();
mesh = mesh_to_export(model_object, true);
else
mesh = model_object->full_raw_mesh();
mesh = mesh_to_export(model_object, false);
}
else
{
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
mesh = model_object->volumes[volume->volume_idx()]->mesh();
mesh.transform(volume->get_volume_transformation().get_matrix());
mesh.transform(volume->get_volume_transformation().get_matrix(), true);
mesh.translate(-model_object->origin_translation.cast<float>());
}
}
else {
mesh = p->model.mesh();
for (const ModelObject *o : p->model.objects)
mesh.merge(mesh_to_export(o, true));
}
}
else
Expand Down

0 comments on commit 978b359

Please sign in to comment.