From a4e50f8219884e7ac963e35e092dc41a76b71e72 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Tue, 10 Jan 2023 17:45:48 +0100 Subject: [PATCH] Fix gizmo cut previews When using legacy hole drilling algorithm --- src/libslic3r/CMakeLists.txt | 2 + src/libslic3r/CSGMesh/CSGMesh.hpp | 23 ----- src/libslic3r/CSGMesh/CSGMeshCopy.hpp | 69 ++++++++++++++ src/libslic3r/CSGMesh/SliceCSGMesh.hpp | 4 +- src/libslic3r/CSGMesh/TriangleMeshAdapter.hpp | 95 +++++++++++++++++++ src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp | 33 ++++--- src/slic3r/GUI/MeshUtils.cpp | 42 ++++++-- src/slic3r/GUI/MeshUtils.hpp | 29 +++++- 8 files changed, 246 insertions(+), 51 deletions(-) create mode 100644 src/libslic3r/CSGMesh/CSGMeshCopy.hpp create mode 100644 src/libslic3r/CSGMesh/TriangleMeshAdapter.hpp diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index 4bb4fee9e7..da561d411a 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -44,6 +44,8 @@ set(SLIC3R_SOURCES CSGMesh/ModelToCSGMesh.hpp CSGMesh/PerformCSGMeshBooleans.hpp CSGMesh/VoxelizeCSGMesh.hpp + CSGMesh/TriangleMeshAdapter.hpp + CSGMesh/CSGMeshCopy.hpp EdgeGrid.cpp EdgeGrid.hpp ElephantFootCompensation.cpp diff --git a/src/libslic3r/CSGMesh/CSGMesh.hpp b/src/libslic3r/CSGMesh/CSGMesh.hpp index 00b60e4fc3..ef555a38b3 100644 --- a/src/libslic3r/CSGMesh/CSGMesh.hpp +++ b/src/libslic3r/CSGMesh/CSGMesh.hpp @@ -64,29 +64,6 @@ Transform3f get_transform(const CSGPartT &part) return part.trafo; } -// Provide default overloads for indexed_triangle_set to be usable as a plain -// CSGPart with an implicit union operation - -inline CSGType get_operation(const indexed_triangle_set &part) -{ - return CSGType::Union; -} - -inline CSGStackOp get_stack_operation(const indexed_triangle_set &part) -{ - return CSGStackOp::Continue; -} - -inline const indexed_triangle_set * get_mesh(const indexed_triangle_set &part) -{ - return ∂ -} - -inline Transform3f get_transform(const indexed_triangle_set &part) -{ - return Transform3f::Identity(); -} - // Default implementation struct CSGPart { AnyPtr its_ptr; diff --git a/src/libslic3r/CSGMesh/CSGMeshCopy.hpp b/src/libslic3r/CSGMesh/CSGMeshCopy.hpp new file mode 100644 index 0000000000..b296ecbfa7 --- /dev/null +++ b/src/libslic3r/CSGMesh/CSGMeshCopy.hpp @@ -0,0 +1,69 @@ +#ifndef CSGMESHCOPY_HPP +#define CSGMESHCOPY_HPP + +#include "CSGMesh.hpp" + +namespace Slic3r { namespace csg { + +// Copy a csg range but for the meshes, only copy the pointers. +template +void copy_csgrange_shallow(const Range &csgrange, OutIt out) +{ + for (const auto &part : csgrange) { + CSGPart cpy{AnyPtr{get_mesh(part)}, + get_operation(part), + get_transform(part)}; + + cpy.stack_operation = get_stack_operation(part); + + *out = std::move(cpy); + ++out; + } +} + +// Copy the csg range, allocating new meshes +template +void copy_csgrange_deep(const Range &csgrange, OutIt out) +{ + for (const auto &part : csgrange) { + + CSGPart cpy{{}, get_operation(part), get_transform(part)}; + + if (auto meshptr = get_mesh(part)) { + cpy.its_ptr = std::make_unique(*meshptr); + } + + cpy.stack_operation = get_stack_operation(part); + + *out = std::move(cpy); + ++out; + } +} + +template +bool is_same(const Range &A, const Range &B) +{ + bool ret = true; + + size_t s = A.size(); + + if (B.size() != s) + ret = false; + + size_t i = 0; + auto itA = A.begin(); + auto itB = B.begin(); + for (; ret && i < s; ++itA, ++itB, ++i) { + ret = ret && + get_mesh(*itA) == get_mesh(*itB) && + get_operation(*itA) == get_operation(*itB) && + get_stack_operation(*itA) == get_stack_operation(*itB) && + get_transform(*itA).isApprox(get_transform(*itB)); + } + + return ret; +} + +}} // namespace Slic3r::csg + +#endif // CSGCOPY_HPP diff --git a/src/libslic3r/CSGMesh/SliceCSGMesh.hpp b/src/libslic3r/CSGMesh/SliceCSGMesh.hpp index 041acedb0e..9d7b9a077d 100644 --- a/src/libslic3r/CSGMesh/SliceCSGMesh.hpp +++ b/src/libslic3r/CSGMesh/SliceCSGMesh.hpp @@ -13,7 +13,7 @@ namespace Slic3r { namespace csg { namespace detail { -void merge_slices(csg::CSGType op, size_t i, +inline void merge_slices(csg::CSGType op, size_t i, std::vector &target, std::vector &source) { @@ -31,7 +31,7 @@ void merge_slices(csg::CSGType op, size_t i, } } -void collect_nonempty_indices(csg::CSGType op, +inline void collect_nonempty_indices(csg::CSGType op, const std::vector &slicegrid, const std::vector &slices, std::vector &indices) diff --git a/src/libslic3r/CSGMesh/TriangleMeshAdapter.hpp b/src/libslic3r/CSGMesh/TriangleMeshAdapter.hpp new file mode 100644 index 0000000000..81b05b0463 --- /dev/null +++ b/src/libslic3r/CSGMesh/TriangleMeshAdapter.hpp @@ -0,0 +1,95 @@ +#ifndef TRIANGLEMESHADAPTER_HPP +#define TRIANGLEMESHADAPTER_HPP + +#include "CSGMesh.hpp" + +#include "libslic3r/TriangleMesh.hpp" + +namespace Slic3r { namespace csg { + +// Provide default overloads for indexed_triangle_set to be usable as a plain +// CSGPart with an implicit union operation + +inline CSGType get_operation(const indexed_triangle_set &part) +{ + return CSGType::Union; +} + +inline CSGStackOp get_stack_operation(const indexed_triangle_set &part) +{ + return CSGStackOp::Continue; +} + +inline const indexed_triangle_set * get_mesh(const indexed_triangle_set &part) +{ + return ∂ +} + +inline Transform3f get_transform(const indexed_triangle_set &part) +{ + return Transform3f::Identity(); +} + +inline CSGType get_operation(const indexed_triangle_set *const part) +{ + return CSGType::Union; +} + +inline CSGStackOp get_stack_operation(const indexed_triangle_set *const part) +{ + return CSGStackOp::Continue; +} + +inline const indexed_triangle_set * get_mesh(const indexed_triangle_set *const part) +{ + return part; +} + +inline Transform3f get_transform(const indexed_triangle_set *const part) +{ + return Transform3f::Identity(); +} + +inline CSGType get_operation(const TriangleMesh &part) +{ + return CSGType::Union; +} + +inline CSGStackOp get_stack_operation(const TriangleMesh &part) +{ + return CSGStackOp::Continue; +} + +inline const indexed_triangle_set * get_mesh(const TriangleMesh &part) +{ + return &part.its; +} + +inline Transform3f get_transform(const TriangleMesh &part) +{ + return Transform3f::Identity(); +} + +inline CSGType get_operation(const TriangleMesh * const part) +{ + return CSGType::Union; +} + +inline CSGStackOp get_stack_operation(const TriangleMesh * const part) +{ + return CSGStackOp::Continue; +} + +inline const indexed_triangle_set * get_mesh(const TriangleMesh * const part) +{ + return &part->its; +} + +inline Transform3f get_transform(const TriangleMesh * const part) +{ + return Transform3f::Identity(); +} + +}} // namespace Slic3r::csg + +#endif // TRIANGLEMESHADAPTER_HPP diff --git a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp index ac3750871e..705a13b902 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosCommon.cpp @@ -172,7 +172,7 @@ void InstancesHider::on_update() for (const TriangleMesh* mesh : meshes) { m_clippers.emplace_back(new MeshClipper); m_clippers.back()->set_plane(ClippingPlane(-Vec3d::UnitZ(), -SINKING_Z_THRESHOLD)); - m_clippers.back()->set_mesh(*mesh); + m_clippers.back()->set_mesh(mesh->its); } m_old_meshes = meshes; } @@ -299,8 +299,9 @@ std::vector Raycaster::raycasters() const return mrcs; } +} // namespace GUI - +namespace GUI { void ObjectClipper::on_update() @@ -313,33 +314,39 @@ void ObjectClipper::on_update() std::vector meshes; std::vector trafos; bool force_clipper_regeneration = false; + + std::unique_ptr mc; + Geometry::Transformation mc_tr; if (wxGetApp().preset_bundle->printers.get_selected_preset().printer_technology() == ptSLA) { // For sla printers we use the mesh generated by the backend const SLAPrintObject* po = get_pool()->selection_info()->print_object(); assert(po != nullptr); - m_sla_mesh_cache = po->get_mesh_to_print(); - if (!m_sla_mesh_cache.empty()) { - m_sla_mesh_cache.transform(po->trafo().inverse()); - meshes.emplace_back(&m_sla_mesh_cache); - trafos.emplace_back(Geometry::Transformation()); - force_clipper_regeneration = true; + auto partstoslice = po->get_parts_to_slice(); + if (! partstoslice.empty()) { + mc = std::make_unique(); + mc->set_mesh(partstoslice); + mc_tr = Geometry::Transformation{po->trafo().inverse().cast()}; } } - if (meshes.empty()) { + if (!mc && meshes.empty()) { for (const ModelVolume* mv : mo->volumes) { meshes.emplace_back(&mv->mesh()); trafos.emplace_back(mv->get_transformation()); } } - if (force_clipper_regeneration || meshes != m_old_meshes) { + if (mc || force_clipper_regeneration || meshes != m_old_meshes) { m_clippers.clear(); for (size_t i = 0; i < meshes.size(); ++i) { m_clippers.emplace_back(new MeshClipper, trafos[i]); - m_clippers.back().first->set_mesh(*meshes[i]); + m_clippers.back().first->set_mesh(meshes[i]->its); + } + m_old_meshes = std::move(meshes); + + if (mc) { + m_clippers.emplace_back(std::move(mc), mc_tr); } - m_old_meshes = meshes; m_active_inst_bb_radius = mo->instance_bounding_box(get_pool()->selection_info()->get_active_instance()).radius(); @@ -470,7 +477,7 @@ void SupportsClipper::on_update() // The timestamp has changed. m_clipper.reset(new MeshClipper); // The mesh should already have the shared vertices calculated. - m_clipper->set_mesh(print_object->support_mesh()); + m_clipper->set_mesh(print_object->support_mesh().its); m_old_timestamp = timestamp; } } diff --git a/src/slic3r/GUI/MeshUtils.cpp b/src/slic3r/GUI/MeshUtils.cpp index 39e463a19b..faa970c4a2 100644 --- a/src/slic3r/GUI/MeshUtils.cpp +++ b/src/slic3r/GUI/MeshUtils.cpp @@ -5,11 +5,13 @@ #include "libslic3r/TriangleMeshSlicer.hpp" #include "libslic3r/ClipperUtils.hpp" #include "libslic3r/Model.hpp" +#include "libslic3r/CSGMesh/SliceCSGMesh.hpp" #include "slic3r/GUI/GUI_App.hpp" #include "slic3r/GUI/Plater.hpp" #include "slic3r/GUI/Camera.hpp" + #include #include @@ -49,22 +51,38 @@ void MeshClipper::set_limiting_plane(const ClippingPlane& plane) -void MeshClipper::set_mesh(const TriangleMesh& mesh) +void MeshClipper::set_mesh(const indexed_triangle_set& mesh) { - if (m_mesh != &mesh) { + if (m_mesh.get() != &mesh) { m_mesh = &mesh; m_result.reset(); } } -void MeshClipper::set_negative_mesh(const TriangleMesh& mesh) +void MeshClipper::set_mesh(AnyPtr &&ptr) { - if (m_negative_mesh != &mesh) { + if (m_mesh.get() != ptr.get()) { + m_mesh = std::move(ptr); + m_result.reset(); + } +} + +void MeshClipper::set_negative_mesh(const indexed_triangle_set& mesh) +{ + if (m_negative_mesh.get() != &mesh) { m_negative_mesh = &mesh; m_result.reset(); } } +void MeshClipper::set_negative_mesh(AnyPtr &&ptr) +{ + if (m_negative_mesh.get() != ptr.get()) { + m_negative_mesh = std::move(ptr); + m_result.reset(); + } +} + void MeshClipper::set_transformation(const Geometry::Transformation& trafo) @@ -172,13 +190,21 @@ void MeshClipper::recalculate_triangles() MeshSlicingParams slicing_params; slicing_params.trafo.rotate(Eigen::Quaternion::FromTwoVectors(up, Vec3d::UnitZ())); - ExPolygons expolys = union_ex(slice_mesh(m_mesh->its, height_mesh, slicing_params)); + ExPolygons expolys; - if (m_negative_mesh && !m_negative_mesh->empty()) { - const ExPolygons neg_expolys = union_ex(slice_mesh(m_negative_mesh->its, height_mesh, slicing_params)); - expolys = diff_ex(expolys, neg_expolys); + if (m_csgmesh.empty()) { + if (m_mesh) + expolys = union_ex(slice_mesh(*m_mesh, height_mesh, slicing_params)); + + if (m_negative_mesh && !m_negative_mesh->empty()) { + const ExPolygons neg_expolys = union_ex(slice_mesh(*m_negative_mesh, height_mesh, slicing_params)); + expolys = diff_ex(expolys, neg_expolys); + } + } else { + expolys = std::move(csg::slice_csgmesh_ex(range(m_csgmesh), {height_mesh}, MeshSlicingParamsEx{slicing_params}).front()); } + // Triangulate and rotate the cut into world coords: Eigen::Quaterniond q; q.setFromTwoVectors(Vec3d::UnitZ(), up); diff --git a/src/slic3r/GUI/MeshUtils.hpp b/src/slic3r/GUI/MeshUtils.hpp index b7afbbb89a..c9ba916ade 100644 --- a/src/slic3r/GUI/MeshUtils.hpp +++ b/src/slic3r/GUI/MeshUtils.hpp @@ -5,6 +5,8 @@ #include "libslic3r/Geometry.hpp" #include "libslic3r/TriangleMesh.hpp" #include "libslic3r/AABBMesh.hpp" +#include "libslic3r/CSGMesh/TriangleMeshAdapter.hpp" +#include "libslic3r/CSGMesh/CSGMeshCopy.hpp" #include "admesh/stl.h" #include "slic3r/GUI/GLModel.hpp" @@ -14,7 +16,6 @@ #include namespace Slic3r { - namespace GUI { struct Camera; @@ -88,9 +89,25 @@ public: // Which mesh to cut. MeshClipper remembers const * to it, caller // must make sure that it stays valid. - void set_mesh(const TriangleMesh& mesh); + void set_mesh(const indexed_triangle_set& mesh); + void set_mesh(AnyPtr &&ptr); - void set_negative_mesh(const TriangleMesh &mesh); + void set_negative_mesh(const indexed_triangle_set &mesh); + void set_negative_mesh(AnyPtr &&ptr); + + template + void set_mesh(const Range &csgrange, bool copy_meshes = false) + { + if (! csg::is_same(range(m_csgmesh), csgrange)) { + m_csgmesh.clear(); + if (copy_meshes) + csg::copy_csgrange_deep(csgrange, std::back_inserter(m_csgmesh)); + else + csg::copy_csgrange_shallow(csgrange, std::back_inserter(m_csgmesh)); + + m_result.reset(); + } + } // Inform the MeshClipper about the transformation that transforms the mesh // into world coordinates. @@ -110,8 +127,10 @@ private: void recalculate_triangles(); Geometry::Transformation m_trafo; - const TriangleMesh* m_mesh = nullptr; - const TriangleMesh* m_negative_mesh = nullptr; + AnyPtr m_mesh; + AnyPtr m_negative_mesh; + std::vector m_csgmesh; + ClippingPlane m_plane; ClippingPlane m_limiting_plane = ClippingPlane::ClipsNothing();