From 83b6b82188941744fe7b1a0ad04f5888b7900bb0 Mon Sep 17 00:00:00 2001 From: bubnikv <bubnikv@gmail.com> Date: Mon, 16 Sep 2019 16:35:08 +0200 Subject: [PATCH 01/11] Refactored ExtrusionEntityCollection::flatten() --- src/libslic3r/ExtrusionEntityCollection.cpp | 26 ++++++++++----------- src/libslic3r/ExtrusionEntityCollection.hpp | 1 - 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/libslic3r/ExtrusionEntityCollection.cpp b/src/libslic3r/ExtrusionEntityCollection.cpp index 9ae116c47..70c2348af 100644 --- a/src/libslic3r/ExtrusionEntityCollection.cpp +++ b/src/libslic3r/ExtrusionEntityCollection.cpp @@ -11,7 +11,7 @@ ExtrusionEntityCollection::ExtrusionEntityCollection(const ExtrusionPaths &paths this->append(paths); } -ExtrusionEntityCollection& ExtrusionEntityCollection::operator= (const ExtrusionEntityCollection &other) +ExtrusionEntityCollection& ExtrusionEntityCollection::operator=(const ExtrusionEntityCollection &other) { this->entities = other.entities; for (size_t i = 0; i < this->entities.size(); ++i) @@ -175,20 +175,20 @@ size_t ExtrusionEntityCollection::items_count() const } // Returns a single vector of pointers to all non-collection items contained in this one. -void ExtrusionEntityCollection::flatten(ExtrusionEntityCollection* retval) const -{ - for (const ExtrusionEntity *entity : this->entities) - if (entity->is_collection()) - retval->append(static_cast<const ExtrusionEntityCollection*>(entity)->flatten().entities); - else - retval->append(*entity); -} - ExtrusionEntityCollection ExtrusionEntityCollection::flatten() const { - ExtrusionEntityCollection coll; - this->flatten(&coll); - return coll; + struct Flatten { + ExtrusionEntityCollection out; + void recursive_do(const ExtrusionEntityCollection &collection) { + for (const ExtrusionEntity* entity : collection.entities) + if (entity->is_collection()) + this->recursive_do(*static_cast<const ExtrusionEntityCollection*>(entity)); + else + out.append(*entity); + } + } flatten; + flatten.recursive_do(*this); + return flatten.out; } double ExtrusionEntityCollection::min_mm3_per_mm() const diff --git a/src/libslic3r/ExtrusionEntityCollection.hpp b/src/libslic3r/ExtrusionEntityCollection.hpp index 4fe964ee1..221afc453 100644 --- a/src/libslic3r/ExtrusionEntityCollection.hpp +++ b/src/libslic3r/ExtrusionEntityCollection.hpp @@ -85,7 +85,6 @@ public: Polygons polygons_covered_by_spacing(const float scaled_epsilon = 0.f) const { Polygons out; this->polygons_covered_by_spacing(out, scaled_epsilon); return out; } size_t items_count() const; - void flatten(ExtrusionEntityCollection* retval) const; ExtrusionEntityCollection flatten() const; double min_mm3_per_mm() const; double total_volume() const override { double volume=0.; for (const auto& ent : entities) volume+=ent->total_volume(); return volume; } From 93aa5ac6ce0649d696a315177dee9158ea00df8a Mon Sep 17 00:00:00 2001 From: YuSanka <yusanka@gmail.com> Date: Tue, 17 Sep 2019 13:41:44 +0200 Subject: [PATCH 02/11] Fixed re-scaling under MSW for Layers editing + Clean code in GUI_ObjectManipulation.cpp --- src/slic3r/GUI/GUI_ObjectLayers.cpp | 41 +++++++++++++++++++++++ src/slic3r/GUI/GUI_ObjectLayers.hpp | 1 + src/slic3r/GUI/GUI_ObjectManipulation.cpp | 14 -------- src/slic3r/GUI/wxExtensions.cpp | 29 ++++++++++++---- 4 files changed, 65 insertions(+), 20 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectLayers.cpp b/src/slic3r/GUI/GUI_ObjectLayers.cpp index 822b137c3..9053cdd42 100644 --- a/src/slic3r/GUI/GUI_ObjectLayers.cpp +++ b/src/slic3r/GUI/GUI_ObjectLayers.cpp @@ -227,6 +227,42 @@ void ObjectLayers::msw_rescale() { m_bmp_delete.msw_rescale(); m_bmp_add.msw_rescale(); + + m_grid_sizer->SetHGap(wxGetApp().em_unit()); + + // rescale edit-boxes + const int cells_cnt = m_grid_sizer->GetCols() * m_grid_sizer->GetEffectiveRowsCount(); + for (int i = 0; i < cells_cnt; i++) + { + const wxSizerItem* item = m_grid_sizer->GetItem(i); + if (item->IsWindow()) + { + LayerRangeEditor* editor = dynamic_cast<LayerRangeEditor*>(item->GetWindow()); + if (editor != nullptr) + editor->msw_rescale(); + } + else if (item->IsSizer()) // case when we have editor with buttons + { + wxSizerItem* e_item = item->GetSizer()->GetItem(size_t(0)); // editor + if (e_item->IsWindow()) { + LayerRangeEditor* editor = dynamic_cast<LayerRangeEditor*>(e_item->GetWindow()); + if (editor != nullptr) + editor->msw_rescale(); + } + + const std::vector<size_t> btns = {2, 3}; // del_btn, add_btn + for (auto btn : btns) + { + wxSizerItem* b_item = item->GetSizer()->GetItem(btn); + if (b_item->IsWindow()) { + ScalableButton* button = dynamic_cast<ScalableButton*>(b_item->GetWindow()); + if (button != nullptr) + button->msw_rescale(); + } + } + } + } + m_grid_sizer->Layout(); } void ObjectLayers::reset_selection() @@ -342,5 +378,10 @@ coordf_t LayerRangeEditor::get_value() return layer_height; } +void LayerRangeEditor::msw_rescale() +{ + SetMinSize(wxSize(8 * wxGetApp().em_unit(), wxDefaultCoord)); +} + } //namespace GUI } //namespace Slic3r \ No newline at end of file diff --git a/src/slic3r/GUI/GUI_ObjectLayers.hpp b/src/slic3r/GUI/GUI_ObjectLayers.hpp index f274183e2..c0de3be4c 100644 --- a/src/slic3r/GUI/GUI_ObjectLayers.hpp +++ b/src/slic3r/GUI/GUI_ObjectLayers.hpp @@ -49,6 +49,7 @@ public: EditorType type() const {return m_type;} void set_focus_data() const { m_set_focus_data(m_type);} + void msw_rescale(); private: coordf_t get_value(); diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index 695c81b5f..2295ac0b6 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -104,8 +104,6 @@ void msw_rescale_word_local_combo(wxBitmapComboBox* combo) combo->Append(_(L("World coordinates"))); combo->Append(_(L("Local coordinates"))); -// combo->SetSelection(0); -// combo->SetValue(combo->GetString(0)); wxBitmap empty_bmp(1, combo->GetFont().GetPixelSize().y + 2); empty_bmp.SetWidth(0); @@ -141,20 +139,10 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : ConfigOptionDef def; - // Objects(sub-objects) name -// def.label = L("Name"); -// def.gui_type = "legend"; -// def.tooltip = L("Object name"); -// def.width = 21 * wxGetApp().em_unit(); -// def.default_value = new ConfigOptionString{ " " }; -// m_og->append_single_option_line(Option(def, "object_name")); - Line line = Line{ "Name", "Object name" }; auto manifold_warning_icon = [this](wxWindow* parent) { m_fix_throught_netfab_bitmap = new wxStaticBitmap(parent, wxID_ANY, wxNullBitmap); -// auto sizer = new wxBoxSizer(wxHORIZONTAL); -// sizer->Add(m_fix_throught_netfab_bitmap); if (is_windows10()) m_fix_throught_netfab_bitmap->Bind(wxEVT_CONTEXT_MENU, [this](wxCommandEvent &e) @@ -167,11 +155,9 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : update_warning_icon_state(wxGetApp().obj_list()->get_mesh_errors_list()); }); -// return sizer; return m_fix_throught_netfab_bitmap; }; - // line.append_widget(manifold_warning_icon); line.near_label_widget = manifold_warning_icon; def.label = ""; def.gui_type = "legend"; diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index 5f1e779d6..bf5500cf4 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -460,6 +460,9 @@ void ObjectDataViewModelNode::init_container() #endif //__WXGTK__ } +#define LAYER_ROOT_ICON "edit_layers_all" +#define LAYER_ICON "edit_layers_some" + ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent, const ItemType type) : m_parent(parent), m_type(type), @@ -478,7 +481,7 @@ ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent } else if (type == itLayerRoot) { - m_bmp = create_scaled_bitmap(nullptr, "edit_layers_all"); // FIXME: pass window ptr + m_bmp = create_scaled_bitmap(nullptr, LAYER_ROOT_ICON); // FIXME: pass window ptr m_name = _(L("Layers")); } @@ -507,7 +510,7 @@ ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent } const std::string label_range = (boost::format(" %.2f-%.2f ") % layer_range.first % layer_range.second).str(); m_name = _(L("Range")) + label_range + "(" + _(L("mm")) + ")"; - m_bmp = create_scaled_bitmap(nullptr, "edit_layers_some"); // FIXME: pass window ptr + m_bmp = create_scaled_bitmap(nullptr, LAYER_ICON); // FIXME: pass window ptr set_action_icon(); init_container(); @@ -581,6 +584,9 @@ void ObjectDataViewModelNode::msw_rescale() if (!m_action_icon_name.empty()) m_action_icon = create_scaled_bitmap(nullptr, m_action_icon_name); + if (m_printable != piUndef) + m_printable_icon = create_scaled_bitmap(nullptr, m_printable == piPrintable ? "eye_open.png" : "eye_closed.png"); + if (!m_opt_categories.empty()) update_settings_digest_bitmaps(); } @@ -1766,11 +1772,22 @@ void ObjectDataViewModel::Rescale() ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID(); node->msw_rescale(); - if (node->m_type & itVolume) + switch (node->m_type) + { + case itObject: + if (node->m_bmp.IsOk()) node->m_bmp = *m_warning_bmp; + break; + case itVolume: node->m_bmp = GetVolumeIcon(node->m_volume_type, node->m_bmp.GetWidth() != node->m_bmp.GetHeight()); - - if (node->m_type & itObject && node->m_bmp.IsOk()) - node->m_bmp = *m_warning_bmp; + break; + case itLayerRoot: + node->m_bmp = create_scaled_bitmap(nullptr, LAYER_ROOT_ICON); // FIXME: pass window ptr + break; + case itLayer: + node->m_bmp = create_scaled_bitmap(nullptr, LAYER_ICON); // FIXME: pass window ptr + break; + default: break; + } ItemChanged(item); } From b6292247e88c7ace1a7c406c0d560e954a448373 Mon Sep 17 00:00:00 2001 From: Lukas Matena <lukasmatena@seznam.cz> Date: Tue, 17 Sep 2019 09:17:53 +0200 Subject: [PATCH 03/11] Unproject on mesh in the SLA gizmo is now performed by the MeshRaycaster class --- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 60 ++++--------- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp | 3 + src/slic3r/GUI/MeshUtils.cpp | 92 ++++++++++++++++++++ src/slic3r/GUI/MeshUtils.hpp | 24 +++++ 4 files changed, 137 insertions(+), 42 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index 80afb29b1..ee98ffc84 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -368,10 +368,14 @@ void GLGizmoSlaSupports::update_mesh() // If this is different mesh than last time or if the AABB tree is uninitialized, recalculate it. if (m_model_object_id != m_model_object->id() || (m_AABB.m_left == NULL && m_AABB.m_right == NULL)) { + //############################šš m_AABB.deinit(); m_AABB.init( MapMatrixXfUnaligned(m_its->vertices.front().data(), m_its->vertices.size(), 3), MapMatrixXiUnaligned(m_its->indices.front().data(), m_its->indices.size(), 3)); + //############################šš + + m_mesh_raycaster.reset(new MeshRaycaster(*m_mesh)); } m_model_object_id = m_model_object->id(); @@ -389,51 +393,22 @@ bool GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos, std::pair<Vec update_mesh(); const Camera& camera = m_parent.get_camera(); - const std::array<int, 4>& viewport = camera.get_viewport(); - const Transform3d& modelview_matrix = camera.get_view_matrix(); - const Transform3d& projection_matrix = camera.get_projection_matrix(); - - Vec3d point1; - Vec3d point2; - ::gluUnProject(mouse_pos(0), viewport[3] - mouse_pos(1), 0.f, modelview_matrix.data(), projection_matrix.data(), viewport.data(), &point1(0), &point1(1), &point1(2)); - ::gluUnProject(mouse_pos(0), viewport[3] - mouse_pos(1), 1.f, modelview_matrix.data(), projection_matrix.data(), viewport.data(), &point2(0), &point2(1), &point2(2)); - - std::vector<igl::Hit> hits; - const Selection& selection = m_parent.get_selection(); const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); + Geometry::Transformation trafo = volume->get_instance_transformation(); + trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., m_z_shift)); - point1(2) -= m_z_shift; - point2(2) -= m_z_shift; + // The raycaster query + std::vector<Vec3f> hits; + std::vector<Vec3f> normals; + m_mesh_raycaster->unproject_on_mesh(mouse_pos, trafo.get_matrix(), camera, &hits, &normals); - Transform3d inv = volume->get_instance_transformation().get_matrix().inverse(); - - point1 = inv * point1; - point2 = inv * point2; - - if (!m_AABB.intersect_ray( - MapMatrixXfUnaligned(m_its->vertices.front().data(), m_its->vertices.size(), 3), - MapMatrixXiUnaligned(m_its->indices.front().data(), m_its->indices.size(), 3), - point1.cast<float>(), (point2-point1).cast<float>(), hits)) - return false; // no intersection found - - std::sort(hits.begin(), hits.end(), [](const igl::Hit& a, const igl::Hit& b) { return a.t < b.t; }); - - // Now let's iterate through the points and find the first that is not clipped: - unsigned int i=0; - Vec3f bc; - Vec3f a; - Vec3f b; - Vec3f result; - for (i=0; i<hits.size(); ++i) { - igl::Hit& hit = hits[i]; - int fid = hit.id; // facet id - bc = Vec3f(1-hit.u-hit.v, hit.u, hit.v); // barycentric coordinates of the hit - a = (m_its->vertices[m_its->indices[fid](1)] - m_its->vertices[m_its->indices[fid](0)]); - b = (m_its->vertices[m_its->indices[fid](2)] - m_its->vertices[m_its->indices[fid](0)]); - result = bc(0) * m_its->vertices[m_its->indices[fid](0)] + bc(1) * m_its->vertices[m_its->indices[fid](1)] + bc(2)*m_its->vertices[m_its->indices[fid](2)]; - if (m_clipping_plane_distance == 0.f || !is_point_clipped(result.cast<double>())) - break; + // We must also take care of the clipping plane (if active) + unsigned i = 0; + if (m_clipping_plane_distance != 0.f) { + for (i=0; i<hits.size(); ++i) + if (! is_point_clipped(hits[i].cast<double>())) + break; } if (i==hits.size() || (hits.size()-i) % 2 != 0) { @@ -443,7 +418,7 @@ bool GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos, std::pair<Vec } // Calculate and return both the point and the facet normal. - pos_and_normal = std::make_pair(result, a.cross(b)); + pos_and_normal = std::make_pair(hits[i], normals[i]); return true; } @@ -1105,6 +1080,7 @@ void GLGizmoSlaSupports::on_set_state() m_its = nullptr; m_object_clipper.reset(); m_supports_clipper.reset(); + m_mesh_raycaster.reset(); } } m_old_state = m_state; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp index 7bef33e1b..8a55f65d1 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp @@ -20,6 +20,7 @@ namespace GUI { class ClippingPlane; class MeshClipper; +class MeshRaycaster; enum class SLAGizmoEventType : unsigned char; class GLGizmoSlaSupports : public GLGizmoBase @@ -38,6 +39,8 @@ private: typedef Eigen::Map<const Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor | Eigen::DontAlign>> MapMatrixXfUnaligned; typedef Eigen::Map<const Eigen::Matrix<int, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor | Eigen::DontAlign>> MapMatrixXiUnaligned; igl::AABB<MapMatrixXfUnaligned, 3> m_AABB; + + std::unique_ptr<MeshRaycaster> m_mesh_raycaster; const TriangleMesh* m_mesh; const indexed_triangle_set* m_its; mutable const TriangleMesh* m_supports_mesh; diff --git a/src/slic3r/GUI/MeshUtils.cpp b/src/slic3r/GUI/MeshUtils.cpp index 9542f0b1f..e6af61621 100644 --- a/src/slic3r/GUI/MeshUtils.cpp +++ b/src/slic3r/GUI/MeshUtils.cpp @@ -3,6 +3,15 @@ #include "libslic3r/Tesselate.hpp" #include "libslic3r/TriangleMesh.hpp" +#include "slic3r/GUI/Camera.hpp" + +// There is an L function in igl that would be overridden by our localization macro. +#undef L +#include <igl/AABB.h> + +#include <GL/glew.h> + + namespace Slic3r { namespace GUI { @@ -90,6 +99,89 @@ void MeshClipper::recalculate_triangles() } +class MeshRaycaster::AABBWrapper { +public: + AABBWrapper(const TriangleMesh* mesh); + ~AABBWrapper() { m_AABB.deinit(); } + + typedef Eigen::Map<const Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor | Eigen::DontAlign>> MapMatrixXfUnaligned; + typedef Eigen::Map<const Eigen::Matrix<int, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor | Eigen::DontAlign>> MapMatrixXiUnaligned; + igl::AABB<MapMatrixXfUnaligned, 3> m_AABB; + +}; + +MeshRaycaster::AABBWrapper::AABBWrapper(const TriangleMesh* mesh) +{ + const indexed_triangle_set* its = &mesh->its; + m_AABB.init( + MapMatrixXfUnaligned(its->vertices.front().data(), its->vertices.size(), 3), + MapMatrixXiUnaligned(its->indices.front().data(), its->indices.size(), 3)); +} + + +MeshRaycaster::MeshRaycaster(const TriangleMesh& mesh) + : m_AABB_wrapper(new AABBWrapper(&mesh)), m_mesh(&mesh) +{ +} + +MeshRaycaster::~MeshRaycaster() +{ + delete m_AABB_wrapper; +} + + +bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& trafo, + const Camera& camera, std::vector<Vec3f>* positions, std::vector<Vec3f>* normals) const +{ + const std::array<int, 4>& viewport = camera.get_viewport(); + const Transform3d& model_mat = camera.get_view_matrix(); + const Transform3d& proj_mat = camera.get_projection_matrix(); + + Vec3d pt1; + Vec3d pt2; + ::gluUnProject(mouse_pos(0), viewport[3] - mouse_pos(1), 0.f, model_mat.data(), proj_mat.data(), viewport.data(), &pt1(0), &pt1(1), &pt1(2)); + ::gluUnProject(mouse_pos(0), viewport[3] - mouse_pos(1), 1.f, model_mat.data(), proj_mat.data(), viewport.data(), &pt2(0), &pt2(1), &pt2(2)); + + std::vector<igl::Hit> hits; + + Transform3d inv = trafo.inverse(); + + pt1 = inv * pt1; + pt2 = inv * pt2; + + if (! m_AABB_wrapper->m_AABB.intersect_ray( + AABBWrapper::MapMatrixXfUnaligned(m_mesh->its.vertices.front().data(), m_mesh->its.vertices.size(), 3), + AABBWrapper::MapMatrixXiUnaligned(m_mesh->its.indices.front().data(), m_mesh->its.indices.size(), 3), + pt1.cast<float>(), (pt2-pt1).cast<float>(), hits)) + return false; // no intersection found + + std::sort(hits.begin(), hits.end(), [](const igl::Hit& a, const igl::Hit& b) { return a.t < b.t; }); + + // Now stuff the points in the provided vector and calculate normals if asked about them: + if (positions != nullptr) { + positions->clear(); + if (normals != nullptr) + normals->clear(); + Vec3f bc; + Vec3f a; + Vec3f b; + int fid = 0; + for (const igl::Hit& hit : hits) { + fid = hit.id; + bc = Vec3f(1-hit.u-hit.v, hit.u, hit.v); // barycentric coordinates of the hit + a = (m_mesh->its.vertices[m_mesh->its.indices[fid](1)] - m_mesh->its.vertices[m_mesh->its.indices[fid](0)]); + b = (m_mesh->its.vertices[m_mesh->its.indices[fid](2)] - m_mesh->its.vertices[m_mesh->its.indices[fid](0)]); + positions->push_back(bc(0) * m_mesh->its.vertices[m_mesh->its.indices[fid](0)] + bc(1) * m_mesh->its.vertices[m_mesh->its.indices[fid](1)] + bc(2) * m_mesh->its.vertices[m_mesh->its.indices[fid](2)]); + + if (normals != nullptr) + normals->push_back(a.cross(b)); + } + } + + return true; +} + + } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/MeshUtils.hpp b/src/slic3r/GUI/MeshUtils.hpp index f97003a91..cadc821dd 100644 --- a/src/slic3r/GUI/MeshUtils.hpp +++ b/src/slic3r/GUI/MeshUtils.hpp @@ -14,6 +14,8 @@ class TriangleMeshSlicer; namespace GUI { +class Camera; + class ClippingPlane @@ -86,6 +88,28 @@ private: }; + + +class MeshRaycaster { +public: + MeshRaycaster(const TriangleMesh& mesh); + ~MeshRaycaster(); + void set_transformation(const Geometry::Transformation& trafo); + void set_camera(const Camera& camera); + + bool unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera, + std::vector<Vec3f>* positions = nullptr, std::vector<Vec3f>* normals = nullptr) const; + +private: + // PIMPL wrapper around igl::AABB so I don't have to include the header-only IGL here + class AABBWrapper; + AABBWrapper* m_AABB_wrapper; + + const TriangleMesh* m_mesh = nullptr; + + +}; + } // namespace GUI } // namespace Slic3r From 3694bf3da97fbbcbabe0ec15607eda8236a8ca39 Mon Sep 17 00:00:00 2001 From: Lukas Matena <lukasmatena@seznam.cz> Date: Tue, 17 Sep 2019 10:47:01 +0200 Subject: [PATCH 04/11] Added functions get_hit_pos, get_hit_normal, ready to implement intersect_ray --- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 2 +- src/slic3r/GUI/MeshUtils.cpp | 52 ++++++++++++++------ src/slic3r/GUI/MeshUtils.hpp | 6 +-- 3 files changed, 41 insertions(+), 19 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index ee98ffc84..04ad8a460 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -503,7 +503,7 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous // clipping plane nor obscured by the mesh. for (const unsigned int i : selected_idxs) { const sla::SupportPoint &support_point = m_editing_cache[i].support_point; - if (!is_point_clipped(support_point.pos.cast<double>())) { + if (! is_point_clipped(support_point.pos.cast<double>())) { bool is_obscured = false; // Cast a ray in the direction of the camera and look for intersection with the mesh: std::vector<igl::Hit> hits; diff --git a/src/slic3r/GUI/MeshUtils.cpp b/src/slic3r/GUI/MeshUtils.cpp index e6af61621..26697acc5 100644 --- a/src/slic3r/GUI/MeshUtils.cpp +++ b/src/slic3r/GUI/MeshUtils.cpp @@ -108,14 +108,19 @@ public: typedef Eigen::Map<const Eigen::Matrix<int, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor | Eigen::DontAlign>> MapMatrixXiUnaligned; igl::AABB<MapMatrixXfUnaligned, 3> m_AABB; + Vec3f get_hit_pos(const igl::Hit& hit) const; + Vec3f get_hit_normal(const igl::Hit& hit) const; + +private: + const TriangleMesh* m_mesh; }; MeshRaycaster::AABBWrapper::AABBWrapper(const TriangleMesh* mesh) + : m_mesh(mesh) { - const indexed_triangle_set* its = &mesh->its; m_AABB.init( - MapMatrixXfUnaligned(its->vertices.front().data(), its->vertices.size(), 3), - MapMatrixXiUnaligned(its->indices.front().data(), its->indices.size(), 3)); + MapMatrixXfUnaligned(m_mesh->its.vertices.front().data(), m_mesh->its.vertices.size(), 3), + MapMatrixXiUnaligned(m_mesh->its.indices.front().data(), m_mesh->its.indices.size(), 3)); } @@ -129,6 +134,23 @@ MeshRaycaster::~MeshRaycaster() delete m_AABB_wrapper; } +Vec3f MeshRaycaster::AABBWrapper::get_hit_pos(const igl::Hit& hit) const +{ + const stl_triangle_vertex_indices& indices = m_mesh->its.indices[hit.id]; + return Vec3f((1-hit.u-hit.v) * m_mesh->its.vertices[indices(0)] + + hit.u * m_mesh->its.vertices[indices(1)] + + hit.v * m_mesh->its.vertices[indices(2)]); +} + + +Vec3f MeshRaycaster::AABBWrapper::get_hit_normal(const igl::Hit& hit) const +{ + const stl_triangle_vertex_indices& indices = m_mesh->its.indices[hit.id]; + Vec3f a(m_mesh->its.vertices[indices(1)] - m_mesh->its.vertices[indices(0)]); + Vec3f b(m_mesh->its.vertices[indices(2)] - m_mesh->its.vertices[indices(0)]); + return Vec3f(a.cross(b)); +} + bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera, std::vector<Vec3f>* positions, std::vector<Vec3f>* normals) const @@ -139,8 +161,8 @@ bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& Vec3d pt1; Vec3d pt2; - ::gluUnProject(mouse_pos(0), viewport[3] - mouse_pos(1), 0.f, model_mat.data(), proj_mat.data(), viewport.data(), &pt1(0), &pt1(1), &pt1(2)); - ::gluUnProject(mouse_pos(0), viewport[3] - mouse_pos(1), 1.f, model_mat.data(), proj_mat.data(), viewport.data(), &pt2(0), &pt2(1), &pt2(2)); + ::gluUnProject(mouse_pos(0), viewport[3] - mouse_pos(1), 0., model_mat.data(), proj_mat.data(), viewport.data(), &pt1(0), &pt1(1), &pt1(2)); + ::gluUnProject(mouse_pos(0), viewport[3] - mouse_pos(1), 1., model_mat.data(), proj_mat.data(), viewport.data(), &pt2(0), &pt2(1), &pt2(2)); std::vector<igl::Hit> hits; @@ -162,19 +184,11 @@ bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& positions->clear(); if (normals != nullptr) normals->clear(); - Vec3f bc; - Vec3f a; - Vec3f b; - int fid = 0; for (const igl::Hit& hit : hits) { - fid = hit.id; - bc = Vec3f(1-hit.u-hit.v, hit.u, hit.v); // barycentric coordinates of the hit - a = (m_mesh->its.vertices[m_mesh->its.indices[fid](1)] - m_mesh->its.vertices[m_mesh->its.indices[fid](0)]); - b = (m_mesh->its.vertices[m_mesh->its.indices[fid](2)] - m_mesh->its.vertices[m_mesh->its.indices[fid](0)]); - positions->push_back(bc(0) * m_mesh->its.vertices[m_mesh->its.indices[fid](0)] + bc(1) * m_mesh->its.vertices[m_mesh->its.indices[fid](1)] + bc(2) * m_mesh->its.vertices[m_mesh->its.indices[fid](2)]); + positions->push_back(m_AABB_wrapper->get_hit_pos(hit)); if (normals != nullptr) - normals->push_back(a.cross(b)); + normals->push_back(m_AABB_wrapper->get_hit_normal(hit)); } } @@ -182,6 +196,14 @@ bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& } +std::vector<size_t> MeshRaycaster::get_unobscured_idxs(const Transform3d& trafo, const Camera& camera, const std::vector<Vec3f>& points) const +{ + + + return std::vector<size_t>(); +} + + } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/MeshUtils.hpp b/src/slic3r/GUI/MeshUtils.hpp index cadc821dd..5c11053ab 100644 --- a/src/slic3r/GUI/MeshUtils.hpp +++ b/src/slic3r/GUI/MeshUtils.hpp @@ -100,14 +100,14 @@ public: bool unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera, std::vector<Vec3f>* positions = nullptr, std::vector<Vec3f>* normals = nullptr) const; + std::vector<size_t> get_unobscured_idxs(const Transform3d& trafo, const Camera& camera, + const std::vector<Vec3f>& points) const; + private: // PIMPL wrapper around igl::AABB so I don't have to include the header-only IGL here class AABBWrapper; AABBWrapper* m_AABB_wrapper; - const TriangleMesh* m_mesh = nullptr; - - }; From 1dfd8a0e621fc5ea3731d0fd407ba121f550ebf7 Mon Sep 17 00:00:00 2001 From: Lukas Matena <lukasmatena@seznam.cz> Date: Tue, 17 Sep 2019 14:14:26 +0200 Subject: [PATCH 05/11] MeshRaycaster class is now used in SLA gizmo when selecting by rectangle --- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 84 +++++--------------- src/slic3r/GUI/MeshUtils.cpp | 45 ++++++++++- src/slic3r/GUI/MeshUtils.hpp | 4 +- 3 files changed, 63 insertions(+), 70 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index 04ad8a460..f15bc806b 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -479,76 +479,28 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous GLSelectionRectangle::EState rectangle_status = m_selection_rectangle.get_state(); // First collect positions of all the points in world coordinates. - const Transform3d& instance_matrix = m_model_object->instances[m_active_instance]->get_transformation().get_matrix(); + Geometry::Transformation trafo = m_model_object->instances[m_active_instance]->get_transformation(); + trafo.set_offset(trafo.get_offset() + Vec3d(0., 0., m_z_shift)); std::vector<Vec3d> points; - for (unsigned int i=0; i<m_editing_cache.size(); ++i) { - const sla::SupportPoint &support_point = m_editing_cache[i].support_point; - points.push_back(instance_matrix * support_point.pos.cast<double>()); - points.back()(2) += m_z_shift; - } + for (unsigned int i=0; i<m_editing_cache.size(); ++i) + points.push_back(trafo.get_matrix() * m_editing_cache[i].support_point.pos.cast<double>()); + // Now ask the rectangle which of the points are inside. - const Camera& camera = m_parent.get_camera(); - std::vector<unsigned int> selected_idxs = m_selection_rectangle.stop_dragging(m_parent, points); + std::vector<Vec3f> points_inside; + std::vector<unsigned int> points_idxs = m_selection_rectangle.stop_dragging(m_parent, points); + for (size_t idx : points_idxs) + points_inside.push_back((trafo.get_matrix() * points[idx]).cast<float>()); - // we'll recover current look direction (in world coords) and transform it to model coords. - const Selection& selection = m_parent.get_selection(); - const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); - const Transform3d& instance_matrix_no_translation_no_scaling = volume->get_instance_transformation().get_matrix(true,false,true); - Vec3f direction_to_camera = -camera.get_dir_forward().cast<float>(); - Vec3f direction_to_camera_mesh = (instance_matrix_no_translation_no_scaling.inverse().cast<float>() * direction_to_camera).normalized().eval(); - Vec3f scaling = volume->get_instance_scaling_factor().cast<float>(); - direction_to_camera_mesh = Vec3f(direction_to_camera_mesh(0)*scaling(0), direction_to_camera_mesh(1)*scaling(1), direction_to_camera_mesh(2)*scaling(2)); - - // Iterate over all points in the rectangle and check that they are neither clipped by the - // clipping plane nor obscured by the mesh. - for (const unsigned int i : selected_idxs) { - const sla::SupportPoint &support_point = m_editing_cache[i].support_point; + // Only select/deselect points that are actually visible + for (size_t idx : m_mesh_raycaster->get_unobscured_idxs(trafo, m_parent.get_camera(), points_inside, + [this](const Vec3f& pt) { return is_point_clipped(pt.cast<double>()); })) + { + const sla::SupportPoint &support_point = m_editing_cache[points_idxs[idx]].support_point; if (! is_point_clipped(support_point.pos.cast<double>())) { - bool is_obscured = false; - // Cast a ray in the direction of the camera and look for intersection with the mesh: - std::vector<igl::Hit> hits; - // Offset the start of the ray to the front of the ball + EPSILON to account for numerical inaccuracies. - if (m_AABB.intersect_ray( - MapMatrixXfUnaligned(m_its->vertices.front().data(), m_its->vertices.size(), 3), - MapMatrixXiUnaligned(m_its->indices.front().data(), m_its->indices.size(), 3), - support_point.pos + direction_to_camera_mesh * (support_point.head_front_radius + EPSILON), direction_to_camera_mesh, hits)) { - std::sort(hits.begin(), hits.end(), [](const igl::Hit& h1, const igl::Hit& h2) { return h1.t < h2.t; }); - - if (m_clipping_plane_distance != 0.f) { - // If the closest hit facet normal points in the same direction as the ray, - // we are looking through the mesh and should therefore discard the point: - int fid = hits.front().id; // facet id - Vec3f a = (m_its->vertices[m_its->indices[fid](1)] - m_its->vertices[m_its->indices[fid](0)]); - Vec3f b = (m_its->vertices[m_its->indices[fid](2)] - m_its->vertices[m_its->indices[fid](0)]); - if ((a.cross(b)).dot(direction_to_camera_mesh) > 0.f) - is_obscured = true; - - // Eradicate all hits that are on clipped surfaces: - for (unsigned int j=0; j<hits.size(); ++j) { - const igl::Hit& hit = hits[j]; - int fid = hit.id; // facet id - - Vec3f bc = Vec3f(1-hit.u-hit.v, hit.u, hit.v); // barycentric coordinates of the hit - Vec3f hit_pos = bc(0) * m_its->vertices[m_its->indices[fid](0)] + bc(1) * m_its->vertices[m_its->indices[fid](1)] + bc(2)*m_its->vertices[m_its->indices[fid](2)]; - if (is_point_clipped(hit_pos.cast<double>())) { - hits.erase(hits.begin()+j); - --j; - } - } - } - - // FIXME: the intersection could in theory be behind the camera, but as of now we only have camera direction. - // Also, the threshold is in mesh coordinates, not in actual dimensions. - if (!hits.empty()) - is_obscured = true; - } - - if (!is_obscured) { - if (rectangle_status == GLSelectionRectangle::Deselect) - unselect_point(i); - else - select_point(i); - } + if (rectangle_status == GLSelectionRectangle::Deselect) + unselect_point(points_idxs[idx]); + else + select_point(points_idxs[idx]); } } return true; diff --git a/src/slic3r/GUI/MeshUtils.cpp b/src/slic3r/GUI/MeshUtils.cpp index 26697acc5..2c0089053 100644 --- a/src/slic3r/GUI/MeshUtils.cpp +++ b/src/slic3r/GUI/MeshUtils.cpp @@ -196,11 +196,52 @@ bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& } -std::vector<size_t> MeshRaycaster::get_unobscured_idxs(const Transform3d& trafo, const Camera& camera, const std::vector<Vec3f>& points) const +std::vector<unsigned> MeshRaycaster::get_unobscured_idxs(const Geometry::Transformation& trafo, const Camera& camera, const std::vector<Vec3f>& points, + std::function<bool(const Vec3f&)> fn_ignore_hit) const { + std::vector<unsigned> out; + const Transform3d& instance_matrix_no_translation_no_scaling = trafo.get_matrix(true,false,true); + Vec3f direction_to_camera = -camera.get_dir_forward().cast<float>(); + Vec3f direction_to_camera_mesh = (instance_matrix_no_translation_no_scaling.inverse().cast<float>() * direction_to_camera).normalized().eval(); + Vec3f scaling = trafo.get_scaling_factor().cast<float>(); + direction_to_camera_mesh = Vec3f(direction_to_camera_mesh(0)*scaling(0), direction_to_camera_mesh(1)*scaling(1), direction_to_camera_mesh(2)*scaling(2)); - return std::vector<size_t>(); + for (size_t i=0; i<points.size(); ++i) { + const Vec3f& pt = points[i]; + bool is_obscured = false; + // Cast a ray in the direction of the camera and look for intersection with the mesh: + std::vector<igl::Hit> hits; + // Offset the start of the ray to the front of the ball + EPSILON to account for numerical inaccuracies. + if (m_AABB_wrapper->m_AABB.intersect_ray( + AABBWrapper::MapMatrixXfUnaligned(m_mesh->its.vertices.front().data(), m_mesh->its.vertices.size(), 3), + AABBWrapper::MapMatrixXiUnaligned(m_mesh->its.indices.front().data(), m_mesh->its.indices.size(), 3), + pt + direction_to_camera_mesh * EPSILON, direction_to_camera_mesh, hits)) { + + std::sort(hits.begin(), hits.end(), [](const igl::Hit& h1, const igl::Hit& h2) { return h1.t < h2.t; }); + // If the closest hit facet normal points in the same direction as the ray, + // we are looking through the mesh and should therefore discard the point: + if (m_AABB_wrapper->get_hit_normal(hits.front()).dot(direction_to_camera_mesh) > 0.f) + is_obscured = true; + + // Eradicate all hits that the caller wants to ignore + for (unsigned j=0; j<hits.size(); ++j) { + const igl::Hit& hit = hits[j]; + if (fn_ignore_hit(m_AABB_wrapper->get_hit_pos(hit))) { + hits.erase(hits.begin()+j); + --j; + } + } + // FIXME: the intersection could in theory be behind the camera, but as of now we only have camera direction. + // Also, the threshold is in mesh coordinates, not in actual dimensions. + if (! hits.empty()) + is_obscured = true; + } + if (! is_obscured) + out.push_back(i); + } + + return out; } diff --git a/src/slic3r/GUI/MeshUtils.hpp b/src/slic3r/GUI/MeshUtils.hpp index 5c11053ab..2573b4b89 100644 --- a/src/slic3r/GUI/MeshUtils.hpp +++ b/src/slic3r/GUI/MeshUtils.hpp @@ -100,8 +100,8 @@ public: bool unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d& trafo, const Camera& camera, std::vector<Vec3f>* positions = nullptr, std::vector<Vec3f>* normals = nullptr) const; - std::vector<size_t> get_unobscured_idxs(const Transform3d& trafo, const Camera& camera, - const std::vector<Vec3f>& points) const; + std::vector<unsigned> get_unobscured_idxs(const Geometry::Transformation& trafo, const Camera& camera, + const std::vector<Vec3f>& points, std::function<bool(const Vec3f&)> fn_ignore_hit) const; private: // PIMPL wrapper around igl::AABB so I don't have to include the header-only IGL here From 6bcafd7c830ddfe5e8a6974f455d26279b0f0603 Mon Sep 17 00:00:00 2001 From: Lukas Matena <lukasmatena@seznam.cz> Date: Tue, 17 Sep 2019 14:56:46 +0200 Subject: [PATCH 06/11] SLA gizmo no more uses IGL code directly, all was moved to the new MeshRaycaster class --- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 36 +++----------------- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp | 7 ---- src/slic3r/GUI/MeshUtils.cpp | 18 +++++++++- src/slic3r/GUI/MeshUtils.hpp | 2 ++ 4 files changed, 24 insertions(+), 39 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index f15bc806b..992f4912a 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -296,8 +296,9 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking) // Matrices set, we can render the point mark now. // If in editing mode, we'll also render a cone pointing to the sphere. if (m_editing_mode) { + // in case the normal is not yet cached, find and cache it if (m_editing_cache[i].normal == Vec3f::Zero()) - update_cache_entry_normal(i); // in case the normal is not yet cached, find and cache it + m_mesh_raycaster->get_closest_point(m_editing_cache[i].support_point.pos, &m_editing_cache[i].normal); Eigen::Quaterniond q; q.setFromTwoVectors(Vec3d{0., 0., 1.}, instance_scaling_matrix_inverse * m_editing_cache[i].normal.cast<double>()); @@ -366,17 +367,8 @@ void GLGizmoSlaSupports::update_mesh() m_its = &m_mesh->its; // If this is different mesh than last time or if the AABB tree is uninitialized, recalculate it. - if (m_model_object_id != m_model_object->id() || (m_AABB.m_left == NULL && m_AABB.m_right == NULL)) - { - //############################šš - m_AABB.deinit(); - m_AABB.init( - MapMatrixXfUnaligned(m_its->vertices.front().data(), m_its->vertices.size(), 3), - MapMatrixXiUnaligned(m_its->indices.front().data(), m_its->indices.size(), 3)); - //############################šš - + if (m_model_object_id != m_model_object->id() || ! m_mesh_raycaster) m_mesh_raycaster.reset(new MeshRaycaster(*m_mesh)); - } m_model_object_id = m_model_object->id(); disable_editing_mode(); @@ -389,7 +381,7 @@ void GLGizmoSlaSupports::update_mesh() bool GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos, std::pair<Vec3f, Vec3f>& pos_and_normal) { // if the gizmo doesn't have the V, F structures for igl, calculate them first: - if (m_its == nullptr) + if (! m_mesh_raycaster) update_mesh(); const Camera& camera = m_parent.get_camera(); @@ -658,23 +650,6 @@ std::vector<const ConfigOption*> GLGizmoSlaSupports::get_config_options(const st } -void GLGizmoSlaSupports::update_cache_entry_normal(size_t i) const -{ - int idx = 0; - Eigen::Matrix<float, 1, 3> pp = m_editing_cache[i].support_point.pos; - Eigen::Matrix<float, 1, 3> cc; - m_AABB.squared_distance( - MapMatrixXfUnaligned(m_its->vertices.front().data(), m_its->vertices.size(), 3), - MapMatrixXiUnaligned(m_its->indices.front().data(), m_its->indices.size(), 3), - pp, idx, cc); - Vec3f a = (m_its->vertices[m_its->indices[idx](1)] - m_its->vertices[m_its->indices[idx](0)]); - Vec3f b = (m_its->vertices[m_its->indices[idx](2)] - m_its->vertices[m_its->indices[idx](0)]); - m_editing_cache[i].normal = a.cross(b); -} - - - - ClippingPlane GLGizmoSlaSupports::get_sla_clipping_plane() const { if (!m_model_object || m_state == Off || m_clipping_plane_distance == 0.f) @@ -1027,8 +1002,7 @@ void GLGizmoSlaSupports::on_set_state() m_parent.toggle_model_objects_visibility(true); m_normal_cache.clear(); m_clipping_plane_distance = 0.f; - // Release triangle mesh slicer and the AABB spatial search structure. - m_AABB.deinit(); + // Release clippers and the AABB raycaster. m_its = nullptr; m_object_clipper.reset(); m_supports_clipper.reset(); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp index 8a55f65d1..cf5245f19 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp @@ -4,11 +4,6 @@ #include "GLGizmoBase.hpp" #include "slic3r/GUI/GLSelectionRectangle.hpp" -// There is an L function in igl that would be overridden by our localization macro - let's undefine it... -#undef L -#include <igl/AABB.h> -#include "slic3r/GUI/I18N.hpp" // ...and redefine again when we are done with the igl code - #include "libslic3r/SLA/SLACommon.hpp" #include <wx/dialog.h> @@ -38,7 +33,6 @@ private: GLUquadricObj* m_quadric; typedef Eigen::Map<const Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor | Eigen::DontAlign>> MapMatrixXfUnaligned; typedef Eigen::Map<const Eigen::Matrix<int, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor | Eigen::DontAlign>> MapMatrixXiUnaligned; - igl::AABB<MapMatrixXfUnaligned, 3> m_AABB; std::unique_ptr<MeshRaycaster> m_mesh_raycaster; const TriangleMesh* m_mesh; @@ -101,7 +95,6 @@ private: void render_clipping_plane(const Selection& selection) const; bool is_mesh_update_necessary() const; void update_mesh(); - void update_cache_entry_normal(size_t i) const; bool unsaved_changes() const; bool m_lock_unique_islands = false; diff --git a/src/slic3r/GUI/MeshUtils.cpp b/src/slic3r/GUI/MeshUtils.cpp index 2c0089053..e559020e9 100644 --- a/src/slic3r/GUI/MeshUtils.cpp +++ b/src/slic3r/GUI/MeshUtils.cpp @@ -240,11 +240,27 @@ std::vector<unsigned> MeshRaycaster::get_unobscured_idxs(const Geometry::Transfo if (! is_obscured) out.push_back(i); } - return out; } +Vec3f MeshRaycaster::get_closest_point(const Vec3f& point, Vec3f* normal) const +{ + int idx = 0; + Eigen::Matrix<float, 1, 3> closest_point; + m_AABB_wrapper->m_AABB.squared_distance( + AABBWrapper::MapMatrixXfUnaligned(m_mesh->its.vertices.front().data(), m_mesh->its.vertices.size(), 3), + AABBWrapper::MapMatrixXiUnaligned(m_mesh->its.indices.front().data(), m_mesh->its.indices.size(), 3), + point, idx, closest_point); + if (normal) { + igl::Hit imag_hit; + imag_hit.id = idx; + *normal = m_AABB_wrapper->get_hit_normal(imag_hit); + } + return closest_point; +} + + } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/MeshUtils.hpp b/src/slic3r/GUI/MeshUtils.hpp index 2573b4b89..21c375e81 100644 --- a/src/slic3r/GUI/MeshUtils.hpp +++ b/src/slic3r/GUI/MeshUtils.hpp @@ -103,6 +103,8 @@ public: std::vector<unsigned> get_unobscured_idxs(const Geometry::Transformation& trafo, const Camera& camera, const std::vector<Vec3f>& points, std::function<bool(const Vec3f&)> fn_ignore_hit) const; + Vec3f get_closest_point(const Vec3f& point, Vec3f* normal = nullptr) const; + private: // PIMPL wrapper around igl::AABB so I don't have to include the header-only IGL here class AABBWrapper; From f4910cafed7d1cc28c7db0eb952dced90c66a9de Mon Sep 17 00:00:00 2001 From: Enrico Turri <enricoturri@seznam.cz> Date: Tue, 17 Sep 2019 15:30:54 +0200 Subject: [PATCH 07/11] Fixed selection after adding a modifier by loading it from file --- src/slic3r/GUI/GUI_ObjectList.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 51098647f..49f0f6fa2 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -1667,6 +1667,10 @@ void ObjectList::load_subobject(ModelVolumeType type) if (sel_item) select_item(sel_item); + +#ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME + selection_changed(); +#endif //no __WXOSX__ //__WXMSW__ } void ObjectList::load_part( ModelObject* model_object, From cd7895065afc839a09cc430130960b6941f6020a Mon Sep 17 00:00:00 2001 From: Enrico Turri <enricoturri@seznam.cz> Date: Tue, 17 Sep 2019 15:48:39 +0200 Subject: [PATCH 08/11] Fixed typo --- src/slic3r/GUI/MeshUtils.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/MeshUtils.hpp b/src/slic3r/GUI/MeshUtils.hpp index 21c375e81..a2be2677b 100644 --- a/src/slic3r/GUI/MeshUtils.hpp +++ b/src/slic3r/GUI/MeshUtils.hpp @@ -14,7 +14,7 @@ class TriangleMeshSlicer; namespace GUI { -class Camera; +struct Camera; From 741e98804cf2a32172cc7989d53202c99c76feb1 Mon Sep 17 00:00:00 2001 From: Lukas Matena <lukasmatena@seznam.cz> Date: Wed, 18 Sep 2019 11:47:19 +0200 Subject: [PATCH 09/11] Purging volumes dialog now uses filament colour in case extruder color is undefined --- src/slic3r/GUI/Plater.cpp | 11 ++++++++++- src/slic3r/GUI/Plater.hpp | 1 + 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index c5aad48a9..e548ed3ba 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -522,7 +522,11 @@ FreqChangedParams::FreqChangedParams(wxWindow* parent) : const std::vector<double> &init_extruders = (project_config.option<ConfigOptionFloats>("wiping_volumes_extruders"))->values; const DynamicPrintConfig* config = &wxGetApp().preset_bundle->printers.get_edited_preset().config; - const std::vector<std::string> &extruder_colours = (config->option<ConfigOptionStrings>("extruder_colour"))->values; + std::vector<std::string> extruder_colours = (config->option<ConfigOptionStrings>("extruder_colour"))->values; + const std::vector<std::string>& filament_colours = (wxGetApp().plater()->get_plater_config()->option<ConfigOptionStrings>("filament_colour"))->values; + for (size_t i=0; i<extruder_colours.size(); ++i) + if (extruder_colours[i] == "") + extruder_colours[i] = filament_colours[i]; WipingDialog dlg(parent, cast<float>(init_matrix), cast<float>(init_extruders), extruder_colours); @@ -4838,6 +4842,11 @@ void Plater::on_activate() this->p->show_delayed_error_message(); } +const DynamicPrintConfig* Plater::get_plater_config() const +{ + return p->config; +} + wxString Plater::get_project_filename(const wxString& extension) const { return p->get_project_filename(extension); diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 6b488fef1..0dc298566 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -213,6 +213,7 @@ public: void on_config_change(const DynamicPrintConfig &config); // On activating the parent window. void on_activate(); + const DynamicPrintConfig* get_plater_config() const; void update_object_menu(); From 76a657ce5217ffb92cfa1b68e2080575186e3244 Mon Sep 17 00:00:00 2001 From: Lukas Matena <lukasmatena@seznam.cz> Date: Wed, 18 Sep 2019 12:54:21 +0200 Subject: [PATCH 10/11] Plater.cpp - better added a range-check when selecting filament color in purging volumes dialog --- src/slic3r/GUI/Plater.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index e548ed3ba..0dc7519e8 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -525,7 +525,7 @@ FreqChangedParams::FreqChangedParams(wxWindow* parent) : std::vector<std::string> extruder_colours = (config->option<ConfigOptionStrings>("extruder_colour"))->values; const std::vector<std::string>& filament_colours = (wxGetApp().plater()->get_plater_config()->option<ConfigOptionStrings>("filament_colour"))->values; for (size_t i=0; i<extruder_colours.size(); ++i) - if (extruder_colours[i] == "") + if (extruder_colours[i] == "" && i < filament_colours.size()) extruder_colours[i] = filament_colours[i]; WipingDialog dlg(parent, cast<float>(init_matrix), cast<float>(init_extruders), extruder_colours); From 94212fa2a92b5d01be5da8235f02423249dd7b2a Mon Sep 17 00:00:00 2001 From: bubnikv <bubnikv@gmail.com> Date: Thu, 19 Sep 2019 08:56:47 +0200 Subject: [PATCH 11/11] Another fix of admesh on big endian architectures, fixes #2879 --- src/admesh/stl_io.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/admesh/stl_io.cpp b/src/admesh/stl_io.cpp index af9bb4f98..ddf377c78 100644 --- a/src/admesh/stl_io.cpp +++ b/src/admesh/stl_io.cpp @@ -151,8 +151,8 @@ bool stl_write_binary(stl_file *stl, const char *file, const char *label) memcpy(buffer, &stl->stats.number_of_facets, 4); stl_internal_reverse_quads(buffer, 4); fwrite(buffer, 4, 1, fp); - for (size_t i = 0; i < stl->stats.number_of_facets; ++ i) { - memcpy(buffer, stl->facet_start + i, 50); + for (const stl_facet &facet : stl->facet_start) { + memcpy(buffer, &facet, 50); // Convert to little endian. stl_internal_reverse_quads(buffer, 48); fwrite(buffer, SIZEOF_STL_FACET, 1, fp);