diff --git a/src/admesh/stl.h b/src/admesh/stl.h index 2c436b426..d682b2434 100644 --- a/src/admesh/stl.h +++ b/src/admesh/stl.h @@ -43,11 +43,21 @@ typedef Eigen::Matrix stl_normal; static_assert(sizeof(stl_vertex) == 12, "size of stl_vertex incorrect"); static_assert(sizeof(stl_normal) == 12, "size of stl_normal incorrect"); -typedef struct { +struct stl_facet { stl_normal normal; stl_vertex vertex[3]; char extra[2]; -} stl_facet; + + stl_facet rotated(const Eigen::Quaternion &rot) { + stl_facet out; + out.normal = rot * this->normal; + out.vertex[0] = rot * this->vertex[0]; + out.vertex[1] = rot * this->vertex[1]; + out.vertex[2] = rot * this->vertex[2]; + return out; + } +}; + #define SIZEOF_STL_FACET 50 static_assert(offsetof(stl_facet, normal) == 0, "stl_facet.normal has correct offset"); diff --git a/src/admesh/stlinit.cpp b/src/admesh/stlinit.cpp index e2939b8af..911f4f5e8 100644 --- a/src/admesh/stlinit.cpp +++ b/src/admesh/stlinit.cpp @@ -41,10 +41,12 @@ stl_open(stl_file *stl, const char *file) { stl_count_facets(stl, file); stl_allocate(stl); stl_read(stl, 0, true); - if (!stl->error) fclose(stl->fp); + if (stl->fp != nullptr) { + fclose(stl->fp); + stl->fp = nullptr; + } } - void stl_initialize(stl_file *stl) { memset(stl, 0, sizeof(stl_file)); @@ -118,7 +120,7 @@ stl_count_facets(stl_file *stl, const char *file) { } /* Read the int following the header. This should contain # of facets */ - bool header_num_faces_read = fread(&header_num_facets, sizeof(uint32_t), 1, stl->fp); + bool header_num_faces_read = fread(&header_num_facets, sizeof(uint32_t), 1, stl->fp) != 0; #ifndef BOOST_LITTLE_ENDIAN // Convert from little endian to big endian. stl_internal_reverse_quads((char*)&header_num_facets, 4); @@ -257,7 +259,6 @@ stl_reallocate(stl_file *stl) { time running this for the stl and therefore we should reset our max and min stats. */ void stl_read(stl_file *stl, int first_facet, bool first) { stl_facet facet; - int i; if (stl->error) return; @@ -268,7 +269,7 @@ void stl_read(stl_file *stl, int first_facet, bool first) { } char normal_buf[3][32]; - for(i = first_facet; i < stl->stats.number_of_facets; i++) { + for(uint32_t i = first_facet; i < stl->stats.number_of_facets; i++) { if(stl->stats.type == binary) /* Read a single facet from a binary .STL file */ { @@ -366,17 +367,19 @@ void stl_facet_stats(stl_file *stl, stl_facet facet, bool &first) } } -void -stl_close(stl_file *stl) { - if (stl->error) return; +void stl_close(stl_file *stl) +{ + assert(stl->fp == nullptr); + assert(stl->heads == nullptr); + assert(stl->tail == nullptr); - if(stl->neighbors_start != NULL) - free(stl->neighbors_start); - if(stl->facet_start != NULL) - free(stl->facet_start); - if(stl->v_indices != NULL) - free(stl->v_indices); - if(stl->v_shared != NULL) - free(stl->v_shared); + if (stl->facet_start != NULL) + free(stl->facet_start); + if (stl->neighbors_start != NULL) + free(stl->neighbors_start); + if (stl->v_indices != NULL) + free(stl->v_indices); + if (stl->v_shared != NULL) + free(stl->v_shared); + memset(stl, 0, sizeof(stl_file)); } - diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index e634dd138..ac4cd73ef 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -897,13 +897,13 @@ BoundingBoxf3 ModelObject::raw_bounding_box() const throw std::invalid_argument("Can't call raw_bounding_box() with no instances"); #endif // !ENABLE_GENERIC_SUBPARTS_PLACEMENT - TriangleMesh vol_mesh(v->mesh); #if ENABLE_GENERIC_SUBPARTS_PLACEMENT - vol_mesh.transform(inst_matrix * v->get_matrix()); - bb.merge(vol_mesh.bounding_box()); + bb.merge(v->mesh.transformed_bounding_box(inst_matrix * v->get_matrix())); #else - vol_mesh.transform(v->get_matrix()); - bb.merge(this->instances.front()->transform_mesh_bounding_box(vol_mesh, true)); + // unmaintaned + assert(false); + // vol_mesh.transform(v->get_matrix()); + // bb.merge(this->instances.front()->transform_mesh_bounding_box(vol_mesh, true)); #endif // ENABLE_GENERIC_SUBPARTS_PLACEMENT } return bb; @@ -920,13 +920,13 @@ BoundingBoxf3 ModelObject::instance_bounding_box(size_t instance_idx, bool dont_ { if (v->is_model_part()) { - TriangleMesh mesh(v->mesh); #if ENABLE_GENERIC_SUBPARTS_PLACEMENT - mesh.transform(inst_matrix * v->get_matrix()); - bb.merge(mesh.bounding_box()); + bb.merge(v->mesh.transformed_bounding_box(inst_matrix * v->get_matrix())); #else - mesh.transform(v->get_matrix()); - bb.merge(this->instances[instance_idx]->transform_mesh_bounding_box(mesh, dont_translate)); + // not maintained + assert(false); + //mesh.transform(v->get_matrix()); + //bb.merge(this->instances[instance_idx]->transform_mesh_bounding_box(mesh, dont_translate)); #endif // ENABLE_GENERIC_SUBPARTS_PLACEMENT } } diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index 44c638a40..2d603661d 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -805,14 +805,7 @@ void TriangleMeshSlicer::slice(const std::vector &z, std::vector* lines, boost::mutex* lines_mutex, const std::vector &z) const { - const stl_facet &facet_orig = this->mesh->stl.facet_start[facet_idx]; - stl_facet facet = facet_orig; - - if (m_use_quaternion) { - facet.vertex[0] = m_quaternion * facet.vertex[0]; - facet.vertex[1] = m_quaternion * facet.vertex[1]; - facet.vertex[2] = m_quaternion * facet.vertex[2]; - } + const stl_facet &facet = m_use_quaternion ? this->mesh->stl.facet_start[facet_idx].rotated(m_quaternion) : this->mesh->stl.facet_start[facet_idx]; // find facet extents const float min_z = fminf(facet.vertex[0](2), fminf(facet.vertex[1](2), facet.vertex[2](2))); @@ -884,7 +877,7 @@ TriangleMeshSlicer::FacetSliceType TriangleMeshSlicer::slice_facet( const int *vertices = this->mesh->stl.v_indices[facet_idx].vertex; int i = (facet.vertex[1].z() == min_z) ? 1 : ((facet.vertex[2].z() == min_z) ? 2 : 0); - // These are used only if the cut plane is inclined: + // These are used only if the cut plane is tilted: stl_vertex rotated_a; stl_vertex rotated_b; @@ -909,10 +902,11 @@ TriangleMeshSlicer::FacetSliceType TriangleMeshSlicer::slice_facet( // Is edge or face aligned with the cutting plane? if (a->z() == slice_z && b->z() == slice_z) { // Edge is horizontal and belongs to the current layer. + // The following rotation of the three vertices may not be efficient, but this branch happens rarely. const stl_vertex &v0 = m_use_quaternion ? stl_vertex(m_quaternion * this->v_scaled_shared[vertices[0]]) : this->v_scaled_shared[vertices[0]]; const stl_vertex &v1 = m_use_quaternion ? stl_vertex(m_quaternion * this->v_scaled_shared[vertices[1]]) : this->v_scaled_shared[vertices[1]]; const stl_vertex &v2 = m_use_quaternion ? stl_vertex(m_quaternion * this->v_scaled_shared[vertices[2]]) : this->v_scaled_shared[vertices[2]]; - const stl_normal &normal = m_use_quaternion ? stl_vertex(m_quaternion * this->mesh->stl.facet_start[facet_idx].normal) : this->mesh->stl.facet_start[facet_idx].normal; + const stl_normal &normal = facet.normal; // We may ignore this edge for slicing purposes, but we may still use it for object cutting. FacetSliceType result = Slicing; if (min_z == max_z) { @@ -1029,7 +1023,7 @@ TriangleMeshSlicer::FacetSliceType TriangleMeshSlicer::slice_facet( i = vertices[2]; assert(i != line_out->a_id && i != line_out->b_id); line_out->edge_type = ((m_use_quaternion ? - m_quaternion * this->v_scaled_shared[i].z() + (m_quaternion * this->v_scaled_shared[i]).z() : this->v_scaled_shared[i].z()) < slice_z) ? feTop : feBottom; } #endif diff --git a/src/libslic3r/TriangleMesh.hpp b/src/libslic3r/TriangleMesh.hpp index a0020255d..4bf5ce039 100644 --- a/src/libslic3r/TriangleMesh.hpp +++ b/src/libslic3r/TriangleMesh.hpp @@ -25,9 +25,10 @@ public: TriangleMesh(const Pointf3s &points, const std::vector &facets); TriangleMesh(const TriangleMesh &other) : repaired(false) { stl_initialize(&this->stl); *this = other; } TriangleMesh(TriangleMesh &&other) : repaired(false) { stl_initialize(&this->stl); this->swap(other); } - ~TriangleMesh() { stl_close(&this->stl); } + ~TriangleMesh() { clear(); } TriangleMesh& operator=(const TriangleMesh &other); TriangleMesh& operator=(TriangleMesh &&other) { this->swap(other); return *this; } + void clear() { stl_close(&this->stl); this->repaired = false; } void swap(TriangleMesh &other) { std::swap(this->stl, other.stl); std::swap(this->repaired, other.repaired); } void ReadSTLFile(const char* input_file) { stl_open(&stl, input_file); } void write_ascii(const char* output_file) { stl_write_ascii(&this->stl, output_file, ""); } @@ -182,7 +183,7 @@ private: // Quaternion that will be used to rotate every facet before the slicing Eigen::Quaternion m_quaternion; // Whether or not the above quaterion should be used - bool m_use_quaternion = false; + bool m_use_quaternion = false; void _slice_do(size_t facet_idx, std::vector* lines, boost::mutex* lines_mutex, const std::vector &z) const; void make_loops(std::vector &lines, Polygons* loops) const; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 96a767c4e..d5da8ac1b 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -3494,10 +3494,13 @@ void GLCanvas3D::_picking_pass() const glsafe(::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)); m_camera_clipping_plane = m_gizmos.get_sla_clipping_plane(); - ::glClipPlane(GL_CLIP_PLANE0, (GLdouble*)m_camera_clipping_plane.get_data()); - ::glEnable(GL_CLIP_PLANE0); + if (! m_use_VBOs) { + ::glClipPlane(GL_CLIP_PLANE0, (GLdouble*)m_camera_clipping_plane.get_data()); + ::glEnable(GL_CLIP_PLANE0); + } _render_volumes(true); - ::glDisable(GL_CLIP_PLANE0); + if (! m_use_VBOs) + ::glDisable(GL_CLIP_PLANE0); m_gizmos.render_current_gizmo_for_picking_pass(m_selection); @@ -3661,7 +3664,7 @@ void GLCanvas3D::_render_objects() const } m_camera_clipping_plane = ClippingPlane::ClipsNothing(); - ::glDisable(GL_LIGHTING); + glsafe(::glDisable(GL_LIGHTING)); } void GLCanvas3D::_render_selection() const diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index 21d1bb3a7..087ec1b01 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -58,6 +58,7 @@ void GLGizmoSlaSupports::set_sla_support_data(ModelObject* model_object, const S { // Cache the bb - it's needed for dealing with the clipping plane quite often // It could be done inside update_mesh but one has to account for scaling of the instance. + //FIXME calling ModelObject::instance_bounding_box() is expensive! m_active_instance_bb_radius = m_model_object->instance_bounding_box(m_active_instance).radius(); if (is_mesh_update_necessary()) { @@ -123,6 +124,11 @@ void GLGizmoSlaSupports::render_clipping_plane(const Selection& selection, const || m_old_direction_to_camera != direction_to_camera) { std::vector list_of_expolys; + if (! m_tms) { + m_tms.reset(new TriangleMeshSlicer); + m_tms->init(const_cast(&m_mesh), [](){}); + } + m_tms->set_up_direction(up); m_tms->slice(std::vector{height_mesh}, 0.f, &list_of_expolys, [](){}); m_triangles = triangulate_expolygons_2f(list_of_expolys[0]); @@ -131,22 +137,23 @@ void GLGizmoSlaSupports::render_clipping_plane(const Selection& selection, const m_old_clipping_plane_distance = m_clipping_plane_distance; } - ::glPushMatrix(); - ::glTranslated(0.0, 0.0, m_z_shift); - ::glMultMatrixf(instance_matrix.data()); - Eigen::Quaternionf q; - q.setFromTwoVectors(Vec3f::UnitZ(), up); - Eigen::AngleAxisf aa(q); - ::glRotatef(aa.angle() * (180./M_PI), aa.axis()(0), aa.axis()(1), aa.axis()(2)); - ::glTranslatef(0.f, 0.f, -0.001f); // to make sure the cut is safely beyond the near clipping plane - - ::glBegin(GL_TRIANGLES); - ::glColor3f(1.0f, 0.37f, 0.0f); - for (const Vec2f& point : m_triangles) - ::glVertex3f(point(0), point(1), height_mesh); - ::glEnd(); - - ::glPopMatrix(); + if (! m_triangles.empty()) { + ::glPushMatrix(); + ::glTranslated(0.0, 0.0, m_z_shift); + ::glMultMatrixf(instance_matrix.data()); + Eigen::Quaternionf q; + q.setFromTwoVectors(Vec3f::UnitZ(), up); + Eigen::AngleAxisf aa(q); + ::glRotatef(aa.angle() * (180./M_PI), aa.axis()(0), aa.axis()(1), aa.axis()(2)); + ::glTranslatef(0.f, 0.f, -0.001f); // to make sure the cut is safely beyond the near clipping plane + ::glColor3f(1.0f, 0.37f, 0.0f); + ::glBegin(GL_TRIANGLES); + ::glColor3f(1.0f, 0.37f, 0.0f); + for (const Vec2f& point : m_triangles) + ::glVertex3f(point(0), point(1), height_mesh); + ::glEnd(); + ::glPopMatrix(); + } } @@ -344,9 +351,6 @@ void GLGizmoSlaSupports::update_mesh() m_AABB = igl::AABB(); m_AABB.init(m_V, m_F); - - m_tms.reset(new TriangleMeshSlicer); - m_tms->init(&m_mesh, [](){}); } // Unprojects the mouse position on the mesh and return the hit point and normal of the facet. @@ -969,6 +973,12 @@ void GLGizmoSlaSupports::on_set_state() m_editing_mode = false; // so it is not active next time the gizmo opens m_editing_mode_cache.clear(); m_clipping_plane_distance = 0.f; + // Release copy of the mesh, triangle slicer and the AABB spatial search structure. + m_mesh.clear(); + m_AABB.deinit(); + m_V = Eigen::MatrixXf(); + m_F = Eigen::MatrixXi(); + m_tms.reset(nullptr); }); } m_old_state = m_state;