From 3c39e1a618f3cfcc0a1b37d0f0f5492ef9ab1ea4 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Wed, 27 Feb 2019 10:46:52 +0100 Subject: [PATCH 01/13] Attempt to fix rendering of printbed svg textures on Mac --- src/slic3r/GUI/3DBed.cpp | 10 ++++++++-- src/slic3r/GUI/GLTexture.cpp | 23 +++++++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index d6d25b550b..b67bf9eafa 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -556,8 +556,10 @@ void Bed3D::render_prusa(const std::string &key, bool bottom) const ::glGenBuffers(1, &m_vbo_id); ::glBindBuffer(GL_ARRAY_BUFFER, m_vbo_id); ::glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)m_triangles.get_vertices_data_size(), (const GLvoid*)m_triangles.get_vertices_data(), GL_STATIC_DRAW); - ::glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, m_triangles.get_vertex_data_size(), (GLvoid*)m_triangles.get_position_offset()); - ::glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, m_triangles.get_vertex_data_size(), (GLvoid*)m_triangles.get_tex_coords_offset()); +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +// ::glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, m_triangles.get_vertex_data_size(), (GLvoid*)m_triangles.get_position_offset()); +// ::glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, m_triangles.get_vertex_data_size(), (GLvoid*)m_triangles.get_tex_coords_offset()); +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ::glBindBuffer(GL_ARRAY_BUFFER, 0); } @@ -597,6 +599,10 @@ void Bed3D::render_prusa_shader(unsigned int vertices_count, bool transparent) c ::glBindTexture(GL_TEXTURE_2D, (GLuint)m_texture.get_id()); ::glBindBuffer(GL_ARRAY_BUFFER, m_vbo_id); +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + ::glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, m_triangles.get_vertex_data_size(), (GLvoid*)m_triangles.get_position_offset()); + ::glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, m_triangles.get_vertex_data_size(), (GLvoid*)m_triangles.get_tex_coords_offset()); +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ ::glEnableVertexAttribArray(0); ::glEnableVertexAttribArray(1); ::glDrawArrays(GL_TRIANGLES, 0, (GLsizei)vertices_count); diff --git a/src/slic3r/GUI/GLTexture.cpp b/src/slic3r/GUI/GLTexture.cpp index e7e20b27e7..436a37e1cc 100644 --- a/src/slic3r/GUI/GLTexture.cpp +++ b/src/slic3r/GUI/GLTexture.cpp @@ -20,6 +20,8 @@ #include "nanosvg/nanosvgrast.h" #endif // ENABLE_TEXTURES_FROM_SVG +#include "libslic3r/Utils.hpp" + namespace Slic3r { namespace GUI { @@ -357,6 +359,27 @@ bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, uns nsvgDeleteRasterizer(rast); nsvgDelete(image); +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#if 1 + // debug output + wxImage output(m_width, m_height); + output.InitAlpha(); + + for (int h = 0; h < m_height; ++h) + { + int px_h = h * m_width; + for (int w = 0; w < m_width; ++w) + { + int offset = (px_h + w) * 4; + output.SetRGB(w, h, data.data()[offset + 0], data.data()[offset + 1], data.data()[offset + 2]); + output.SetAlpha(w, h, data.data()[offset + 3]); + } + } + + output.SaveFile(resources_dir() + "/icons/test_svg_import.png", wxBITMAP_TYPE_PNG); +#endif // 0 +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + return true; } #endif // ENABLE_TEXTURES_FROM_SVG From 68805fc63a07c709f0ce59c7fac0c3cecefa2ed7 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Wed, 27 Feb 2019 15:19:03 +0100 Subject: [PATCH 02/13] Small refactoring in Bed3D and GLShader --- src/slic3r/GUI/3DBed.cpp | 79 +++++++++++++++++------------------- src/slic3r/GUI/3DBed.hpp | 2 +- src/slic3r/GUI/GLShader.cpp | 13 +++++- src/slic3r/GUI/GLShader.hpp | 1 + src/slic3r/GUI/GLTexture.cpp | 21 ---------- 5 files changed, 51 insertions(+), 65 deletions(-) diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index b67bf9eafa..f271f9738e 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -516,9 +516,9 @@ void Bed3D::render_prusa(const std::string &key, bool bottom) const if (max_anisotropy > 0.0f) { - ::glBindTexture(GL_TEXTURE_2D, m_texture.get_id()); - ::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropy); - ::glBindTexture(GL_TEXTURE_2D, 0); + glsafe(::glBindTexture(GL_TEXTURE_2D, m_texture.get_id())); + glsafe(::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropy)); + glsafe(::glBindTexture(GL_TEXTURE_2D, 0)); } } @@ -542,9 +542,9 @@ void Bed3D::render_prusa(const std::string &key, bool bottom) const if (!m_model.get_filename().empty()) { - ::glEnable(GL_LIGHTING); + glsafe(::glEnable(GL_LIGHTING)); m_model.render(); - ::glDisable(GL_LIGHTING); + glsafe(::glDisable(GL_LIGHTING)); } } @@ -553,41 +553,40 @@ void Bed3D::render_prusa(const std::string &key, bool bottom) const { if (m_vbo_id == 0) { - ::glGenBuffers(1, &m_vbo_id); - ::glBindBuffer(GL_ARRAY_BUFFER, m_vbo_id); - ::glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)m_triangles.get_vertices_data_size(), (const GLvoid*)m_triangles.get_vertices_data(), GL_STATIC_DRAW); -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ -// ::glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, m_triangles.get_vertex_data_size(), (GLvoid*)m_triangles.get_position_offset()); -// ::glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, m_triangles.get_vertex_data_size(), (GLvoid*)m_triangles.get_tex_coords_offset()); -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ - ::glBindBuffer(GL_ARRAY_BUFFER, 0); + unsigned int stride = m_triangles.get_vertex_data_size(); + glsafe(::glGenBuffers(1, &m_vbo_id)); + glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_vbo_id)); + glsafe(::glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)m_triangles.get_vertices_data_size(), (const GLvoid*)m_triangles.get_vertices_data(), GL_STATIC_DRAW)); + glsafe(::glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, stride, (GLvoid*)m_triangles.get_position_offset())); + glsafe(::glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, stride, (GLvoid*)m_triangles.get_tex_coords_offset())); + glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); } - ::glEnable(GL_DEPTH_TEST); - ::glDepthMask(GL_FALSE); + glsafe(::glEnable(GL_DEPTH_TEST)); + glsafe(::glDepthMask(GL_FALSE)); - ::glEnable(GL_BLEND); - ::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glsafe(::glEnable(GL_BLEND)); + glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); - ::glEnable(GL_TEXTURE_2D); - ::glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); +// glsafe(::glEnable(GL_TEXTURE_2D)); +// glsafe(::glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE)); if (bottom) - ::glFrontFace(GL_CW); + glsafe(::glFrontFace(GL_CW)); - render_prusa_shader(triangles_vcount, bottom); + render_prusa_shader(bottom); if (bottom) - ::glFrontFace(GL_CCW); + glsafe(::glFrontFace(GL_CCW)); - ::glDisable(GL_TEXTURE_2D); +// glsafe(::glDisable(GL_TEXTURE_2D)); - ::glDisable(GL_BLEND); - ::glDepthMask(GL_TRUE); + glsafe(::glDisable(GL_BLEND)); + glsafe(::glDepthMask(GL_TRUE)); } } -void Bed3D::render_prusa_shader(unsigned int vertices_count, bool transparent) const +void Bed3D::render_prusa_shader(bool transparent) const { if (m_shader.get_shader_program_id() == 0) m_shader.init("printbed.vs", "printbed.fs"); @@ -597,19 +596,15 @@ void Bed3D::render_prusa_shader(unsigned int vertices_count, bool transparent) c m_shader.start_using(); m_shader.set_uniform("transparent_background", transparent); - ::glBindTexture(GL_TEXTURE_2D, (GLuint)m_texture.get_id()); - ::glBindBuffer(GL_ARRAY_BUFFER, m_vbo_id); -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ - ::glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, m_triangles.get_vertex_data_size(), (GLvoid*)m_triangles.get_position_offset()); - ::glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, m_triangles.get_vertex_data_size(), (GLvoid*)m_triangles.get_tex_coords_offset()); -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ - ::glEnableVertexAttribArray(0); - ::glEnableVertexAttribArray(1); - ::glDrawArrays(GL_TRIANGLES, 0, (GLsizei)vertices_count); - ::glDisableVertexAttribArray(1); - ::glDisableVertexAttribArray(0); - ::glBindBuffer(GL_ARRAY_BUFFER, 0); - ::glBindTexture(GL_TEXTURE_2D, 0); + glsafe(::glBindTexture(GL_TEXTURE_2D, (GLuint)m_texture.get_id())); + glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_vbo_id)); + glsafe(::glEnableVertexAttribArray(0)); + glsafe(::glEnableVertexAttribArray(1)); + glsafe(::glDrawArrays(GL_TRIANGLES, 0, (GLsizei)m_triangles.get_vertices_count())); + glsafe(::glDisableVertexAttribArray(1)); + glsafe(::glDisableVertexAttribArray(0)); + glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); + glsafe(::glBindTexture(GL_TEXTURE_2D, 0)); m_shader.stop_using(); } @@ -760,7 +755,7 @@ void Bed3D::render_custom() const glsafe(::glColor4f(0.35f, 0.35f, 0.35f, 0.4f)); glsafe(::glNormal3d(0.0f, 0.0f, 1.0f)); #if ENABLE_TEXTURES_FROM_SVG - ::glVertexPointer(3, GL_FLOAT, m_triangles.get_vertex_data_size(), (GLvoid*)m_triangles.get_vertices_data()); + glsafe(::glVertexPointer(3, GL_FLOAT, m_triangles.get_vertex_data_size(), (GLvoid*)m_triangles.get_vertices_data())); #else glsafe(::glVertexPointer(3, GL_FLOAT, 0, (GLvoid*)m_triangles.get_vertices())); #endif // ENABLE_TEXTURES_FROM_SVG @@ -774,7 +769,7 @@ void Bed3D::render_custom() const glsafe(::glLineWidth(3.0f * m_scale_factor)); glsafe(::glColor4f(0.2f, 0.2f, 0.2f, 0.4f)); #if ENABLE_TEXTURES_FROM_SVG - ::glVertexPointer(3, GL_FLOAT, m_triangles.get_vertex_data_size(), (GLvoid*)m_gridlines.get_vertices_data()); + glsafe(::glVertexPointer(3, GL_FLOAT, m_triangles.get_vertex_data_size(), (GLvoid*)m_gridlines.get_vertices_data())); #else glsafe(::glVertexPointer(3, GL_FLOAT, 0, (GLvoid*)m_gridlines.get_vertices())); #endif // ENABLE_TEXTURES_FROM_SVG @@ -792,7 +787,7 @@ void Bed3D::reset() { if (m_vbo_id > 0) { - ::glDeleteBuffers(1, &m_vbo_id); + glsafe(::glDeleteBuffers(1, &m_vbo_id)); m_vbo_id = 0; } } diff --git a/src/slic3r/GUI/3DBed.hpp b/src/slic3r/GUI/3DBed.hpp index edf3e5ee76..e60cdf94e1 100644 --- a/src/slic3r/GUI/3DBed.hpp +++ b/src/slic3r/GUI/3DBed.hpp @@ -131,7 +131,7 @@ private: EType detect_type(const Pointfs& shape) const; #if ENABLE_TEXTURES_FROM_SVG void render_prusa(const std::string& key, bool bottom) const; - void render_prusa_shader(unsigned int vertices_count, bool transparent) const; + void render_prusa_shader(bool transparent) const; #else void render_prusa(const std::string &key, float theta, bool useVBOs) const; #endif // ENABLE_TEXTURES_FROM_SVG diff --git a/src/slic3r/GUI/GLShader.cpp b/src/slic3r/GUI/GLShader.cpp index 24d8d41b2d..3d3148d02b 100644 --- a/src/slic3r/GUI/GLShader.cpp +++ b/src/slic3r/GUI/GLShader.cpp @@ -225,6 +225,17 @@ bool GLShader::set_uniform(const char* name, const float* matrix) const return false; } +bool GLShader::set_uniform(const char* name, int value) const +{ + int id = get_uniform_location(name); + if (id >= 0) + { + ::glUniform1i(id, value); + return true; + } + return false; +} + /* # Set shader vector sub SetVector @@ -321,7 +332,7 @@ void Shader::set_uniform(const std::string& name, const float* matrix) const void Shader::set_uniform(const std::string& name, bool value) const { if (m_shader != nullptr) - m_shader->set_uniform(name.c_str(), value); + m_shader->set_uniform(name.c_str(), value ? 1 : 0); } unsigned int Shader::get_shader_program_id() const diff --git a/src/slic3r/GUI/GLShader.hpp b/src/slic3r/GUI/GLShader.hpp index 2f88d03936..f7e8c7716f 100644 --- a/src/slic3r/GUI/GLShader.hpp +++ b/src/slic3r/GUI/GLShader.hpp @@ -26,6 +26,7 @@ public: bool set_uniform(const char *name, float value) const; bool set_uniform(const char* name, const float* matrix) const; + bool set_uniform(const char* name, int value) const; void enable() const; void disable() const; diff --git a/src/slic3r/GUI/GLTexture.cpp b/src/slic3r/GUI/GLTexture.cpp index 436a37e1cc..19eff88e05 100644 --- a/src/slic3r/GUI/GLTexture.cpp +++ b/src/slic3r/GUI/GLTexture.cpp @@ -359,27 +359,6 @@ bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, uns nsvgDeleteRasterizer(rast); nsvgDelete(image); -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ -#if 1 - // debug output - wxImage output(m_width, m_height); - output.InitAlpha(); - - for (int h = 0; h < m_height; ++h) - { - int px_h = h * m_width; - for (int w = 0; w < m_width; ++w) - { - int offset = (px_h + w) * 4; - output.SetRGB(w, h, data.data()[offset + 0], data.data()[offset + 1], data.data()[offset + 2]); - output.SetAlpha(w, h, data.data()[offset + 3]); - } - } - - output.SaveFile(resources_dir() + "/icons/test_svg_import.png", wxBITMAP_TYPE_PNG); -#endif // 0 -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ - return true; } #endif // ENABLE_TEXTURES_FROM_SVG From 4eb4e40746343f665cfc26527fd468a2c74a49b0 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 27 Feb 2019 16:23:10 +0100 Subject: [PATCH 03/13] SLA gizmo keeps track of current status of the points, enables the user to erase all points --- src/libslic3r/Model.cpp | 4 +++ src/libslic3r/Model.hpp | 3 +++ src/libslic3r/SLA/SLACommon.hpp | 8 ++++++ src/libslic3r/SLAPrint.cpp | 24 ++++++++++++++---- src/slic3r/GUI/GLGizmo.cpp | 43 +++++++++++++++++++++------------ src/slic3r/GUI/GLGizmo.hpp | 14 +++++------ 6 files changed, 68 insertions(+), 28 deletions(-) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 6e291412c2..9c5f8c826a 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -592,6 +592,7 @@ ModelObject& ModelObject::assign_copy(const ModelObject &rhs) this->input_file = rhs.input_file; this->config = rhs.config; this->sla_support_points = rhs.sla_support_points; + this->sla_points_status = rhs.sla_points_status; this->layer_height_ranges = rhs.layer_height_ranges; this->layer_height_profile = rhs.layer_height_profile; this->origin_translation = rhs.origin_translation; @@ -625,6 +626,7 @@ ModelObject& ModelObject::assign_copy(ModelObject &&rhs) this->input_file = std::move(rhs.input_file); this->config = std::move(rhs.config); this->sla_support_points = std::move(rhs.sla_support_points); + this->sla_points_status = std::move(rhs.sla_points_status); this->layer_height_ranges = std::move(rhs.layer_height_ranges); this->layer_height_profile = std::move(rhs.layer_height_profile); this->origin_translation = std::move(rhs.origin_translation); @@ -1130,6 +1132,7 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b if (keep_upper) { upper->set_model(nullptr); upper->sla_support_points.clear(); + upper->sla_points_status = sla::PointsStatus::None; upper->clear_volumes(); upper->input_file = ""; } @@ -1137,6 +1140,7 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b if (keep_lower) { lower->set_model(nullptr); lower->sla_support_points.clear(); + lower->sla_points_status = sla::PointsStatus::None; lower->clear_volumes(); lower->input_file = ""; } diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index a215f9b9f1..a4b32d93f8 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -180,6 +180,9 @@ public: // saved in mesh coordinates to allow using them for several instances. // The format is (x, y, z, point_size, supports_island) std::vector sla_support_points; + // To keep track of where the points came from (used for synchronization between + // the SLA gizmo and the backend). + sla::PointsStatus sla_points_status = sla::PointsStatus::None; /* This vector accumulates the total translation applied to the object by the center_around_origin() method. Callers might want to apply the same translation diff --git a/src/libslic3r/SLA/SLACommon.hpp b/src/libslic3r/SLA/SLACommon.hpp index f7c0acf332..bdeead9caa 100644 --- a/src/libslic3r/SLA/SLACommon.hpp +++ b/src/libslic3r/SLA/SLACommon.hpp @@ -15,6 +15,14 @@ class TriangleMesh; namespace sla { +// An enum to keep track of where the current points on the ModelObject came from. +enum class PointsStatus { + None, // No points were generated so far. + Generating, // The autogeneration algorithm triggered, but not yet finished. + AutoGenerated, // Points were autogenerated (i.e. copied from the backend). + UserModified // User has done some edits. +}; + struct SupportPoint { Vec3f pos; float head_front_radius; diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 827846b71e..8ce3068699 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -342,6 +342,17 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf if (it_print_object_status != print_object_status.end()) update_apply_status(it_print_object_status->print_object->invalidate_step(slaposSupportPoints)); } + if (model_object.sla_points_status != model_object_new.sla_points_status) { + // Change of this status should invalidate support points. The points themselves are not enough, there are none + // in case that nothing was generated OR that points were autogenerated already and not copied to the front-end. + // These cases can only be differentiated by checking the status change. However, changing from 'Generating' should NOT + // invalidate - that would keep stopping the background processing without a reason. + if (model_object.sla_points_status != sla::PointsStatus::Generating) + if (it_print_object_status != print_object_status.end()) + update_apply_status(it_print_object_status->print_object->invalidate_step(slaposSupportPoints)); + model_object.sla_points_status = model_object_new.sla_points_status; + } + // Copy the ModelObject name, input_file and instances. The instances will compared against PrintObject instances in the next step. model_object.name = model_object_new.name; model_object.input_file = model_object_new.input_file; @@ -630,10 +641,11 @@ void SLAPrint::process() BOOST_LOG_TRIVIAL(debug) << "Support point count " << mo.sla_support_points.size(); - // If there are no points on the front-end, we will do the - // autoplacement. Otherwise we will just blindly copy the frontend data + // Unless the user modified the points or we already did the calculation, we will do + // the autoplacement. Otherwise we will just blindly copy the frontend data // into the backend cache. - if(mo.sla_support_points.empty()) { + if (mo.sla_points_status != sla::PointsStatus::UserModified) { + // calculate heights of slices (slices are calculated already) double lh = po.m_config.layer_height.getFloat(); @@ -645,7 +657,9 @@ void SLAPrint::process() this->throw_if_canceled(); SLAAutoSupports::Config config; const SLAPrintObjectConfig& cfg = po.config(); - config.density_relative = float(cfg.support_points_density_relative / 100.f); // the config value is in percents + + // the density config value is in percents: + config.density_relative = float(cfg.support_points_density_relative / 100.f); config.minimal_distance = float(cfg.support_points_minimal_distance); // Construction of this object does the calculation. @@ -669,7 +683,7 @@ void SLAPrint::process() report_status(*this, -1, L("Generating support points"), SlicingStatus::RELOAD_SLA_SUPPORT_POINTS); } else { - // There are some points on the front-end, no calculation will be done. + // There are either some points on the front-end, or the user removed them on purpose. No calculation will be done. po.m_supportdata->support_points = po.transformed_support_points(); } }; diff --git a/src/slic3r/GUI/GLGizmo.cpp b/src/slic3r/GUI/GLGizmo.cpp index f1a4589feb..e7f77eb2f4 100644 --- a/src/slic3r/GUI/GLGizmo.cpp +++ b/src/slic3r/GUI/GLGizmo.cpp @@ -1789,12 +1789,12 @@ void GLGizmoSlaSupports::set_sla_support_data(ModelObject* model_object, const G if (is_mesh_update_necessary()) update_mesh(); - // If there are no points, let's ask the backend if it calculated some. - if (m_editing_mode_cache.empty()) - get_data_from_backend(); - if (m_model_object != m_old_model_object) m_editing_mode = false; + + if (m_editing_mode_cache.empty() && m_model_object->sla_points_status != sla::PointsStatus::UserModified) + get_data_from_backend(); + if (m_state == On) { m_parent.toggle_model_objects_visibility(false); m_parent.toggle_model_objects_visibility(true, m_model_object, m_active_instance); @@ -2296,8 +2296,7 @@ RENDER_AGAIN: m_imgui->text(" "); // vertical gap - bool apply_changes = m_imgui->button(_(L("Apply changes"))); - if (apply_changes) { + if (m_imgui->button(_(L("Apply changes")))) { editing_mode_apply_changes(); force_refresh = true; } @@ -2308,24 +2307,28 @@ RENDER_AGAIN: force_refresh = true; } } - else { - /* ImGui::PushItemWidth(50.0f); + else { // not in editing mode: + /*ImGui::PushItemWidth(100.0f); m_imgui->text(_(L("Minimal points distance: "))); ImGui::SameLine(); - bool value_changed = ImGui::InputDouble("mm", &m_minimal_point_distance, 0.0f, 0.0f, "%.2f"); + bool value_changed = ImGui::SliderFloat("", &m_minimal_point_distance, 0.f, 20.f, "%.f mm"); m_imgui->text(_(L("Support points density: "))); ImGui::SameLine(); - value_changed |= ImGui::InputDouble("%", &m_density, 0.0f, 0.0f, "%.f");*/ + value_changed |= ImGui::SliderFloat(" ", &m_density, 0.f, 200.f, "%.f %%");*/ bool generate = m_imgui->button(_(L("Auto-generate points [A]"))); if (generate) auto_generate(); - m_imgui->text(""); m_imgui->text(""); if (m_imgui->button(_(L("Manual editing [M]")))) switch_to_editing_mode(); + + m_imgui->text(m_model_object->sla_points_status == sla::PointsStatus::None ? "No points (will be autogenerated)" : + (m_model_object->sla_points_status == sla::PointsStatus::AutoGenerated ? "Autogenerated points (no modifications)" : + (m_model_object->sla_points_status == sla::PointsStatus::UserModified ? "User-modified points" : + (m_model_object->sla_points_status == sla::PointsStatus::Generating ? "Generation in progress..." : "UNKNOWN STATUS")))); } m_imgui->end(); @@ -2448,16 +2451,18 @@ void GLGizmoSlaSupports::editing_mode_apply_changes() // If there are no changes, don't touch the front-end. The data in the cache could have been // taken from the backend and copying them to ModelObject would needlessly invalidate them. if (m_unsaved_changes) { + m_model_object->sla_points_status = sla::PointsStatus::UserModified; m_model_object->sla_support_points.clear(); for (const std::pair& point_and_selection : m_editing_mode_cache) m_model_object->sla_support_points.push_back(point_and_selection.first); + + // Recalculate support structures once the editing mode is left. + // m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); + // m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); + wxGetApp().plater()->reslice_SLA_supports(*m_model_object); } m_editing_mode = false; m_unsaved_changes = false; - - // Recalculate support structures once the editing mode is left. - // m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS)); - wxGetApp().plater()->reslice_SLA_supports(*m_model_object); } @@ -2476,10 +2481,15 @@ void GLGizmoSlaSupports::get_data_from_backend() { for (const SLAPrintObject* po : m_parent.sla_print()->objects()) { if (po->model_object()->id() == m_model_object->id() && po->is_step_done(slaposSupportPoints)) { + m_editing_mode_cache.clear(); const std::vector& points = po->get_support_points(); auto mat = po->trafo().inverse().cast(); for (unsigned int i=0; isla_points_status != sla::PointsStatus::UserModified) + m_model_object->sla_points_status = sla::PointsStatus::AutoGenerated; + break; } } @@ -2497,8 +2507,9 @@ void GLGizmoSlaSupports::auto_generate() "Are you sure you want to do it?\n" )), _(L("Warning")), wxICON_WARNING | wxYES | wxNO); - if (m_model_object->sla_support_points.empty() || dlg.ShowModal() == wxID_YES) { + if (m_model_object->sla_points_status != sla::PointsStatus::UserModified || dlg.ShowModal() == wxID_YES) { m_model_object->sla_support_points.clear(); + m_model_object->sla_points_status = sla::PointsStatus::Generating; m_editing_mode_cache.clear(); wxGetApp().plater()->reslice_SLA_supports(*m_model_object); } diff --git a/src/slic3r/GUI/GLGizmo.hpp b/src/slic3r/GUI/GLGizmo.hpp index 6996f5576c..a5371a3e9d 100644 --- a/src/slic3r/GUI/GLGizmo.hpp +++ b/src/slic3r/GUI/GLGizmo.hpp @@ -489,19 +489,19 @@ private: #endif // not ENABLE_IMGUI bool m_lock_unique_islands = false; - bool m_editing_mode = false; - bool m_old_editing_state = false; - float m_new_point_head_diameter = 0.4f; - double m_minimal_point_distance = 20.; - double m_density = 100.; + bool m_editing_mode = false; // Is editing mode active? + bool m_old_editing_state = false; // To keep track of whether the user toggled between the modes (needed for imgui refreshes). + float m_new_point_head_diameter = 0.4f; // Size of a new point. + float m_minimal_point_distance = 20.f; + float m_density = 100.f; std::vector> m_editing_mode_cache; // a support point and whether it is currently selected bool m_selection_rectangle_active = false; Vec2d m_selection_rectangle_start_corner; Vec2d m_selection_rectangle_end_corner; bool m_ignore_up_event = false; - bool m_combo_box_open = false; - bool m_unsaved_changes = false; + bool m_combo_box_open = false; // To ensure proper rendering of the imgui combobox. + bool m_unsaved_changes = false; // Are there unsaved changes in manual mode? bool m_selection_empty = true; EState m_old_state = Off; // to be able to see that the gizmo has just been closed (see on_set_state) int m_canvas_width; From 44b2ca81821b2b1095277a1089fab31f95630161 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 28 Feb 2019 09:04:17 +0100 Subject: [PATCH 04/13] 2nd attempt to fix rendering of printbed svg textures on Mac --- resources/shaders/printbed.vs | 10 +++++-- src/slic3r/GUI/3DBed.cpp | 53 ++++++++++++++++++++++++++++++----- src/slic3r/GUI/GLShader.cpp | 12 ++++++++ src/slic3r/GUI/GLShader.hpp | 5 ++++ 4 files changed, 71 insertions(+), 9 deletions(-) diff --git a/resources/shaders/printbed.vs b/resources/shaders/printbed.vs index 968bcce16a..7d61e03dd5 100644 --- a/resources/shaders/printbed.vs +++ b/resources/shaders/printbed.vs @@ -1,11 +1,17 @@ #version 110 +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +attribute vec4 v_position; +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ attribute vec2 v_tex_coords; varying vec2 tex_coords; void main() { - gl_Position = ftransform(); +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * v_position; +// gl_Position = ftransform(); +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ tex_coords = v_tex_coords; -} \ No newline at end of file +} diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index f271f9738e..8b71f7a780 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -553,12 +553,16 @@ void Bed3D::render_prusa(const std::string &key, bool bottom) const { if (m_vbo_id == 0) { - unsigned int stride = m_triangles.get_vertex_data_size(); +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +// unsigned int stride = m_triangles.get_vertex_data_size(); +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ glsafe(::glGenBuffers(1, &m_vbo_id)); glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_vbo_id)); glsafe(::glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)m_triangles.get_vertices_data_size(), (const GLvoid*)m_triangles.get_vertices_data(), GL_STATIC_DRAW)); - glsafe(::glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, stride, (GLvoid*)m_triangles.get_position_offset())); - glsafe(::glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, stride, (GLvoid*)m_triangles.get_tex_coords_offset())); +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +// glsafe(::glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, stride, (GLvoid*)m_triangles.get_position_offset())); +// glsafe(::glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, stride, (GLvoid*)m_triangles.get_tex_coords_offset())); +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); } @@ -596,13 +600,48 @@ void Bed3D::render_prusa_shader(bool transparent) const m_shader.start_using(); m_shader.set_uniform("transparent_background", transparent); +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + unsigned int stride = m_triangles.get_vertex_data_size(); + + GLint position_id = m_shader.get_attrib_location("v_position"); + GLint tex_coords_id = m_shader.get_attrib_location("v_tex_coords"); + + std::cout << "position_id: " << position_id << std::endl; + std::cout << "tex_coords_id: " << tex_coords_id << std::endl; + +// if (tex_coords_id != -1) +// glsafe(::glBindAttribLocation(m_shader.get_shader_program_id(), tex_coords_id, "v_tex_coords")); +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + glsafe(::glBindTexture(GL_TEXTURE_2D, (GLuint)m_texture.get_id())); glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_vbo_id)); - glsafe(::glEnableVertexAttribArray(0)); - glsafe(::glEnableVertexAttribArray(1)); +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + if (position_id != -1) + { + glsafe(::glEnableVertexAttribArray(position_id)); + glsafe(::glVertexAttribPointer(position_id, 3, GL_FLOAT, GL_FALSE, stride, (GLvoid*)m_triangles.get_position_offset())); + } + if (tex_coords_id != -1) + { + glsafe(::glEnableVertexAttribArray(tex_coords_id)); + glsafe(::glVertexAttribPointer(tex_coords_id, 2, GL_FLOAT, GL_FALSE, stride, (GLvoid*)m_triangles.get_tex_coords_offset())); + } + +// glsafe(::glEnableVertexAttribArray(0)); +// glsafe(::glEnableVertexAttribArray(1)); +// glsafe(::glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, stride, (GLvoid*)m_triangles.get_position_offset())); +// glsafe(::glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, stride, (GLvoid*)m_triangles.get_tex_coords_offset())); +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ glsafe(::glDrawArrays(GL_TRIANGLES, 0, (GLsizei)m_triangles.get_vertices_count())); - glsafe(::glDisableVertexAttribArray(1)); - glsafe(::glDisableVertexAttribArray(0)); +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + if (tex_coords_id != -1) + glsafe(::glDisableVertexAttribArray(tex_coords_id)); + if (position_id != -1) + glsafe(::glDisableVertexAttribArray(position_id)); + +// glsafe(::glDisableVertexAttribArray(1)); +// glsafe(::glDisableVertexAttribArray(0)); +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); glsafe(::glBindTexture(GL_TEXTURE_2D, 0)); diff --git a/src/slic3r/GUI/GLShader.cpp b/src/slic3r/GUI/GLShader.cpp index 3d3148d02b..ff6235296b 100644 --- a/src/slic3r/GUI/GLShader.cpp +++ b/src/slic3r/GUI/GLShader.cpp @@ -317,6 +317,18 @@ void Shader::stop_using() const m_shader->disable(); } +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +int Shader::get_attrib_location(const std::string& name) const +{ + return (m_shader != nullptr) ? m_shader->get_attrib_location(name.c_str()) : -1; +} + +int Shader::get_uniform_location(const std::string& name) const +{ + return (m_shader != nullptr) ? m_shader->get_uniform_location(name.c_str()) : -1; +} +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + void Shader::set_uniform(const std::string& name, float value) const { if (m_shader != nullptr) diff --git a/src/slic3r/GUI/GLShader.hpp b/src/slic3r/GUI/GLShader.hpp index f7e8c7716f..db5fe28327 100644 --- a/src/slic3r/GUI/GLShader.hpp +++ b/src/slic3r/GUI/GLShader.hpp @@ -53,6 +53,11 @@ public: bool start_using() const; void stop_using() const; +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + int get_attrib_location(const std::string& name) const; + int get_uniform_location(const std::string& name) const; +//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + void set_uniform(const std::string& name, float value) const; void set_uniform(const std::string& name, const float* matrix) const; void set_uniform(const std::string& name, bool value) const; From 4b6ab84dbc6c7ca44ac527e9bfa8969e318b3546 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 28 Feb 2019 09:37:55 +0100 Subject: [PATCH 05/13] Code cleanup --- resources/shaders/printbed.vs | 5 ----- src/slic3r/GUI/3DBed.cpp | 33 +++------------------------------ src/slic3r/GUI/GLShader.cpp | 2 -- src/slic3r/GUI/GLShader.hpp | 2 -- 4 files changed, 3 insertions(+), 39 deletions(-) diff --git a/resources/shaders/printbed.vs b/resources/shaders/printbed.vs index 7d61e03dd5..ac47637820 100644 --- a/resources/shaders/printbed.vs +++ b/resources/shaders/printbed.vs @@ -1,17 +1,12 @@ #version 110 -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ attribute vec4 v_position; -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ attribute vec2 v_tex_coords; varying vec2 tex_coords; void main() { -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * v_position; -// gl_Position = ftransform(); -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ tex_coords = v_tex_coords; } diff --git a/src/slic3r/GUI/3DBed.cpp b/src/slic3r/GUI/3DBed.cpp index 8b71f7a780..2367938147 100644 --- a/src/slic3r/GUI/3DBed.cpp +++ b/src/slic3r/GUI/3DBed.cpp @@ -553,16 +553,9 @@ void Bed3D::render_prusa(const std::string &key, bool bottom) const { if (m_vbo_id == 0) { -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ -// unsigned int stride = m_triangles.get_vertex_data_size(); -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ glsafe(::glGenBuffers(1, &m_vbo_id)); glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_vbo_id)); glsafe(::glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)m_triangles.get_vertices_data_size(), (const GLvoid*)m_triangles.get_vertices_data(), GL_STATIC_DRAW)); -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ -// glsafe(::glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, stride, (GLvoid*)m_triangles.get_position_offset())); -// glsafe(::glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, stride, (GLvoid*)m_triangles.get_tex_coords_offset())); -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); } @@ -572,9 +565,6 @@ void Bed3D::render_prusa(const std::string &key, bool bottom) const glsafe(::glEnable(GL_BLEND)); glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); -// glsafe(::glEnable(GL_TEXTURE_2D)); -// glsafe(::glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE)); - if (bottom) glsafe(::glFrontFace(GL_CW)); @@ -583,8 +573,6 @@ void Bed3D::render_prusa(const std::string &key, bool bottom) const if (bottom) glsafe(::glFrontFace(GL_CCW)); -// glsafe(::glDisable(GL_TEXTURE_2D)); - glsafe(::glDisable(GL_BLEND)); glsafe(::glDepthMask(GL_TRUE)); } @@ -600,22 +588,14 @@ void Bed3D::render_prusa_shader(bool transparent) const m_shader.start_using(); m_shader.set_uniform("transparent_background", transparent); -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ unsigned int stride = m_triangles.get_vertex_data_size(); GLint position_id = m_shader.get_attrib_location("v_position"); GLint tex_coords_id = m_shader.get_attrib_location("v_tex_coords"); - std::cout << "position_id: " << position_id << std::endl; - std::cout << "tex_coords_id: " << tex_coords_id << std::endl; - -// if (tex_coords_id != -1) -// glsafe(::glBindAttribLocation(m_shader.get_shader_program_id(), tex_coords_id, "v_tex_coords")); -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ - glsafe(::glBindTexture(GL_TEXTURE_2D, (GLuint)m_texture.get_id())); glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_vbo_id)); -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + if (position_id != -1) { glsafe(::glEnableVertexAttribArray(position_id)); @@ -627,21 +607,14 @@ void Bed3D::render_prusa_shader(bool transparent) const glsafe(::glVertexAttribPointer(tex_coords_id, 2, GL_FLOAT, GL_FALSE, stride, (GLvoid*)m_triangles.get_tex_coords_offset())); } -// glsafe(::glEnableVertexAttribArray(0)); -// glsafe(::glEnableVertexAttribArray(1)); -// glsafe(::glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, stride, (GLvoid*)m_triangles.get_position_offset())); -// glsafe(::glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, stride, (GLvoid*)m_triangles.get_tex_coords_offset())); -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ glsafe(::glDrawArrays(GL_TRIANGLES, 0, (GLsizei)m_triangles.get_vertices_count())); -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + if (tex_coords_id != -1) glsafe(::glDisableVertexAttribArray(tex_coords_id)); + if (position_id != -1) glsafe(::glDisableVertexAttribArray(position_id)); -// glsafe(::glDisableVertexAttribArray(1)); -// glsafe(::glDisableVertexAttribArray(0)); -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); glsafe(::glBindTexture(GL_TEXTURE_2D, 0)); diff --git a/src/slic3r/GUI/GLShader.cpp b/src/slic3r/GUI/GLShader.cpp index ff6235296b..f401f54662 100644 --- a/src/slic3r/GUI/GLShader.cpp +++ b/src/slic3r/GUI/GLShader.cpp @@ -317,7 +317,6 @@ void Shader::stop_using() const m_shader->disable(); } -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ int Shader::get_attrib_location(const std::string& name) const { return (m_shader != nullptr) ? m_shader->get_attrib_location(name.c_str()) : -1; @@ -327,7 +326,6 @@ int Shader::get_uniform_location(const std::string& name) const { return (m_shader != nullptr) ? m_shader->get_uniform_location(name.c_str()) : -1; } -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ void Shader::set_uniform(const std::string& name, float value) const { diff --git a/src/slic3r/GUI/GLShader.hpp b/src/slic3r/GUI/GLShader.hpp index db5fe28327..58e2678d03 100644 --- a/src/slic3r/GUI/GLShader.hpp +++ b/src/slic3r/GUI/GLShader.hpp @@ -53,10 +53,8 @@ public: bool start_using() const; void stop_using() const; -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ int get_attrib_location(const std::string& name) const; int get_uniform_location(const std::string& name) const; -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ void set_uniform(const std::string& name, float value) const; void set_uniform(const std::string& name, const float* matrix) const; From 3053010446aceee2979391f16aa90a49ea1795d5 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Thu, 28 Feb 2019 11:11:13 +0100 Subject: [PATCH 06/13] Bumped up the alpha version number. --- version.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.inc b/version.inc index 6713416eb1..f8c60feb69 100644 --- a/version.inc +++ b/version.inc @@ -2,7 +2,7 @@ # (the version numbers are generated by the build script from the git current label) set(SLIC3R_FORK_NAME "Slic3r Prusa Edition") -set(SLIC3R_VERSION "1.42.0-alpha5") +set(SLIC3R_VERSION "1.42.0-alpha6") set(SLIC3R_BUILD "${SLIC3R_VERSION}+UNKNOWN") set(SLIC3R_BUILD_ID "${SLIC3R_BUILD_ID}") set(SLIC3R_RC_VERSION "1,42,0,0") From dc0c58a9c5f49ca1b718e28118c5b540e0a69138 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Thu, 28 Feb 2019 11:20:01 +0100 Subject: [PATCH 07/13] Improvement of the initial placement of modifier meshes: Sphere and Cylinder are scaled to the same volume as Box Newly entered modifier meshes are rotated parallell to the world coordinates. If the instance coordinate system is rotated and scaled, it is not possible to create an unskewed modifier to world transformation. In that case the best possible transformation is found to minimize least squares error of the 8 corners of the new modifier mesh bounding box using Levenberg-Marquardt algorithm. FIXME: 1) The Levenberg-Marquardt non-linear least squares does not converge nicely, it may require some tuning. 2) Above all, if 1) is called, then often the skew of the modifier mesh is so high, that it is likely more useful to display the modifier with zero rotation and inverse scaling, so that the modifier will be of correct size, but not parallel to the world coordinates. --- src/libslic3r/Geometry.hpp | 1 + src/slic3r/GUI/GUI_ObjectList.cpp | 203 ++++++++++++++++++++++++++---- 2 files changed, 178 insertions(+), 26 deletions(-) diff --git a/src/libslic3r/Geometry.hpp b/src/libslic3r/Geometry.hpp index b43d591439..380245b5fc 100644 --- a/src/libslic3r/Geometry.hpp +++ b/src/libslic3r/Geometry.hpp @@ -242,6 +242,7 @@ public: void set_scaling_factor(const Vec3d& scaling_factor); void set_scaling_factor(Axis axis, double scaling_factor); + bool is_scaling_uniform() const { return std::abs(m_scaling_factor.x() - m_scaling_factor.y()) < 1e-8 && std::abs(m_scaling_factor.x() - m_scaling_factor.z()) < 1e-8; } const Vec3d& get_mirror() const { return m_mirror; } double get_mirror(Axis axis) const { return m_mirror(axis); } diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index c5d6fe9fde..b7b52e10cf 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -1173,10 +1173,161 @@ void ObjectList::load_part( ModelObject* model_object, } +// Find volume transformation, so that the chained (instance_trafo * volume_trafo) will be as close to identity +// as possible in least squares norm in regard to the 8 corners of bbox. +// Bounding box is expected to be centered around zero in all axes. +Geometry::Transformation volume_to_bed_transformation(const Geometry::Transformation &instance_transformation, const BoundingBoxf3 &bbox) +{ + Geometry::Transformation out; + + if (instance_transformation.is_scaling_uniform()) { + // No need to run the non-linear least squares fitting for uniform scaling. + // Just set the inverse. + out.set_from_transform(instance_transformation.get_matrix(true).inverse()); + } + else + { + Eigen::Matrix3d instance_rotation_trafo = + (Eigen::AngleAxisd(instance_transformation.get_rotation().z(), Vec3d::UnitZ()) * + Eigen::AngleAxisd(instance_transformation.get_rotation().y(), Vec3d::UnitY()) * + Eigen::AngleAxisd(instance_transformation.get_rotation().x(), Vec3d::UnitX())).toRotationMatrix(); + Eigen::Matrix3d instance_rotation_trafo_inv = + (Eigen::AngleAxisd(- instance_transformation.get_rotation().x(), Vec3d::UnitX()) * + Eigen::AngleAxisd(- instance_transformation.get_rotation().y(), Vec3d::UnitY()) * + Eigen::AngleAxisd(- instance_transformation.get_rotation().z(), Vec3d::UnitZ())).toRotationMatrix(); + Vec3d euler_angles_inv = Geometry::extract_euler_angles(instance_rotation_trafo_inv); + + Eigen::Matrix3d instance_trafo = instance_rotation_trafo * + Eigen::Scaling(instance_transformation.get_scaling_factor().cwiseProduct(instance_transformation.get_mirror())); + + // 8 corners of the bounding box. + auto pts = Eigen::MatrixXd(8, 3); + pts(0, 0) = bbox.min.x(); pts(0, 1) = bbox.min.y(); pts(0, 2) = bbox.min.z(); + pts(1, 0) = bbox.min.x(); pts(1, 1) = bbox.min.y(); pts(1, 2) = bbox.max.z(); + pts(2, 0) = bbox.min.x(); pts(2, 1) = bbox.max.y(); pts(2, 2) = bbox.min.z(); + pts(3, 0) = bbox.min.x(); pts(3, 1) = bbox.max.y(); pts(3, 2) = bbox.max.z(); + pts(4, 0) = bbox.max.x(); pts(4, 1) = bbox.min.y(); pts(4, 2) = bbox.min.z(); + pts(5, 0) = bbox.max.x(); pts(5, 1) = bbox.min.y(); pts(5, 2) = bbox.max.z(); + pts(6, 0) = bbox.max.x(); pts(6, 1) = bbox.max.y(); pts(6, 2) = bbox.min.z(); + pts(7, 0) = bbox.max.x(); pts(7, 1) = bbox.max.y(); pts(7, 2) = bbox.max.z(); + + // Current parameters: 3x scale, 3x rotation + auto beta = Eigen::MatrixXd(3 + 3, 1); + beta << 1., 1., 1., euler_angles_inv(0), euler_angles_inv(1), euler_angles_inv(2); + + { + // Trafo from world to the coordinate system of the modifier mesh, with the inverse rotation applied to the modifier. + Eigen::Matrix3d A_scaling = instance_trafo * instance_rotation_trafo_inv; + // Corners of the bounding box transformed into the modifier mesh coordinate space, with inverse rotation applied to the modifier. + auto qs = pts * A_scaling.inverse().transpose(); + // Fill in scaling based on least squares fitting of the bounding box corners. + for (int i = 0; i < 3; ++i) + beta(i) = pts.col(i).dot(qs.col(i)) / pts.col(i).dot(pts.col(i)); + } + + // Jacobian + // rows: 8 corners of a cube times 3 dimensions, + // cols: 3x scale, 3x rotation + auto J = Eigen::MatrixXd(8 * 3, 3 + 3); + + // Until convergence: + Eigen::Matrix3d s, dsx, dsy, dsz; + Eigen::Matrix3d rx, drx, ry, dry, rz, drz; + s.setIdentity(); + rx.setIdentity(); ry.setIdentity(); rz.setIdentity(); + dsx.setZero(); dsy.setZero(); dsz.setZero(); + drx.setZero(); dry.setZero(); drz.setZero(); + dsx(0, 0) = 1.; dsy(1, 1) = 1.; dsz(2, 2) = 1.; + + // Solve the non-linear Least Squares problem by Levenberg–Marquardt algorithm (modified Gauss–Newton iteration) + const double eps = 1.e-7; + auto beta_best = beta; + double beta_best_error = 1e10; + for (size_t iter = 0; iter < 200; ++ iter) { + // Current rotation & scaling transformation. + auto trafo = instance_trafo * + Eigen::AngleAxisd(beta(5), Vec3d::UnitZ()) * + Eigen::AngleAxisd(beta(4), Vec3d::UnitY()) * + Eigen::AngleAxisd(beta(3), Vec3d::UnitX()) * + Eigen::Scaling(Vec3d(beta(0), beta(1), beta(2))); + // Current error after rotation & scaling. + auto dy = (pts - pts * trafo.transpose()).eval(); + double err = 0; + for (int i = 0; i < 8; ++i) + err += dy.row(i).norm(); + if (err < beta_best_error) { + beta_best = beta; + beta_best_error = err; + } + // Fill in the Jacobian at current beta. + double cos_rx = cos(beta(3)); + double sin_rx = sin(beta(3)); + double cos_ry = cos(beta(4)); + double sin_ry = sin(beta(4)); + double cos_rz = cos(beta(5)); + double sin_rz = sin(beta(5)); + rx << 1., 0., 0., 0., cos_rx, -sin_rx, 0., sin_rx, cos_rx; + drx << 0., 0., 0., 0., -sin_rx, -cos_rx, 0., cos_rx, -sin_rx; + ry << cos_ry, 0., sin_ry, 0., 1., 0., -sin_ry, 0., cos_ry; + dry << -sin_ry, 0., cos_ry, 0., 0., 0., -cos_ry, 0., -sin_ry; + rz << cos_rz, -sin_rz, 0., sin_rz, cos_rz, 0., 0., 0., 1.; + drz << -sin_rz, -cos_rz, 0., cos_rz, -sin_rz, 0., 0., 0., 0.; + s(0, 0) = beta(0); + s(1, 1) = beta(1); + s(2, 2) = beta(2); + auto rot = (instance_trafo * rz * ry * rx).eval(); + auto jrx = pts * (instance_trafo * rz * ry * drx * s).transpose(); + auto jry = pts * (instance_trafo * rz * dry * rx * s).transpose(); + auto jrz = pts * (instance_trafo * drz * ry * rx * s).transpose(); + for (int r = 0; r < 8; ++ r) { + for (int i = 0; i < 3; ++ i) { + J(r * 3 + i, 0) = rot(i, 0) * pts(r, 0); + J(r * 3 + i, 1) = rot(i, 1) * pts(r, 1); + J(r * 3 + i, 2) = rot(i, 2) * pts(r, 2); + J(r * 3 + i, 3) = jrx(r, i); + J(r * 3 + i, 4) = jry(r, i); + J(r * 3 + i, 5) = jrz(r, i); + } + } + // Solving the normal equations for delta beta. + auto rhs = (J.transpose() * Eigen::Map(dy.data(), dy.size())).eval(); + double lambda = 1.; // 0.01; + auto A = (J.transpose() * J + Eigen::Matrix::Identity() * lambda).eval(); + auto L = A.ldlt(); + auto delta_beta = L.solve(rhs).eval(); + // Check for convergence. + auto delta_beta_max = delta_beta.cwiseAbs().maxCoeff(); + if (delta_beta_max < eps) + break; + beta = beta + delta_beta; + } + + out.set_rotation(Vec3d(beta_best(3), beta_best(4), beta_best(5))); + out.set_scaling_factor(Vec3d(std::abs(beta_best(0)), std::abs(beta_best(1)), std::abs(beta_best(2)))); + out.set_mirror(Vec3d(beta_best(0) > 0 ? 1. : -1, beta_best(1) > 0 ? 1. : -1, beta_best(2) > 0 ? 1. : -1)); + } + + return out; +} + void ObjectList::load_generic_subobject(const std::string& type_name, const ModelVolumeType type) { const auto obj_idx = get_selected_obj_idx(); - if (obj_idx < 0) return; + if (obj_idx < 0) + return; + + const GLCanvas3D::Selection& selection = wxGetApp().plater()->canvas3D()->get_selection(); + assert(obj_idx == selection.get_object_idx()); + // Selected instance index in ModelObject. Only valid if there is only one instance selected in the selection. + int instance_idx = selection.get_instance_idx(); + assert(instance_idx != -1); + if (instance_idx == -1) + return; + + // Selected object + ModelObject &model_object = *(*m_objects)[obj_idx]; + // Bounding box of the selected instance in world coordinate system including the translation, without modifiers. + BoundingBoxf3 instance_bb = model_object.instance_bounding_box(instance_idx); const wxString name = _(L("Generic")) + "-" + _(type_name); TriangleMesh mesh; @@ -1185,48 +1336,48 @@ void ObjectList::load_generic_subobject(const std::string& type_name, const Mode const auto& sz = BoundingBoxf(bed_shape).size(); const auto side = 0.1 * std::max(sz(0), sz(1)); - if (type_name == "Box") { + if (type_name == "Box") + // Sitting on the print bed, left front front corner at (0, 0). mesh = make_cube(side, side, side); - // box sets the base coordinate at 0, 0, move to center of plate - mesh.translate(-side * 0.5, -side * 0.5, 0); - } else if (type_name == "Cylinder") - mesh = make_cylinder(0.5*side, side); + // Centered around 0, sitting on the print bed. + // The cylinder has the same volume as the box above. + mesh = make_cylinder(0.564 * side, side); else if (type_name == "Sphere") - mesh = make_sphere(0.5*side, PI/18); - else if (type_name == "Slab") { - const auto& size = (*m_objects)[obj_idx]->bounding_box().size(); - mesh = make_cube(size(0)*1.5, size(1)*1.5, size(2)*0.5); - // box sets the base coordinate at 0, 0, move to center of plate and move it up to initial_z - mesh.translate(-size(0)*1.5 / 2.0, -size(1)*1.5 / 2.0, 0); - } + // Centered around 0, half the sphere below the print bed, half above. + // The sphere has the same volume as the box above. + mesh = make_sphere(0.62 * side, PI / 18); + else if (type_name == "Slab") + // Sitting on the print bed, left front front corner at (0, 0). + mesh = make_cube(instance_bb.size().x()*1.5, instance_bb.size().y()*1.5, instance_bb.size().z()*0.5); mesh.repair(); - auto new_volume = (*m_objects)[obj_idx]->add_volume(mesh); + // Mesh will be centered when loading. + ModelVolume *new_volume = model_object.add_volume(std::move(mesh)); new_volume->set_type(type); #if !ENABLE_GENERIC_SUBPARTS_PLACEMENT - new_volume->set_offset(Vec3d(0.0, 0.0, (*m_objects)[obj_idx]->origin_translation(2) - mesh.stl.stats.min(2))); + new_volume->set_offset(Vec3d(0.0, 0.0, model_object.origin_translation(2) - mesh.stl.stats.min(2))); #endif // !ENABLE_GENERIC_SUBPARTS_PLACEMENT #if !ENABLE_VOLUMES_CENTERING_FIXES new_volume->center_geometry(); #endif // !ENABLE_VOLUMES_CENTERING_FIXES #if ENABLE_GENERIC_SUBPARTS_PLACEMENT - const GLCanvas3D::Selection& selection = wxGetApp().plater()->canvas3D()->get_selection(); - int instance_idx = selection.get_instance_idx(); if (instance_idx != -1) { + // First (any) GLVolume of the selected instance. They all share the same instance matrix. const GLVolume* v = selection.get_volume(*selection.get_volume_idxs().begin()); - const Transform3d& inst_m = v->get_instance_transformation().get_matrix(true); - TriangleMesh vol_mesh(mesh); - vol_mesh.transform(inst_m); - Vec3d vol_shift = -vol_mesh.bounding_box().center(); - vol_mesh.translate((float)vol_shift(0), (float)vol_shift(1), (float)vol_shift(2)); - Vec3d world_mesh_bb_size = vol_mesh.bounding_box().size(); - BoundingBoxf3 inst_bb = (*m_objects)[obj_idx]->instance_bounding_box(instance_idx); - Vec3d world_target = Vec3d(inst_bb.max(0), inst_bb.min(1), inst_bb.min(2)) + 0.5 * world_mesh_bb_size; - new_volume->set_offset(inst_m.inverse() * (world_target - v->get_instance_offset())); + // Transform the new modifier to be aligned with the print bed. + const BoundingBoxf3 mesh_bb = new_volume->mesh.bounding_box(); + new_volume->set_transformation(volume_to_bed_transformation(v->get_instance_transformation(), mesh_bb)); + // Set the modifier position. + auto offset = (type_name == "Slab") ? + // Slab: Lift to print bed + Vec3d(0., 0., 0.5 * mesh_bb.size().z() + instance_bb.min.z() - v->get_instance_offset().z()) : + // Translate the new modifier to be pickable: move to the left front corner of the instance's bounding box, lift to print bed. + Vec3d(instance_bb.max(0), instance_bb.min(1), instance_bb.min(2)) + 0.5 * mesh_bb.size() - v->get_instance_offset(); + new_volume->set_offset(v->get_instance_transformation().get_matrix(true).inverse() * offset); } #endif // ENABLE_GENERIC_SUBPARTS_PLACEMENT From 8a6d29f7d8b643f18a1112fb4c456990d4424596 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 28 Feb 2019 11:26:27 +0100 Subject: [PATCH 08/13] Workaround to fix inconsistencies of width of gcode preview extrusion paths --- src/libslic3r/GCode.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 4d3ad00dd0..910c3f871d 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -2488,6 +2488,10 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, // adds analyzer tags and updates analyzer's tracking data if (m_enable_analyzer) { + // PrusaMultiMaterial::Writer may generate GCodeAnalyzer::Height_Tag and GCodeAnalyzer::Width_Tag lines without updating m_last_height and m_last_width + // so, if the last role was erWipeTower we force export of GCodeAnalyzer::Height_Tag and GCodeAnalyzer::Width_Tag lines + bool last_was_wipe_tower = (m_last_analyzer_extrusion_role == erWipeTower); + if (path.role() != m_last_analyzer_extrusion_role) { m_last_analyzer_extrusion_role = path.role(); @@ -2505,7 +2509,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, gcode += buf; } - if (m_last_width != path.width) + if (last_was_wipe_tower || (m_last_width != path.width)) { m_last_width = path.width; @@ -2514,7 +2518,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description, gcode += buf; } - if (m_last_height != path.height) + if (last_was_wipe_tower || (m_last_height != path.height)) { m_last_height = path.height; From 1f7db3d40c310ad68b681fadeef0dfdfc97f06dc Mon Sep 17 00:00:00 2001 From: bubnikv Date: Fri, 1 Mar 2019 10:09:20 +0100 Subject: [PATCH 09/13] Reworked the "new modifier mesh place on face" code to not place on face if the instance coordinate system is skewed. --- src/slic3r/GUI/GUI_ObjectList.cpp | 136 ++++++++---------------------- src/slic3r/GUI/Plater.cpp | 2 +- 2 files changed, 34 insertions(+), 104 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index b7b52e10cf..082ea42c68 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -1180,25 +1180,29 @@ Geometry::Transformation volume_to_bed_transformation(const Geometry::Transforma { Geometry::Transformation out; + // Is the angle close to a multiple of 90 degrees? + auto ninety_degrees = [](double a) { + a = fmod(std::abs(a), 0.5 * PI); + if (a > 0.25 * PI) + a = 0.5 * PI - a; + return a < 0.001; + }; if (instance_transformation.is_scaling_uniform()) { // No need to run the non-linear least squares fitting for uniform scaling. // Just set the inverse. out.set_from_transform(instance_transformation.get_matrix(true).inverse()); } - else - { + else if (ninety_degrees(instance_transformation.get_rotation().x()) && ninety_degrees(instance_transformation.get_rotation().y()) && ninety_degrees(instance_transformation.get_rotation().z())) + { + // Anisotropic scaling, rotation by multiples of ninety degrees. Eigen::Matrix3d instance_rotation_trafo = (Eigen::AngleAxisd(instance_transformation.get_rotation().z(), Vec3d::UnitZ()) * Eigen::AngleAxisd(instance_transformation.get_rotation().y(), Vec3d::UnitY()) * Eigen::AngleAxisd(instance_transformation.get_rotation().x(), Vec3d::UnitX())).toRotationMatrix(); - Eigen::Matrix3d instance_rotation_trafo_inv = - (Eigen::AngleAxisd(- instance_transformation.get_rotation().x(), Vec3d::UnitX()) * - Eigen::AngleAxisd(- instance_transformation.get_rotation().y(), Vec3d::UnitY()) * - Eigen::AngleAxisd(- instance_transformation.get_rotation().z(), Vec3d::UnitZ())).toRotationMatrix(); - Vec3d euler_angles_inv = Geometry::extract_euler_angles(instance_rotation_trafo_inv); - - Eigen::Matrix3d instance_trafo = instance_rotation_trafo * - Eigen::Scaling(instance_transformation.get_scaling_factor().cwiseProduct(instance_transformation.get_mirror())); + Eigen::Matrix3d volume_rotation_trafo = + (Eigen::AngleAxisd(-instance_transformation.get_rotation().x(), Vec3d::UnitX()) * + Eigen::AngleAxisd(-instance_transformation.get_rotation().y(), Vec3d::UnitY()) * + Eigen::AngleAxisd(-instance_transformation.get_rotation().z(), Vec3d::UnitZ())).toRotationMatrix(); // 8 corners of the bounding box. auto pts = Eigen::MatrixXd(8, 3); @@ -1211,101 +1215,27 @@ Geometry::Transformation volume_to_bed_transformation(const Geometry::Transforma pts(6, 0) = bbox.max.x(); pts(6, 1) = bbox.max.y(); pts(6, 2) = bbox.min.z(); pts(7, 0) = bbox.max.x(); pts(7, 1) = bbox.max.y(); pts(7, 2) = bbox.max.z(); - // Current parameters: 3x scale, 3x rotation - auto beta = Eigen::MatrixXd(3 + 3, 1); - beta << 1., 1., 1., euler_angles_inv(0), euler_angles_inv(1), euler_angles_inv(2); + // Corners of the bounding box transformed into the modifier mesh coordinate space, with inverse rotation applied to the modifier. + auto qs = pts * + (instance_rotation_trafo * + Eigen::Scaling(instance_transformation.get_scaling_factor().cwiseProduct(instance_transformation.get_mirror())) * + volume_rotation_trafo).inverse().transpose(); + // Fill in scaling based on least squares fitting of the bounding box corners. + Vec3d scale; + for (int i = 0; i < 3; ++ i) + scale(i) = pts.col(i).dot(qs.col(i)) / pts.col(i).dot(pts.col(i)); - { - // Trafo from world to the coordinate system of the modifier mesh, with the inverse rotation applied to the modifier. - Eigen::Matrix3d A_scaling = instance_trafo * instance_rotation_trafo_inv; - // Corners of the bounding box transformed into the modifier mesh coordinate space, with inverse rotation applied to the modifier. - auto qs = pts * A_scaling.inverse().transpose(); - // Fill in scaling based on least squares fitting of the bounding box corners. - for (int i = 0; i < 3; ++i) - beta(i) = pts.col(i).dot(qs.col(i)) / pts.col(i).dot(pts.col(i)); - } - - // Jacobian - // rows: 8 corners of a cube times 3 dimensions, - // cols: 3x scale, 3x rotation - auto J = Eigen::MatrixXd(8 * 3, 3 + 3); - - // Until convergence: - Eigen::Matrix3d s, dsx, dsy, dsz; - Eigen::Matrix3d rx, drx, ry, dry, rz, drz; - s.setIdentity(); - rx.setIdentity(); ry.setIdentity(); rz.setIdentity(); - dsx.setZero(); dsy.setZero(); dsz.setZero(); - drx.setZero(); dry.setZero(); drz.setZero(); - dsx(0, 0) = 1.; dsy(1, 1) = 1.; dsz(2, 2) = 1.; - - // Solve the non-linear Least Squares problem by Levenberg–Marquardt algorithm (modified Gauss–Newton iteration) - const double eps = 1.e-7; - auto beta_best = beta; - double beta_best_error = 1e10; - for (size_t iter = 0; iter < 200; ++ iter) { - // Current rotation & scaling transformation. - auto trafo = instance_trafo * - Eigen::AngleAxisd(beta(5), Vec3d::UnitZ()) * - Eigen::AngleAxisd(beta(4), Vec3d::UnitY()) * - Eigen::AngleAxisd(beta(3), Vec3d::UnitX()) * - Eigen::Scaling(Vec3d(beta(0), beta(1), beta(2))); - // Current error after rotation & scaling. - auto dy = (pts - pts * trafo.transpose()).eval(); - double err = 0; - for (int i = 0; i < 8; ++i) - err += dy.row(i).norm(); - if (err < beta_best_error) { - beta_best = beta; - beta_best_error = err; - } - // Fill in the Jacobian at current beta. - double cos_rx = cos(beta(3)); - double sin_rx = sin(beta(3)); - double cos_ry = cos(beta(4)); - double sin_ry = sin(beta(4)); - double cos_rz = cos(beta(5)); - double sin_rz = sin(beta(5)); - rx << 1., 0., 0., 0., cos_rx, -sin_rx, 0., sin_rx, cos_rx; - drx << 0., 0., 0., 0., -sin_rx, -cos_rx, 0., cos_rx, -sin_rx; - ry << cos_ry, 0., sin_ry, 0., 1., 0., -sin_ry, 0., cos_ry; - dry << -sin_ry, 0., cos_ry, 0., 0., 0., -cos_ry, 0., -sin_ry; - rz << cos_rz, -sin_rz, 0., sin_rz, cos_rz, 0., 0., 0., 1.; - drz << -sin_rz, -cos_rz, 0., cos_rz, -sin_rz, 0., 0., 0., 0.; - s(0, 0) = beta(0); - s(1, 1) = beta(1); - s(2, 2) = beta(2); - auto rot = (instance_trafo * rz * ry * rx).eval(); - auto jrx = pts * (instance_trafo * rz * ry * drx * s).transpose(); - auto jry = pts * (instance_trafo * rz * dry * rx * s).transpose(); - auto jrz = pts * (instance_trafo * drz * ry * rx * s).transpose(); - for (int r = 0; r < 8; ++ r) { - for (int i = 0; i < 3; ++ i) { - J(r * 3 + i, 0) = rot(i, 0) * pts(r, 0); - J(r * 3 + i, 1) = rot(i, 1) * pts(r, 1); - J(r * 3 + i, 2) = rot(i, 2) * pts(r, 2); - J(r * 3 + i, 3) = jrx(r, i); - J(r * 3 + i, 4) = jry(r, i); - J(r * 3 + i, 5) = jrz(r, i); - } - } - // Solving the normal equations for delta beta. - auto rhs = (J.transpose() * Eigen::Map(dy.data(), dy.size())).eval(); - double lambda = 1.; // 0.01; - auto A = (J.transpose() * J + Eigen::Matrix::Identity() * lambda).eval(); - auto L = A.ldlt(); - auto delta_beta = L.solve(rhs).eval(); - // Check for convergence. - auto delta_beta_max = delta_beta.cwiseAbs().maxCoeff(); - if (delta_beta_max < eps) - break; - beta = beta + delta_beta; - } - - out.set_rotation(Vec3d(beta_best(3), beta_best(4), beta_best(5))); - out.set_scaling_factor(Vec3d(std::abs(beta_best(0)), std::abs(beta_best(1)), std::abs(beta_best(2)))); - out.set_mirror(Vec3d(beta_best(0) > 0 ? 1. : -1, beta_best(1) > 0 ? 1. : -1, beta_best(2) > 0 ? 1. : -1)); + out.set_rotation(Geometry::extract_euler_angles(volume_rotation_trafo)); + out.set_scaling_factor(Vec3d(std::abs(scale(0)), std::abs(scale(1)), std::abs(scale(2)))); + out.set_mirror(Vec3d(scale(0) > 0 ? 1. : -1, scale(1) > 0 ? 1. : -1, scale(2) > 0 ? 1. : -1)); } + else + { + // General anisotropic scaling, general rotation. + // Keep the modifier mesh in the instance coordinate system, so the modifier mesh will not be aligned with the world. + // Scale it to get the required size. + out.set_scaling_factor(instance_transformation.get_scaling_factor().cwiseInverse()); + } return out; } diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index e917269d25..08698998ff 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -2972,7 +2972,7 @@ void Plater::export_gcode() default_output_file = fs::path(Slic3r::fold_utf8_to_ascii(default_output_file.string())); auto start_dir = wxGetApp().app_config->get_last_output_dir(default_output_file.parent_path().string()); - wxFileDialog dlg(this, (printer_technology() == ptFFF) ? _(L("Save G-code file as:")) : _(L("Save Zip file as:")), + wxFileDialog dlg(this, (printer_technology() == ptFFF) ? _(L("Save G-code file as:")) : _(L("Save SL1 file as:")), start_dir, from_path(default_output_file.filename()), GUI::file_wildcards((printer_technology() == ptFFF) ? FT_GCODE : FT_PNGZIP, default_output_file.extension().string()), From d009be760914b94829c05f48fa6a1e55f31a347e Mon Sep 17 00:00:00 2001 From: bubnikv Date: Fri, 1 Mar 2019 10:20:12 +0100 Subject: [PATCH 10/13] Fixed rotation of single instance -> it works now with absolute values. Added Absolute / relative, World / Local, Rigid body / independent modifier parameter to the object / group rotation. --- src/slic3r/GUI/GLCanvas3D.cpp | 28 ++++++++---- src/slic3r/GUI/GLCanvas3D.hpp | 55 ++++++++++++++++++++++- src/slic3r/GUI/GUI_ObjectManipulation.cpp | 14 +++--- 3 files changed, 82 insertions(+), 15 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 4f456c3921..6f80b0165b 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1261,17 +1261,21 @@ static double rotation_diff_z(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to return (axis.z() < 0) ? -angle : angle; } -void GLCanvas3D::Selection::rotate(const Vec3d& rotation, bool local) +// Rotate an object around one of the axes. Only one rotation component is expected to be changing. +void GLCanvas3D::Selection::rotate(const Vec3d& rotation, GLCanvas3D::TransformationType transformation_type) { if (!m_valid) return; + // Only relative rotation values are allowed in the world coordinate system. + assert(! transformation_type.world() || transformation_type.relative()); + int rot_axis_max; rotation.cwiseAbs().maxCoeff(&rot_axis_max); // For generic rotation, we want to rotate the first volume in selection, and then to synchronize the other volumes with it. std::vector object_instance_first(m_model->objects.size(), -1); - auto rotate_instance = [this, &rotation, &object_instance_first, rot_axis_max, local](GLVolume &volume, int i) { + auto rotate_instance = [this, &rotation, &object_instance_first, rot_axis_max, transformation_type](GLVolume &volume, int i) { int first_volume_idx = object_instance_first[volume.object_idx()]; if (rot_axis_max != 2 && first_volume_idx != -1) { // Generic rotation, but no rotation around the Z axis. @@ -1283,11 +1287,14 @@ void GLCanvas3D::Selection::rotate(const Vec3d& rotation, bool local) volume.set_instance_rotation(Vec3d(rotation(0), rotation(1), rotation(2) + z_diff)); } else { // extracts rotations from the composed transformation - Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation); - Vec3d new_rotation = Geometry::extract_euler_angles(m * m_cache.volumes_data[i].get_instance_rotation_matrix()); - if (rot_axis_max == 2 && !local) + Vec3d new_rotation = transformation_type.world() ? + Geometry::extract_euler_angles(Geometry::assemble_transform(Vec3d::Zero(), rotation) * m_cache.volumes_data[i].get_instance_rotation_matrix()) : + transformation_type.absolute() ? rotation : rotation + m_cache.volumes_data[i].get_instance_rotation(); + if (rot_axis_max == 2 && transformation_type.joint()) { // Only allow rotation of multiple instances as a single rigid body when rotating around the Z axis. - volume.set_instance_offset(m_cache.dragging_center + m * (m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center)); + double z_diff = rotation_diff_z(new_rotation, m_cache.volumes_data[i].get_instance_rotation()); + volume.set_instance_offset(m_cache.dragging_center + Eigen::AngleAxisd(z_diff, Vec3d::UnitZ()) * (m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center)); + } volume.set_instance_rotation(new_rotation); object_instance_first[volume.object_idx()] = i; } @@ -1300,7 +1307,7 @@ void GLCanvas3D::Selection::rotate(const Vec3d& rotation, bool local) rotate_instance(volume, i); else if (is_single_volume() || is_single_modifier()) { - if (local) + if (transformation_type.independent()) volume.set_volume_rotation(volume.get_volume_rotation() + rotation); else { @@ -1318,7 +1325,7 @@ void GLCanvas3D::Selection::rotate(const Vec3d& rotation, bool local) // extracts rotations from the composed transformation Transform3d m = Geometry::assemble_transform(Vec3d::Zero(), rotation); Vec3d new_rotation = Geometry::extract_euler_angles(m * m_cache.volumes_data[i].get_volume_rotation_matrix()); - if (!local) + if (transformation_type.joint()) { Vec3d offset = m * (m_cache.volumes_data[i].get_volume_position() + m_cache.volumes_data[i].get_instance_position() - m_cache.dragging_center); volume.set_volume_offset(m_cache.dragging_center - m_cache.volumes_data[i].get_instance_position() + offset); @@ -5162,7 +5169,10 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) case Gizmos::Rotate: { // Apply new temporary rotations - m_selection.rotate(m_gizmos.get_rotation(), evt.AltDown()); + TransformationType transformation_type(TransformationType::World_Relative_Joint); + if (evt.AltDown()) + transformation_type.set_independent(); + m_selection.rotate(m_gizmos.get_rotation(), transformation_type); wxGetApp().obj_manipul()->update_settings_value(m_selection); break; } diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 008e770562..06fda3e5c3 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -375,6 +375,59 @@ class GLCanvas3D }; public: + class TransformationType + { + public: + enum Enum { + // Transforming in a world coordinate system + World = 0, + // Transforming in a local coordinate system + Local = 1, + // Absolute transformations, allowed in local coordinate system only. + Absolute = 0, + // Relative transformations, allowed in both local and world coordinate system. + Relative = 2, + // For group selection, the transformation is performed as if the group made a single solid body. + Joint = 0, + // For group selection, the transformation is performed on each object independently. + Independent = 4, + + World_Relative_Joint = World | Relative | Joint, + World_Relative_Independent = World | Relative | Independent, + Local_Absolute_Joint = Local | Absolute | Joint, + Local_Absolute_Independent = Local | Absolute | Independent, + Local_Relative_Joint = Local | Relative | Joint, + Local_Relative_Independent = Local | Relative | Independent, + }; + + TransformationType() : m_value(World) {} + TransformationType(Enum value) : m_value(value) {} + TransformationType& operator=(Enum value) { m_value = value; return *this; } + + Enum operator()() const { return m_value; } + bool has(Enum v) const { return ((unsigned int)m_value & (unsigned int)v) != 0; } + + void set_world() { this->remove(Local); } + void set_local() { this->add(Local); } + void set_absolute() { this->remove(Relative); } + void set_relative() { this->add(Relative); } + void set_joint() { this->remove(Independent); } + void set_independent() { this->add(Independent); } + + bool world() const { return ! this->has(Local); } + bool local() const { return this->has(Local); } + bool absolute() const { return ! this->has(Relative); } + bool relative() const { return this->has(Relative); } + bool joint() const { return ! this->has(Independent); } + bool independent() const { return this->has(Independent); } + + private: + void add(Enum v) { m_value = Enum((unsigned int)m_value | (unsigned int)v); } + void remove(Enum v) { m_value = Enum((unsigned int)m_value & (~(unsigned int)v)); } + + Enum m_value; + }; + class Selection { public: @@ -553,7 +606,7 @@ public: void start_dragging(); void translate(const Vec3d& displacement, bool local = false); - void rotate(const Vec3d& rotation, bool local); + void rotate(const Vec3d& rotation, TransformationType transformation_type); void flattening_rotate(const Vec3d& normal); void scale(const Vec3d& scale, bool local); void mirror(Axis axis); diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index 5afd7ae59c..1fa28d65a8 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -361,16 +361,20 @@ void ObjectManipulation::change_rotation_value(const Vec3d& rotation) GLCanvas3D* canvas = wxGetApp().plater()->canvas3D(); const GLCanvas3D::Selection& selection = canvas->get_selection(); - Vec3d delta_rotation = rotation - m_cache.rotation; + GLCanvas3D::TransformationType transformation_type(GLCanvas3D::TransformationType::World_Relative_Joint); + if (selection.is_single_full_instance() || selection.requires_local_axes()) + transformation_type.set_independent(); + if (selection.is_single_full_instance()) { + transformation_type.set_absolute(); + transformation_type.set_local(); + } Vec3d rad_rotation; for (size_t i = 0; i < 3; ++i) - { - rad_rotation(i) = Geometry::deg2rad(delta_rotation(i)); - } + rad_rotation(i) = Geometry::deg2rad((transformation_type.absolute()) ? rotation(i) : rotation(i) - m_cache.rotation(i)); canvas->get_selection().start_dragging(); - canvas->get_selection().rotate(rad_rotation, selection.is_single_full_instance() || selection.requires_local_axes()); + canvas->get_selection().rotate(rad_rotation, transformation_type); canvas->do_rotate(); m_cache.rotation = rotation; From e03199d9896ebac2a1a992a4d3cebb441557f958 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 1 Mar 2019 10:40:10 +0100 Subject: [PATCH 11/13] Allow selection of subparts only from sidebar table --- src/slic3r/GUI/GLCanvas3D.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 6f80b0165b..f5698ef43c 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -896,8 +896,7 @@ void GLCanvas3D::Selection::add(unsigned int volume_idx, bool as_single_selectio if (needs_reset) clear(); - if (volume->is_modifier) - m_mode = Volume; + m_mode = volume->is_modifier ? Volume : Instance; switch (m_mode) { From 058468d371c29f79260d776ff4e90b5976180786 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 28 Feb 2019 15:27:03 +0100 Subject: [PATCH 12/13] Do not regenerate existing gcode preview toolpaths when switching to Preview --- src/libslic3r/Technologies.hpp | 2 ++ src/slic3r/GUI/GUI_Preview.cpp | 17 ++++++++++++++--- src/slic3r/GUI/GUI_Preview.hpp | 4 ++++ src/slic3r/GUI/Plater.cpp | 10 ++++++++++ 4 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 755ca5ffac..20f18cdeea 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -58,5 +58,7 @@ // Printbed textures generated from svg files #define ENABLE_TEXTURES_FROM_SVG (1 && ENABLE_1_42_0_ALPHA7) +// Do not regenerate GLVolumes for gcode preview if not needed +#define ENABLE_NO_GCODE_TOOLPATHS_REGENERATION (1 && ENABLE_1_42_0_ALPHA7) #endif // _technologies_h_ diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index 549dbd7e6e..f9f5075716 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -418,11 +418,22 @@ void Preview::load_print() load_print_as_sla(); } +#if ENABLE_NO_GCODE_TOOLPATHS_REGENERATION +void Preview::reload_print(bool force, bool keep_volumes) +#else void Preview::reload_print(bool force) +#endif // ENABLE_NO_GCODE_TOOLPATHS_REGENERATION { - m_canvas->reset_volumes(); - m_canvas->reset_legend_texture(); - m_loaded = false; +#if ENABLE_NO_GCODE_TOOLPATHS_REGENERATION + if (!keep_volumes) + { +#endif // ENABLE_NO_GCODE_TOOLPATHS_REGENERATION + m_canvas->reset_volumes(); + m_canvas->reset_legend_texture(); + m_loaded = false; +#if ENABLE_NO_GCODE_TOOLPATHS_REGENERATION + } +#endif // ENABLE_NO_GCODE_TOOLPATHS_REGENERATION if (!IsShown() && !force) return; diff --git a/src/slic3r/GUI/GUI_Preview.hpp b/src/slic3r/GUI/GUI_Preview.hpp index 6cd67013cc..124be934d0 100644 --- a/src/slic3r/GUI/GUI_Preview.hpp +++ b/src/slic3r/GUI/GUI_Preview.hpp @@ -129,7 +129,11 @@ public: void set_drop_target(wxDropTarget* target); void load_print(); +#if ENABLE_NO_GCODE_TOOLPATHS_REGENERATION + void reload_print(bool force = false, bool keep_volumes = false); +#else void reload_print(bool force = false); +#endif // ENABLE_NO_GCODE_TOOLPATHS_REGENERATION void refresh_print(); private: diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 08698998ff..6d62e9d842 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1997,6 +1997,11 @@ void Plater::priv::schedule_background_process() this->background_process_timer.Start(500, wxTIMER_ONE_SHOT); // Notify the Canvas3D that something has changed, so it may invalidate some of the layer editing stuff. this->view3D->get_canvas3d()->set_config(this->config); +#if ENABLE_NO_GCODE_TOOLPATHS_REGENERATION + // Reset gcode preview + this->preview->get_canvas3d()->reset_volumes(); + this->preview->get_canvas3d()->reset_legend_texture(); +#endif // ENABLE_NO_GCODE_TOOLPATHS_REGENERATION } void Plater::priv::update_print_volume_state() @@ -2261,7 +2266,12 @@ void Plater::priv::set_current_panel(wxPanel* panel) else if (current_panel == preview) { this->q->reslice(); +#if ENABLE_NO_GCODE_TOOLPATHS_REGENERATION + // keeps current gcode preview, if any + preview->reload_print(false, true); +#else preview->reload_print(); +#endif // ENABLE_NO_GCODE_TOOLPATHS_REGENERATION preview->set_canvas_as_dirty(); view_toolbar.select_item("Preview"); } From 8c3df91f2e9453bb9190b21c76d567be189cd3a8 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Fri, 1 Mar 2019 10:46:28 +0100 Subject: [PATCH 13/13] Code cleanup --- src/libslic3r/Technologies.hpp | 2 -- src/slic3r/GUI/GUI_Preview.cpp | 8 -------- src/slic3r/GUI/GUI_Preview.hpp | 4 ---- src/slic3r/GUI/Plater.cpp | 6 ------ 4 files changed, 20 deletions(-) diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 20f18cdeea..755ca5ffac 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -58,7 +58,5 @@ // Printbed textures generated from svg files #define ENABLE_TEXTURES_FROM_SVG (1 && ENABLE_1_42_0_ALPHA7) -// Do not regenerate GLVolumes for gcode preview if not needed -#define ENABLE_NO_GCODE_TOOLPATHS_REGENERATION (1 && ENABLE_1_42_0_ALPHA7) #endif // _technologies_h_ diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index f9f5075716..22def06230 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -418,22 +418,14 @@ void Preview::load_print() load_print_as_sla(); } -#if ENABLE_NO_GCODE_TOOLPATHS_REGENERATION void Preview::reload_print(bool force, bool keep_volumes) -#else -void Preview::reload_print(bool force) -#endif // ENABLE_NO_GCODE_TOOLPATHS_REGENERATION { -#if ENABLE_NO_GCODE_TOOLPATHS_REGENERATION if (!keep_volumes) { -#endif // ENABLE_NO_GCODE_TOOLPATHS_REGENERATION m_canvas->reset_volumes(); m_canvas->reset_legend_texture(); m_loaded = false; -#if ENABLE_NO_GCODE_TOOLPATHS_REGENERATION } -#endif // ENABLE_NO_GCODE_TOOLPATHS_REGENERATION if (!IsShown() && !force) return; diff --git a/src/slic3r/GUI/GUI_Preview.hpp b/src/slic3r/GUI/GUI_Preview.hpp index 124be934d0..d3cb4e5bfd 100644 --- a/src/slic3r/GUI/GUI_Preview.hpp +++ b/src/slic3r/GUI/GUI_Preview.hpp @@ -129,11 +129,7 @@ public: void set_drop_target(wxDropTarget* target); void load_print(); -#if ENABLE_NO_GCODE_TOOLPATHS_REGENERATION void reload_print(bool force = false, bool keep_volumes = false); -#else - void reload_print(bool force = false); -#endif // ENABLE_NO_GCODE_TOOLPATHS_REGENERATION void refresh_print(); private: diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 6d62e9d842..7a41e06e5f 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1997,11 +1997,9 @@ void Plater::priv::schedule_background_process() this->background_process_timer.Start(500, wxTIMER_ONE_SHOT); // Notify the Canvas3D that something has changed, so it may invalidate some of the layer editing stuff. this->view3D->get_canvas3d()->set_config(this->config); -#if ENABLE_NO_GCODE_TOOLPATHS_REGENERATION // Reset gcode preview this->preview->get_canvas3d()->reset_volumes(); this->preview->get_canvas3d()->reset_legend_texture(); -#endif // ENABLE_NO_GCODE_TOOLPATHS_REGENERATION } void Plater::priv::update_print_volume_state() @@ -2266,12 +2264,8 @@ void Plater::priv::set_current_panel(wxPanel* panel) else if (current_panel == preview) { this->q->reslice(); -#if ENABLE_NO_GCODE_TOOLPATHS_REGENERATION // keeps current gcode preview, if any preview->reload_print(false, true); -#else - preview->reload_print(); -#endif // ENABLE_NO_GCODE_TOOLPATHS_REGENERATION preview->set_canvas_as_dirty(); view_toolbar.select_item("Preview"); }