From eff8dd1ae53b06108f995b9560a4e44912ba8b9c Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Wed, 3 Apr 2019 09:05:52 +0200 Subject: [PATCH 01/23] Fixed negative values for size shown in the sidebar matrix fields when mirroring is applied --- src/slic3r/GUI/GUI_ObjectManipulation.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index 6c8fdcab73..61e98d5425 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -179,7 +179,7 @@ void ObjectManipulation::update_settings_value(const Selection& selection) changed_box = true; } if (changed_box || !m_cache.instance.matches_instance(instance_idx) || !m_cache.scale.isApprox(100.0 * m_new_scale)) - m_new_size = volume->get_instance_transformation().get_matrix(true, true) * m_cache.instance.box_size; + m_new_size = (volume->get_instance_transformation().get_matrix(true, true) * m_cache.instance.box_size).cwiseAbs(); } else // this should never happen @@ -209,7 +209,7 @@ void ObjectManipulation::update_settings_value(const Selection& selection) m_new_position = volume->get_volume_offset(); m_new_rotation = volume->get_volume_rotation(); m_new_scale = volume->get_volume_scaling_factor(); - m_new_size = volume->get_volume_transformation().get_matrix(true, true) * volume->bounding_box.size(); + m_new_size = (volume->get_volume_transformation().get_matrix(true, true) * volume->bounding_box.size()).cwiseAbs(); m_new_enabled = true; } else if (wxGetApp().obj_list()->multiple_selection()) From 7b414fe34a56885789661e44719975a1ce4bd4b4 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Wed, 3 Apr 2019 10:17:57 +0200 Subject: [PATCH 02/23] Get rid of unnecessary copies and moves in ClipperUtils This is up to a code review session. --- src/libslic3r/ClipperUtils.cpp | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/libslic3r/ClipperUtils.cpp b/src/libslic3r/ClipperUtils.cpp index f00e908ce5..86b4ee4475 100644 --- a/src/libslic3r/ClipperUtils.cpp +++ b/src/libslic3r/ClipperUtils.cpp @@ -120,7 +120,7 @@ Slic3r::Polygon ClipperPath_to_Slic3rPolygon(const ClipperLib::Path &input) { Polygon retval; for (ClipperLib::Path::const_iterator pit = input.begin(); pit != input.end(); ++pit) - retval.points.push_back(Point( (*pit).X, (*pit).Y )); + retval.points.emplace_back(pit->X, pit->Y); return retval; } @@ -128,7 +128,7 @@ Slic3r::Polyline ClipperPath_to_Slic3rPolyline(const ClipperLib::Path &input) { Polyline retval; for (ClipperLib::Path::const_iterator pit = input.begin(); pit != input.end(); ++pit) - retval.points.push_back(Point( (*pit).X, (*pit).Y )); + retval.points.emplace_back(pit->X, pit->Y); return retval; } @@ -137,7 +137,7 @@ Slic3r::Polygons ClipperPaths_to_Slic3rPolygons(const ClipperLib::Paths &input) Slic3r::Polygons retval; retval.reserve(input.size()); for (ClipperLib::Paths::const_iterator it = input.begin(); it != input.end(); ++it) - retval.push_back(ClipperPath_to_Slic3rPolygon(*it)); + retval.emplace_back(ClipperPath_to_Slic3rPolygon(*it)); return retval; } @@ -146,7 +146,7 @@ Slic3r::Polylines ClipperPaths_to_Slic3rPolylines(const ClipperLib::Paths &input Slic3r::Polylines retval; retval.reserve(input.size()); for (ClipperLib::Paths::const_iterator it = input.begin(); it != input.end(); ++it) - retval.push_back(ClipperPath_to_Slic3rPolyline(*it)); + retval.emplace_back(ClipperPath_to_Slic3rPolyline(*it)); return retval; } @@ -171,7 +171,7 @@ Slic3rMultiPoint_to_ClipperPath(const MultiPoint &input) { ClipperLib::Path retval; for (Points::const_iterator pit = input.points.begin(); pit != input.points.end(); ++pit) - retval.push_back(ClipperLib::IntPoint( (*pit)(0), (*pit)(1) )); + retval.emplace_back((*pit)(0), (*pit)(1)); return retval; } @@ -181,7 +181,7 @@ Slic3rMultiPoint_to_ClipperPath_reversed(const Slic3r::MultiPoint &input) ClipperLib::Path output; output.reserve(input.points.size()); for (Slic3r::Points::const_reverse_iterator pit = input.points.rbegin(); pit != input.points.rend(); ++pit) - output.push_back(ClipperLib::IntPoint( (*pit)(0), (*pit)(1) )); + output.emplace_back((*pit)(0), (*pit)(1)); return output; } @@ -189,7 +189,7 @@ ClipperLib::Paths Slic3rMultiPoints_to_ClipperPaths(const Polygons &input) { ClipperLib::Paths retval; for (Polygons::const_iterator it = input.begin(); it != input.end(); ++it) - retval.push_back(Slic3rMultiPoint_to_ClipperPath(*it)); + retval.emplace_back(Slic3rMultiPoint_to_ClipperPath(*it)); return retval; } @@ -197,7 +197,7 @@ ClipperLib::Paths Slic3rMultiPoints_to_ClipperPaths(const Polylines &input) { ClipperLib::Paths retval; for (Polylines::const_iterator it = input.begin(); it != input.end(); ++it) - retval.push_back(Slic3rMultiPoint_to_ClipperPath(*it)); + retval.emplace_back(Slic3rMultiPoint_to_ClipperPath(*it)); return retval; } @@ -226,7 +226,7 @@ ClipperLib::Paths _offset(ClipperLib::Paths &&input, ClipperLib::EndType endType ClipperLib::Paths _offset(ClipperLib::Path &&input, ClipperLib::EndType endType, const float delta, ClipperLib::JoinType joinType, double miterLimit) { ClipperLib::Paths paths; - paths.push_back(std::move(input)); + paths.emplace_back(std::move(input)); return _offset(std::move(paths), endType, delta, joinType, miterLimit); } @@ -585,7 +585,7 @@ Polylines _clipper_pl(ClipperLib::ClipType clipType, const Polygons &subject, co Polylines polylines; polylines.reserve(subject.size()); for (Polygons::const_iterator polygon = subject.begin(); polygon != subject.end(); ++polygon) - polylines.push_back(*polygon); // implicit call to split_at_first_point() + polylines.emplace_back(polygon->operator Polyline()); // implicit call to split_at_first_point() // perform clipping Polylines retval = _clipper_pl(clipType, polylines, clip, safety_offset_); @@ -643,7 +643,7 @@ _clipper_ln(ClipperLib::ClipType clipType, const Lines &subject, const Polygons // convert Polylines to Lines Lines retval; for (Polylines::const_iterator polyline = polylines.begin(); polyline != polylines.end(); ++polyline) - retval.push_back(*polyline); + retval.emplace_back(std::move(*polyline)); return retval; } @@ -673,7 +673,7 @@ void traverse_pt(ClipperLib::PolyNodes &nodes, Polygons* retval) ordering_points.reserve(nodes.size()); for (ClipperLib::PolyNodes::const_iterator it = nodes.begin(); it != nodes.end(); ++it) { Point p((*it)->Contour.front().X, (*it)->Contour.front().Y); - ordering_points.push_back(p); + ordering_points.emplace_back(p); } // perform the ordering @@ -684,7 +684,7 @@ void traverse_pt(ClipperLib::PolyNodes &nodes, Polygons* retval) for (ClipperLib::PolyNodes::iterator it = ordered_nodes.begin(); it != ordered_nodes.end(); ++it) { // traverse the next depth traverse_pt((*it)->Childs, retval); - retval->push_back(ClipperPath_to_Slic3rPolygon((*it)->Contour)); + retval->emplace_back(ClipperPath_to_Slic3rPolygon((*it)->Contour)); if ((*it)->IsHole()) retval->back().reverse(); // ccw } } @@ -791,8 +791,8 @@ Polygons top_level_islands(const Slic3r::Polygons &polygons) Polygons out; out.reserve(polytree.ChildCount()); for (int i = 0; i < polytree.ChildCount(); ++i) - out.push_back(ClipperPath_to_Slic3rPolygon(polytree.Childs[i]->Contour)); + out.emplace_back(ClipperPath_to_Slic3rPolygon(polytree.Childs[i]->Contour)); return out; } -} \ No newline at end of file +} From 32af3ff3c052c2e574b2595dc22a0d792c84a566 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Wed, 3 Apr 2019 10:29:27 +0200 Subject: [PATCH 03/23] Remove unnecessary reversals of print polygons. --- src/libslic3r/SLAPrint.cpp | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 7dc920517b..809b32d901 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -1041,31 +1041,37 @@ void SLAPrint::process() { ClipperPolygon poly; + // We need to reverse if flpXY OR is_lefthanded is true but + // not if both are true which is a logical inequality (XOR) + bool needreverse = flpXY != is_lefthanded; + // should be a move poly.Contour.reserve(polygon.contour.size() + 1); - for(auto& p : polygon.contour.points) - poly.Contour.emplace_back(p.x(), p.y()); - - auto pfirst = poly.Contour.front(); - poly.Contour.emplace_back(pfirst); + auto& cntr = polygon.contour.points; + if(needreverse) + for(auto it = cntr.rbegin(); it != cntr.rend(); ++it) + poly.Contour.emplace_back(it->x(), it->y()); + else + for(auto& p : cntr) + poly.Contour.emplace_back(p.x(), p.y()); for(auto& h : polygon.holes) { poly.Holes.emplace_back(); auto& hole = poly.Holes.back(); hole.reserve(h.points.size() + 1); - for(auto& p : h.points) hole.emplace_back(p.x(), p.y()); - auto pfirst = hole.front(); hole.emplace_back(pfirst); + if(needreverse) + for(auto& p : h.points) + hole.emplace_back(p.x(), p.y()); + else + for(auto it = h.points.rbegin(); it != h.points.rend(); ++it) + hole.emplace_back(it->x(), it->y()); } if(is_lefthanded) { for(auto& p : poly.Contour) p.X = -p.X; - std::reverse(poly.Contour.begin(), poly.Contour.end()); - for(auto& h : poly.Holes) { - for(auto& p : h) p.X = -p.X; - std::reverse(h.begin(), h.end()); - } + for(auto& h : poly.Holes) for(auto& p : h) p.X = -p.X; } sl::rotate(poly, double(instances[i].rotation)); @@ -1074,12 +1080,7 @@ void SLAPrint::process() if (flpXY) { for(auto& p : poly.Contour) std::swap(p.X, p.Y); - std::reverse(poly.Contour.begin(), poly.Contour.end()); - - for(auto& h : poly.Holes) { - for(auto& p : h) std::swap(p.X, p.Y); - std::reverse(h.begin(), h.end()); - } + for(auto& h : poly.Holes) for(auto& p : h) std::swap(p.X, p.Y); } polygons.emplace_back(std::move(poly)); From 2269e1b1839fcc15c6b0a39cd37bb2794e102774 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 3 Apr 2019 10:36:54 +0200 Subject: [PATCH 04/23] Deliberately setting the SLA dialog a bit too large It is not possible to precisely calculate actual window size before the rendering, so I added a safety margin. It would be nicer to let the window autoscale and only use the inflated dimension for possible moving the window upward to prevent collision with the bottom panel, but... ImGui autoscaling does not work properly for some reason (the window size autoscales only after a mouse move), so this is a workaround. --- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index 75f13cdcf0..5be7f9100a 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -565,12 +565,12 @@ void GLGizmoSlaSupports::on_render_input_window(float x, float y, float bottom_l RENDER_AGAIN: m_imgui->set_next_window_pos(x, y, ImGuiCond_Always); - const ImVec2 window_size(m_imgui->scaled(15.f, 16.5f)); + const ImVec2 window_size(m_imgui->scaled(17.f, 18.f)); ImGui::SetNextWindowPos(ImVec2(x, y - std::max(0.f, y+window_size.y-bottom_limit) )); ImGui::SetNextWindowSize(ImVec2(window_size)); m_imgui->set_next_window_bg_alpha(0.5f); - m_imgui->begin(on_get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); + m_imgui->begin(on_get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse); ImGui::PushItemWidth(100.0f); From 382326ffc85620edbe320e956439caccca9df271 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Wed, 3 Apr 2019 11:12:03 +0200 Subject: [PATCH 05/23] Fixed FFF slicing of meshes with left hand oriented transformations applied. Slight optimization of FFF slicing - optimized copy of an object with just a single volume. --- src/libslic3r/PrintObject.cpp | 17 +++++++++-------- src/libslic3r/TriangleMesh.cpp | 7 ++++++- src/libslic3r/TriangleMesh.hpp | 2 +- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 6c04c7781a..42c6fbf754 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -1790,15 +1790,16 @@ std::vector PrintObject::_slice_volumes(const std::vector &z, if (! volumes.empty()) { // Compose mesh. //FIXME better to perform slicing over each volume separately and then to use a Boolean operation to merge them. - TriangleMesh mesh; - for (const ModelVolume *v : volumes) - { - TriangleMesh vol_mesh(v->mesh); - vol_mesh.transform(v->get_matrix()); + TriangleMesh mesh(volumes.front()->mesh); + mesh.transform(volumes.front()->get_matrix(), true); + for (size_t idx_volume = 1; idx_volume < volumes.size(); ++ idx_volume) { + const ModelVolume &model_volume = *volumes[idx_volume]; + TriangleMesh vol_mesh(model_volume.mesh); + vol_mesh.transform(model_volume.get_matrix(), true); mesh.merge(vol_mesh); } if (mesh.stl.stats.number_of_facets > 0) { - mesh.transform(m_trafo); + mesh.transform(m_trafo, true); // apply XY shift mesh.translate(- unscale(m_copies_shift(0)), - unscale(m_copies_shift(1)), 0); // perform actual slicing @@ -1819,9 +1820,9 @@ std::vector PrintObject::_slice_volume(const std::vector &z, // Compose mesh. //FIXME better to perform slicing over each volume separately and then to use a Boolean operation to merge them. TriangleMesh mesh(volume.mesh); - mesh.transform(volume.get_matrix()); + mesh.transform(volume.get_matrix(), true); if (mesh.stl.stats.number_of_facets > 0) { - mesh.transform(m_trafo); + mesh.transform(m_trafo, true); // apply XY shift mesh.translate(- unscale(m_copies_shift(0)), - unscale(m_copies_shift(1)), 0); // perform actual slicing diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index c145380c96..0d9a79978d 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -314,10 +314,15 @@ void TriangleMesh::mirror(const Axis &axis) stl_invalidate_shared_vertices(&this->stl); } -void TriangleMesh::transform(const Transform3d& t) +void TriangleMesh::transform(const Transform3d& t, bool fix_left_handed) { stl_transform(&stl, t); stl_invalidate_shared_vertices(&stl); + if (fix_left_handed && t.matrix().block(0, 0, 3, 3).determinant() < 0.) { + // Left handed transformation is being applied. It is a good idea to flip the faces and their normals. + this->repair(); + stl_reverse_all_facets(&stl); + } } void TriangleMesh::align_to_origin() diff --git a/src/libslic3r/TriangleMesh.hpp b/src/libslic3r/TriangleMesh.hpp index a65a4be75b..527846f9d9 100644 --- a/src/libslic3r/TriangleMesh.hpp +++ b/src/libslic3r/TriangleMesh.hpp @@ -49,7 +49,7 @@ public: void mirror_x() { this->mirror(X); } void mirror_y() { this->mirror(Y); } void mirror_z() { this->mirror(Z); } - void transform(const Transform3d& t); + void transform(const Transform3d& t, bool fix_left_handed = false); void align_to_origin(); void rotate(double angle, Point* center); TriangleMeshPtrs split() const; From 1534356268a5ef5a190d3790f4a756d1307d82cc Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Wed, 3 Apr 2019 11:17:15 +0200 Subject: [PATCH 06/23] Call Line conversion operator explicitly. --- src/libslic3r/ClipperUtils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libslic3r/ClipperUtils.cpp b/src/libslic3r/ClipperUtils.cpp index 86b4ee4475..4c6e542f4d 100644 --- a/src/libslic3r/ClipperUtils.cpp +++ b/src/libslic3r/ClipperUtils.cpp @@ -643,7 +643,7 @@ _clipper_ln(ClipperLib::ClipType clipType, const Lines &subject, const Polygons // convert Polylines to Lines Lines retval; for (Polylines::const_iterator polyline = polylines.begin(); polyline != polylines.end(); ++polyline) - retval.emplace_back(std::move(*polyline)); + retval.emplace_back(polyline->operator Line()); return retval; } From 527c213b57f4279615d34ee5c59860c01209c0c4 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Wed, 3 Apr 2019 12:07:58 +0200 Subject: [PATCH 07/23] Fixed cutting of objects in left oriented coordinate space. Removed some spurious debugging printf. --- src/libslic3r/Model.cpp | 5 +++-- src/slic3r/GUI/GUI_ObjectList.cpp | 1 - 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index b5b9a008d0..ba898d9d52 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -1187,8 +1187,9 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b else { TriangleMesh upper_mesh, lower_mesh; - // Transform the mesh by the combined transformation matrix - volume->mesh.transform(instance_matrix * volume_matrix); + // Transform the mesh by the combined transformation matrix. + // Flip the triangles in case the composite transformation is left handed. + volume->mesh.transform(instance_matrix * volume_matrix, true); // Perform cut TriangleMeshSlicer tms(&volume->mesh); diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 224bb802eb..c0dcc659d9 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -507,7 +507,6 @@ void ObjectList::key_event(wxKeyEvent& event) || event.GetKeyCode() == WXK_BACK #endif //__WXOSX__ ) { - printf("WXK_BACK\n"); remove(); } else if (wxGetKeyState(wxKeyCode('A')) && wxGetKeyState(WXK_SHIFT)) From 7d488e3424b76b4e4d66fd7d49c7d8971f20429d Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Wed, 3 Apr 2019 12:45:06 +0200 Subject: [PATCH 08/23] Added call to schedule_background_process() when deleting modifier attribute --- src/slic3r/GUI/GUI_ObjectSettings.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/GUI_ObjectSettings.cpp b/src/slic3r/GUI/GUI_ObjectSettings.cpp index 4c0879ad3c..cd995bc094 100644 --- a/src/slic3r/GUI/GUI_ObjectSettings.cpp +++ b/src/slic3r/GUI/GUI_ObjectSettings.cpp @@ -85,7 +85,8 @@ void ObjectSettings::update_settings_list() #endif // __WXMSW__ btn->Bind(wxEVT_BUTTON, [opt_key, config, this](wxEvent &event) { config->erase(opt_key); - wxTheApp->CallAfter([this]() { + wxGetApp().obj_list()->part_settings_changed(); + wxTheApp->CallAfter([this]() { wxWindowUpdateLocker noUpdates(m_parent); update_settings_list(); m_parent->Layout(); From 69027b53fd8689ec2c9c7352e8580cd3fea76adf Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 3 Apr 2019 14:44:15 +0200 Subject: [PATCH 09/23] SLA gizmo now allows to deselect a point --- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 21 ++++++++++++++++++-- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp | 1 + 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index 5be7f9100a..2264c541e8 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -330,8 +330,12 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous m_canvas_width = m_parent.get_canvas_size().get_width(); m_canvas_height = m_parent.get_canvas_size().get_height(); } - else - select_point(m_hover_id); + else { + if (m_editing_mode_cache[m_hover_id].selected) + unselect_point(m_hover_id); + else + select_point(m_hover_id); + } return true; } @@ -791,6 +795,19 @@ void GLGizmoSlaSupports::select_point(int i) } +void GLGizmoSlaSupports::unselect_point(int i) +{ + m_editing_mode_cache[i].selected = false; + m_selection_empty = true; + for (const CacheEntry& ce : m_editing_mode_cache) { + if (ce.selected) { + m_selection_empty = false; + break; + } + } +} + + void GLGizmoSlaSupports::editing_mode_discard_changes() { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp index 7e8113774b..bb3cf06ce4 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp @@ -93,6 +93,7 @@ private: NoPoints, }; void select_point(int i); + void unselect_point(int i); void editing_mode_apply_changes(); void editing_mode_discard_changes(); void editing_mode_reload_cache(); From 28ec3415eb45de9827bad22d5309456045f7b26e Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Wed, 3 Apr 2019 15:28:09 +0200 Subject: [PATCH 10/23] Keep instance mode selection when at least one instance is already selected --- src/slic3r/GUI/Selection.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 7103ca12dc..ca245029c1 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -108,21 +108,26 @@ void Selection::add(unsigned int volume_idx, bool as_single_selection) if (is_wipe_tower() && volume->is_wipe_tower) return; + bool keep_instance_mode = (m_mode == Instance) && !as_single_selection && (is_single_full_instance() || is_multiple_full_instance()); + // resets the current list if needed bool needs_reset = as_single_selection; needs_reset |= volume->is_wipe_tower; needs_reset |= is_wipe_tower() && !volume->is_wipe_tower; - needs_reset |= !is_modifier() && volume->is_modifier; + needs_reset |= !keep_instance_mode && !is_modifier() && volume->is_modifier; needs_reset |= is_modifier() && !volume->is_modifier; if (needs_reset) clear(); if (!contains_volume(volume_idx)) - m_mode = volume->is_modifier ? Volume : Instance; + { + if (!keep_instance_mode) + m_mode = volume->is_modifier ? Volume : Instance; + } else - // keep current mode - return; + // keep current mode + return; switch (m_mode) { From c99fe20504ea72e06c35620e7e779c8f5a1c32b7 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Wed, 3 Apr 2019 16:31:40 +0200 Subject: [PATCH 11/23] imgui: Yet another font size fix --- src/slic3r/GUI/ImGuiWrapper.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index 1b4d4edf9e..8a6a71b1b9 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -340,13 +340,11 @@ bool ImGuiWrapper::want_any_input() const void ImGuiWrapper::init_font() { - const float font_size = m_font_size * m_style_scaling; - destroy_font(); ImGuiIO& io = ImGui::GetIO(); io.Fonts->Clear(); - ImFont* font = io.Fonts->AddFontFromFileTTF((Slic3r::resources_dir() + "/fonts/NotoSans-Regular.ttf").c_str(), font_size, nullptr, m_glyph_ranges); + ImFont* font = io.Fonts->AddFontFromFileTTF((Slic3r::resources_dir() + "/fonts/NotoSans-Regular.ttf").c_str(), m_font_size, nullptr, m_glyph_ranges); if (font == nullptr) { font = io.Fonts->AddFontDefault(); if (font == nullptr) { From 703b9bda324d656182e17cdf95b82abf358819e6 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Wed, 3 Apr 2019 16:39:28 +0200 Subject: [PATCH 12/23] imgui: Fix scaling --- src/slic3r/GUI/ImGuiWrapper.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/ImGuiWrapper.hpp b/src/slic3r/GUI/ImGuiWrapper.hpp index c1bf491e14..b593054c4a 100644 --- a/src/slic3r/GUI/ImGuiWrapper.hpp +++ b/src/slic3r/GUI/ImGuiWrapper.hpp @@ -45,8 +45,8 @@ public: void new_frame(); void render(); - float scaled(float x) const { return x * m_font_size * m_style_scaling; } - ImVec2 scaled(float x, float y) const { return ImVec2(x * m_font_size * m_style_scaling, y * m_font_size * m_style_scaling); } + float scaled(float x) const { return x * m_font_size; } + ImVec2 scaled(float x, float y) const { return ImVec2(x * m_font_size, y * m_font_size); } ImVec2 calc_text_size(const wxString &text); void set_next_window_pos(float x, float y, int flag); From a7318dbe197d0a05d368865fe169751f07840cd7 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 4 Apr 2019 09:01:47 +0200 Subject: [PATCH 13/23] Keeps non selected instances as disabled for any combination of current instance's volumes selection --- src/slic3r/GUI/Selection.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index ca245029c1..db25e6332f 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -1147,16 +1147,12 @@ void Selection::_update_type() } if (modifiers_count == 0) - { m_type = MultipleVolume; - requires_disable = true; - } else if (modifiers_count == (unsigned int)m_list.size()) - { m_type = MultipleModifier; - requires_disable = true; - } } + + requires_disable = true; } else if ((selected_instances_count > 1) && (selected_instances_count * volumes_count == (unsigned int)m_list.size())) { From 8e63a6ba97167965764dcbaa85ea65a219170470 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Thu, 4 Apr 2019 09:02:53 +0200 Subject: [PATCH 14/23] First batch of SVG icons. Support for loading SVG icons into a BitmapCache. --- resources/icons/cog.svg | 17 ++++++++++++++ resources/icons/cooling.svg | 25 ++++++++++++++++++++ resources/icons/funnel.svg | 15 ++++++++++++ resources/icons/infill.svg | 33 +++++++++++++++++++++++++++ resources/icons/note.svg | 25 ++++++++++++++++++++ resources/icons/output+page_white.svg | 21 +++++++++++++++++ resources/icons/printer.svg | 14 ++++++++++++ resources/icons/skirt+brim.svg | 19 +++++++++++++++ resources/icons/spool.svg | 21 +++++++++++++++++ resources/icons/support.svg | 25 ++++++++++++++++++++ resources/icons/time.svg | 16 +++++++++++++ resources/icons/wrench.svg | 24 +++++++++++++++++++ 12 files changed, 255 insertions(+) create mode 100644 resources/icons/cog.svg create mode 100644 resources/icons/cooling.svg create mode 100644 resources/icons/funnel.svg create mode 100644 resources/icons/infill.svg create mode 100644 resources/icons/note.svg create mode 100644 resources/icons/output+page_white.svg create mode 100644 resources/icons/printer.svg create mode 100644 resources/icons/skirt+brim.svg create mode 100644 resources/icons/spool.svg create mode 100644 resources/icons/support.svg create mode 100644 resources/icons/time.svg create mode 100644 resources/icons/wrench.svg diff --git a/resources/icons/cog.svg b/resources/icons/cog.svg new file mode 100644 index 0000000000..07adb66101 --- /dev/null +++ b/resources/icons/cog.svg @@ -0,0 +1,17 @@ + + + + + + + + diff --git a/resources/icons/cooling.svg b/resources/icons/cooling.svg new file mode 100644 index 0000000000..b5d80e434a --- /dev/null +++ b/resources/icons/cooling.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + diff --git a/resources/icons/funnel.svg b/resources/icons/funnel.svg new file mode 100644 index 0000000000..8877722e33 --- /dev/null +++ b/resources/icons/funnel.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + diff --git a/resources/icons/infill.svg b/resources/icons/infill.svg new file mode 100644 index 0000000000..fcb1f99c9e --- /dev/null +++ b/resources/icons/infill.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/icons/note.svg b/resources/icons/note.svg new file mode 100644 index 0000000000..c142142010 --- /dev/null +++ b/resources/icons/note.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/icons/output+page_white.svg b/resources/icons/output+page_white.svg new file mode 100644 index 0000000000..ec1518f252 --- /dev/null +++ b/resources/icons/output+page_white.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + diff --git a/resources/icons/printer.svg b/resources/icons/printer.svg new file mode 100644 index 0000000000..91e103ec70 --- /dev/null +++ b/resources/icons/printer.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + diff --git a/resources/icons/skirt+brim.svg b/resources/icons/skirt+brim.svg new file mode 100644 index 0000000000..9242761b61 --- /dev/null +++ b/resources/icons/skirt+brim.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + diff --git a/resources/icons/spool.svg b/resources/icons/spool.svg new file mode 100644 index 0000000000..8403659381 --- /dev/null +++ b/resources/icons/spool.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/resources/icons/support.svg b/resources/icons/support.svg new file mode 100644 index 0000000000..65c7592c83 --- /dev/null +++ b/resources/icons/support.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/icons/time.svg b/resources/icons/time.svg new file mode 100644 index 0000000000..5d8f23cfc3 --- /dev/null +++ b/resources/icons/time.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + diff --git a/resources/icons/wrench.svg b/resources/icons/wrench.svg new file mode 100644 index 0000000000..7966da8d8f --- /dev/null +++ b/resources/icons/wrench.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + From c29f7bc1470e6a249621c65fc15cea1eb29eceef Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 2 Apr 2019 09:03:45 +0200 Subject: [PATCH 15/23] Fix of #2044 Added sorting by z of the preview data used to generate the gcode preview because there can be shuffling in case of sequential printing --- src/libslic3r/GCode/Analyzer.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/libslic3r/GCode/Analyzer.cpp b/src/libslic3r/GCode/Analyzer.cpp index d1ad4f5752..321d9a3427 100644 --- a/src/libslic3r/GCode/Analyzer.cpp +++ b/src/libslic3r/GCode/Analyzer.cpp @@ -776,6 +776,9 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& previ preview_data.ranges.width.update_from(width_range); preview_data.ranges.feedrate.update_from(feedrate_range); preview_data.ranges.volumetric_rate.update_from(volumetric_rate_range); + + // we need to sort the layers by their z as they can be shuffled in case of sequential prints + std::sort(preview_data.extrusion.layers.begin(), preview_data.extrusion.layers.end(), [](const GCodePreviewData::Extrusion::Layer& l1, const GCodePreviewData::Extrusion::Layer& l2)->bool { return l1.z < l2.z; }); } void GCodeAnalyzer::_calc_gcode_preview_travel(GCodePreviewData& preview_data, std::function cancel_callback) @@ -855,6 +858,11 @@ void GCodeAnalyzer::_calc_gcode_preview_travel(GCodePreviewData& preview_data, s preview_data.ranges.height.update_from(height_range); preview_data.ranges.width.update_from(width_range); preview_data.ranges.feedrate.update_from(feedrate_range); + + // we need to sort the polylines by their min z as they can be shuffled in case of sequential prints + std::sort(preview_data.travel.polylines.begin(), preview_data.travel.polylines.end(), + [](const GCodePreviewData::Travel::Polyline& p1, const GCodePreviewData::Travel::Polyline& p2)->bool + { return unscale(p1.polyline.bounding_box().min(2)) < unscale(p2.polyline.bounding_box().min(2)); }); } void GCodeAnalyzer::_calc_gcode_preview_retractions(GCodePreviewData& preview_data, std::function cancel_callback) @@ -877,6 +885,11 @@ void GCodeAnalyzer::_calc_gcode_preview_retractions(GCodePreviewData& preview_da Vec3crd position(scale_(move.start_position.x()), scale_(move.start_position.y()), scale_(move.start_position.z())); preview_data.retraction.positions.emplace_back(position, move.data.width, move.data.height); } + + // we need to sort the positions by their z as they can be shuffled in case of sequential prints + std::sort(preview_data.retraction.positions.begin(), preview_data.retraction.positions.end(), + [](const GCodePreviewData::Retraction::Position& p1, const GCodePreviewData::Retraction::Position& p2)->bool + { return unscale(p1.position(2)) < unscale(p2.position(2)); }); } void GCodeAnalyzer::_calc_gcode_preview_unretractions(GCodePreviewData& preview_data, std::function cancel_callback) @@ -899,6 +912,11 @@ void GCodeAnalyzer::_calc_gcode_preview_unretractions(GCodePreviewData& preview_ Vec3crd position(scale_(move.start_position.x()), scale_(move.start_position.y()), scale_(move.start_position.z())); preview_data.unretraction.positions.emplace_back(position, move.data.width, move.data.height); } + + // we need to sort the positions by their z as they can be shuffled in case of sequential prints + std::sort(preview_data.unretraction.positions.begin(), preview_data.unretraction.positions.end(), + [](const GCodePreviewData::Retraction::Position& p1, const GCodePreviewData::Retraction::Position& p2)->bool + { return unscale(p1.position(2)) < unscale(p2.position(2)); }); } // Return an estimate of the memory consumed by the time estimator. From a36bdefda51833f7c3ac63d2ce1870fcea671d34 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Thu, 4 Apr 2019 09:20:11 +0200 Subject: [PATCH 16/23] Code to load SVG icons into the BitmapCache class. --- resources/icons/layers.svg | 40 +++++++++--------- src/slic3r/GUI/BitmapCache.cpp | 73 +++++++++++++++++++++++++++++++++ src/slic3r/GUI/BitmapCache.hpp | 6 +++ src/slic3r/GUI/GLTexture.cpp | 5 +-- src/slic3r/GUI/Tab.cpp | 2 +- src/slic3r/GUI/wxExtensions.cpp | 23 +++++------ 6 files changed, 113 insertions(+), 36 deletions(-) diff --git a/resources/icons/layers.svg b/resources/icons/layers.svg index 7718a8cbd5..da5dec21d5 100644 --- a/resources/icons/layers.svg +++ b/resources/icons/layers.svg @@ -1,25 +1,27 @@ - + - + viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve"> + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + diff --git a/src/slic3r/GUI/BitmapCache.cpp b/src/slic3r/GUI/BitmapCache.cpp index 16baa1629e..4c7f999ffc 100644 --- a/src/slic3r/GUI/BitmapCache.cpp +++ b/src/slic3r/GUI/BitmapCache.cpp @@ -1,5 +1,7 @@ #include "BitmapCache.hpp" +#include "libslic3r/Utils.hpp" + #if ! defined(WIN32) && ! defined(__APPLE__) #define BROKEN_ALPHA #endif @@ -9,6 +11,11 @@ #include #endif /* BROKEN_ALPHA */ +#define NANOSVG_IMPLEMENTATION +#include "nanosvg/nanosvg.h" +#define NANOSVGRAST_IMPLEMENTATION +#include "nanosvg/nanosvgrast.h" + namespace Slic3r { namespace GUI { void BitmapCache::clear() @@ -155,6 +162,72 @@ wxBitmap* BitmapCache::insert(const std::string &bitmap_key, const wxBitmap *beg #endif } +wxBitmap* BitmapCache::insert_raw_rgba(const std::string &bitmap_key, unsigned int width, unsigned int height, const unsigned char *raw_data) +{ + wxImage image(width, height); + image.InitAlpha(); + unsigned char *rgb = image.GetData(); + unsigned char *alpha = image.GetAlpha(); + unsigned int pixels = width * height; + for (unsigned int i = 0; i < pixels; ++ i) { + *rgb ++ = *raw_data ++; + *rgb ++ = *raw_data ++; + *rgb ++ = *raw_data ++; + *alpha ++ = *raw_data ++; + } + return this->insert(bitmap_key, wxImage_to_wxBitmap_with_alpha(std::move(image))); +} + +wxBitmap* BitmapCache::load_png(const std::string &bitmap_name, unsigned int height) +{ + std::string bitmap_key = bitmap_name + "-h" + std::to_string(height); + auto it = m_map.find(bitmap_key); + if (it != m_map.end()) + return it->second; + + wxImage image; + if (! image.LoadFile(Slic3r::GUI::from_u8(Slic3r::var(bitmap_name + ".png")), wxBITMAP_TYPE_PNG) || + image.GetWidth() == 0 || image.GetHeight() == 0) + return nullptr; + if (image.GetHeight() != height) + image.Rescale(int(0.5f + float(image.GetWidth()) * height / image.GetHeight()), height, wxIMAGE_QUALITY_BILINEAR); + return this->insert(bitmap_key, wxImage_to_wxBitmap_with_alpha(std::move(image))); +} + +wxBitmap* BitmapCache::load_svg(const std::string &bitmap_name, unsigned int target_height) +{ + std::string bitmap_key = bitmap_name + "-h" + std::to_string(target_height); + auto it = m_map.find(bitmap_key); + if (it != m_map.end()) + return it->second; + + NSVGimage *image = ::nsvgParseFromFile(Slic3r::var(bitmap_name + ".svg").c_str(), "px", 96.0f); + if (image == nullptr) + return nullptr; + + float scale = (float)target_height / image->height; + int width = (int)(scale * image->width + 0.5f); + int height = (int)(scale * image->height + 0.5f); + int n_pixels = width * height; + if (n_pixels <= 0) { + ::nsvgDelete(image); + return nullptr; + } + + NSVGrasterizer *rast = ::nsvgCreateRasterizer(); + if (rast == nullptr) { + ::nsvgDelete(image); + return nullptr; + } + + std::vector data(n_pixels * 4, 0); + ::nsvgRasterize(rast, image, 0, 0, scale, data.data(), width, height, width * 4); + ::nsvgDeleteRasterizer(rast); + ::nsvgDelete(image); + + return this->insert_raw_rgba(bitmap_key, width, height, data.data()); +} + wxBitmap BitmapCache::mksolid(size_t width, size_t height, unsigned char r, unsigned char g, unsigned char b, unsigned char transparency) { wxImage image(width, height); diff --git a/src/slic3r/GUI/BitmapCache.hpp b/src/slic3r/GUI/BitmapCache.hpp index 0cb70d28b9..ce5eb3c77a 100644 --- a/src/slic3r/GUI/BitmapCache.hpp +++ b/src/slic3r/GUI/BitmapCache.hpp @@ -29,6 +29,12 @@ public: wxBitmap* insert(const std::string &name, const wxBitmap &bmp, const wxBitmap &bmp2, const wxBitmap &bmp3); wxBitmap* insert(const std::string &name, const std::vector &bmps) { return this->insert(name, &bmps.front(), &bmps.front() + bmps.size()); } wxBitmap* insert(const std::string &name, const wxBitmap *begin, const wxBitmap *end); + wxBitmap* insert_raw_rgba(const std::string &bitmap_key, unsigned int width, unsigned int height, const unsigned char *raw_data); + + // Load png from resources/icons. bitmap_key is given without the .png suffix. Bitmap will be rescaled to provided height if nonzero. + wxBitmap* load_png(const std::string &bitmap_key, unsigned int height = 0); + // Load svg from resources/icons. bitmap_key is given without the .svg suffix. SVG will be rasterized to provided height. + wxBitmap* load_svg(const std::string &bitmap_key, unsigned int height); static wxBitmap mksolid(size_t width, size_t height, unsigned char r, unsigned char g, unsigned char b, unsigned char transparency); static wxBitmap mksolid(size_t width, size_t height, const unsigned char rgb[3]) { return mksolid(width, height, rgb[0], rgb[1], rgb[2], wxALPHA_OPAQUE); } diff --git a/src/slic3r/GUI/GLTexture.cpp b/src/slic3r/GUI/GLTexture.cpp index b48ca20448..68369d9d03 100644 --- a/src/slic3r/GUI/GLTexture.cpp +++ b/src/slic3r/GUI/GLTexture.cpp @@ -11,15 +11,11 @@ #include #include -#define NANOSVG_IMPLEMENTATION #include "nanosvg/nanosvg.h" -#define NANOSVGRAST_IMPLEMENTATION #include "nanosvg/nanosvgrast.h" #include "libslic3r/Utils.hpp" -#include "libslic3r/Utils.hpp" - namespace Slic3r { namespace GUI { @@ -378,6 +374,7 @@ bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, uns if (n_pixels <= 0) { reset(); + nsvgDelete(image); return false; } diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 631050f297..a91dae0265 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1446,7 +1446,7 @@ void TabFilament::build() line.append_option(optgroup->get_option("bed_temperature")); optgroup->append_line(line); - page = add_options_page(_(L("Cooling")), "hourglass.png"); + page = add_options_page(_(L("Cooling")), "cooling"); optgroup = page->new_optgroup(_(L("Enable"))); optgroup->append_single_option_line("fan_always_on"); optgroup->append_single_option_line("cooling"); diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index 55544f28e3..09096cb059 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -8,6 +8,8 @@ #include #include +#include + #include "BitmapCache.hpp" #include "GUI.hpp" #include "GUI_App.hpp" @@ -421,19 +423,16 @@ void PrusaCollapsiblePaneMSW::Collapse(bool collapse) // PrusaObjectDataViewModelNode // ---------------------------------------------------------------------------- -wxBitmap create_scaled_bitmap(const std::string& bmp_name) +wxBitmap create_scaled_bitmap(const std::string& bmp_name_in) { - const double scale_f = Slic3r::GUI::wxGetApp().em_unit()* 0.1;//GetContentScaleFactor(); - if (scale_f == 1.0) - return wxBitmap(Slic3r::GUI::from_u8(Slic3r::var(bmp_name)), wxBITMAP_TYPE_PNG); -// else if (scale_f == 2.0) // use biger icon -// return wxBitmap(Slic3r::GUI::from_u8(Slic3r::var(bmp_name_X2)), wxBITMAP_TYPE_PNG); - - wxImage img = wxImage(Slic3r::GUI::from_u8(Slic3r::var(bmp_name)), wxBITMAP_TYPE_PNG); - const int sz_w = int(img.GetWidth()*scale_f); - const int sz_h = int(img.GetHeight()*scale_f); - img.Rescale(sz_w, sz_h, wxIMAGE_QUALITY_BILINEAR); - return wxBitmap(img); + static Slic3r::GUI::BitmapCache cache; + const auto height = (unsigned int)(Slic3r::GUI::wxGetApp().em_unit() * 1.6f + 0.5f); + std::string bmp_name = bmp_name_in; + boost::replace_last(bmp_name, ".png", ""); + wxBitmap *bmp = cache.load_svg(bmp_name, height); + if (bmp == nullptr) + bmp = cache.load_png(bmp_name, height); + return *bmp; } void PrusaObjectDataViewModelNode::set_object_action_icon() { From 936f7a3b844813efe6dec8e75117c1e9cf5ab258 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 4 Apr 2019 09:35:13 +0200 Subject: [PATCH 17/23] Select newly added parts/volumes from current selected instance when adding from 3D scene's context menu --- src/slic3r/GUI/GUI_ObjectList.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index c0dcc659d9..c725fae432 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -2051,12 +2051,15 @@ void ObjectList::update_selections_on_canvas() } }; + // stores current instance idx before to clear the selection + int instance_idx = selection.get_instance_idx(); + if (sel_cnt == 1) { wxDataViewItem item = GetSelection(); if (m_objects_model->GetItemType(item) & (itSettings|itInstanceRoot)) add_to_selection(m_objects_model->GetParent(item), selection, -1, true); else - add_to_selection(item, selection, -1, true); + add_to_selection(item, selection, instance_idx, true); wxGetApp().plater()->canvas3D()->update_gizmos_on_off_state(); return; @@ -2065,8 +2068,6 @@ void ObjectList::update_selections_on_canvas() wxDataViewItemArray sels; GetSelections(sels); - // stores current instance idx before to clear the selection - int instance_idx = selection.get_instance_idx(); selection.clear(); for (auto item: sels) add_to_selection(item, selection, instance_idx, false); From 30f44880d7f3b76e503a0c329f87ee84eff6c139 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 4 Apr 2019 11:31:26 +0200 Subject: [PATCH 18/23] Removed 'Export print config' checkbox from save dialog for 3mf and amf files --- src/slic3r/GUI/Plater.cpp | 70 +++++++++++++++++++++------------------ 1 file changed, 38 insertions(+), 32 deletions(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 435d9548f8..bc9b7d5b5f 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1199,7 +1199,7 @@ struct Plater::priv BoundingBox scaled_bed_shape_bb() const; std::vector load_files(const std::vector& input_files, bool load_model, bool load_config); std::vector load_model_objects(const ModelObjectPtrs &model_objects); - std::unique_ptr get_export_file(GUI::FileType file_type); + wxString get_export_file(GUI::FileType file_type); const Selection& get_selection() const; Selection& get_selection(); @@ -1784,7 +1784,7 @@ std::vector Plater::priv::load_model_objects(const ModelObjectPtrs &mode return obj_idxs; } -std::unique_ptr Plater::priv::get_export_file(GUI::FileType file_type) +wxString Plater::priv::get_export_file(GUI::FileType file_type) { wxString wildcard; switch (file_type) { @@ -1804,31 +1804,43 @@ std::unique_ptr Plater::priv::get_export_file(GUI::FileType // Find the file name of the first printable object. fs::path output_file = this->model.propose_export_file_name_and_path(); + wxString dlg_title; switch (file_type) { - case FT_STL: output_file.replace_extension("stl"); break; - case FT_AMF: output_file.replace_extension("zip.amf"); break; // XXX: Problem on OS X with double extension? - case FT_3MF: output_file.replace_extension("3mf"); break; + case FT_STL: + { + output_file.replace_extension("stl"); + dlg_title = _(L("Export STL file:")); + break; + } + case FT_AMF: + { + // XXX: Problem on OS X with double extension? + output_file.replace_extension("zip.amf"); + dlg_title = _(L("Export AMF file:")); + break; + } + case FT_3MF: + { + output_file.replace_extension("3mf"); + dlg_title = _(L("Save file as:")); + break; + } default: break; } - auto dlg = Slic3r::make_unique(q, - ((file_type == FT_AMF) || (file_type == FT_3MF)) ? _(L("Export print config")) : "", - true, - _(L("Save file as:")), - from_path(output_file.parent_path()), - from_path(output_file.filename()), - wildcard, - wxFD_SAVE | wxFD_OVERWRITE_PROMPT - ); + wxFileDialog* dlg = new wxFileDialog(q, dlg_title, + from_path(output_file.parent_path()), from_path(output_file.filename()), + wildcard, wxFD_SAVE | wxFD_OVERWRITE_PROMPT); if (dlg->ShowModal() != wxID_OK) { - return nullptr; + return wxEmptyString; } - fs::path path(into_path(dlg->GetPath())); + wxString out_path = dlg->GetPath(); + fs::path path(into_path(out_path)); wxGetApp().app_config->update_last_output_dir(path.parent_path().string()); - return dlg; + return out_path; } const Selection& Plater::priv::get_selection() const @@ -3243,11 +3255,8 @@ void Plater::export_stl(bool selection_only) { if (p->model.objects.empty()) { return; } - auto dialog = p->get_export_file(FT_STL); - if (! dialog) { return; } - - // Store a binary STL - const wxString path = dialog->GetPath(); + wxString path = p->get_export_file(FT_STL); + if (path.empty()) { return; } const std::string path_u8 = into_u8(path); wxBusyCursor wait; @@ -3272,15 +3281,14 @@ void Plater::export_amf() { if (p->model.objects.empty()) { return; } - auto dialog = p->get_export_file(FT_AMF); - if (! dialog) { return; } - - const wxString path = dialog->GetPath(); + wxString path = p->get_export_file(FT_AMF); + if (path.empty()) { return; } const std::string path_u8 = into_u8(path); - DynamicPrintConfig cfg = wxGetApp().preset_bundle->full_config_secure(); wxBusyCursor wait; - if (Slic3r::store_amf(path_u8.c_str(), &p->model, dialog->get_checkbox_value() ? &cfg : nullptr)) { + bool export_config = true; + DynamicPrintConfig cfg = wxGetApp().preset_bundle->full_config_secure(); + if (Slic3r::store_amf(path_u8.c_str(), &p->model, export_config ? &cfg : nullptr)) { // Success p->statusbar()->set_status_text(wxString::Format(_(L("AMF file exported to %s")), path)); } else { @@ -3297,10 +3305,8 @@ void Plater::export_3mf(const boost::filesystem::path& output_path) bool export_config = true; if (output_path.empty()) { - auto dialog = p->get_export_file(FT_3MF); - if (!dialog) { return; } - path = dialog->GetPath(); - export_config = dialog->get_checkbox_value(); + path = p->get_export_file(FT_3MF); + if (path.empty()) { return; } } else path = from_path(output_path); From 369cdd8b3ba61f975e59682b4615d2b93855dc48 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 4 Apr 2019 12:02:13 +0200 Subject: [PATCH 19/23] Ask user to switch to expert mode when loading a 3mf or an amf file containing instances or modifiers from simple mode --- src/slic3r/GUI/Plater.cpp | 41 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index bc9b7d5b5f..9cf9768a5e 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1617,6 +1617,45 @@ std::vector Plater::priv::load_files(const std::vector& input_ } #if ENABLE_VOLUMES_CENTERING_FIXES } + else if ((wxGetApp().get_mode() == comSimple) && (type_3mf || type_any_amf)) + { + bool advanced = false; + for (const ModelObject* model_object : model.objects) + { + // is there more than one instance ? + if (model_object->instances.size() > 1) + { + advanced = true; + break; + } + + // is there any modifier ? + for (const ModelVolume* model_volume : model_object->volumes) + { + if (!model_volume->is_model_part()) + { + advanced = true; + break; + } + } + + if (advanced) + break; + } + + if (advanced) + { + wxMessageDialog dlg(q, _(L("This file cannot be loaded in simple mode. Do you want to switch to expert mode?\n")), + _(L("Detected advanced data")), wxICON_WARNING | wxYES | wxNO); + if (dlg.ShowModal() == wxID_YES) + { + Slic3r::GUI::wxGetApp().save_mode(comExpert); + view3D->set_as_dirty(); + } + else + return obj_idxs; + } + } #endif // ENABLE_VOLUMES_CENTERING_FIXES #if !ENABLE_VOLUMES_CENTERING_FIXES @@ -1642,7 +1681,7 @@ std::vector Plater::priv::load_files(const std::vector& input_ Slic3r::GUI::show_error(nullptr, wxString::Format(_(L("You can't to add the object(s) from %s because of one or some of them is(are) multi-part")), from_path(filename))); - return std::vector(); + return obj_idxs; } } From 590ae25b13d2ff27843a82f821ec6b2d9e2e12f6 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Thu, 4 Apr 2019 12:30:11 +0200 Subject: [PATCH 20/23] Altering sla export interface to support explicit project name. --- src/libslic3r/Print.cpp | 2 +- src/libslic3r/PrintExport.hpp | 19 ++++++++++--------- src/libslic3r/SLAPrint.hpp | 20 ++++++++------------ src/libslic3r/Zipper.cpp | 5 ----- src/libslic3r/Zipper.hpp | 3 --- 5 files changed, 19 insertions(+), 30 deletions(-) diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 7943901339..c13f0bc2a3 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -10,7 +10,7 @@ #include "GCode/WipeTowerPrusaMM.hpp" #include "Utils.hpp" -#include "PrintExport.hpp" +//#include "PrintExport.hpp" #include #include diff --git a/src/libslic3r/PrintExport.hpp b/src/libslic3r/PrintExport.hpp index 04b993a529..ce62f7cb0f 100644 --- a/src/libslic3r/PrintExport.hpp +++ b/src/libslic3r/PrintExport.hpp @@ -7,6 +7,7 @@ #include #include +#include #include "Rasterizer/Rasterizer.hpp" //#include @@ -72,7 +73,8 @@ public: void finish_layer(); // Save all the layers into the file (or dir) specified in the path argument - void save(const std::string& path); + // An optional project name can be added to be used for the layer file names + void save(const std::string& path, const std::string& projectname = ""); // Save only the selected layer to the file specified in path argument. void save_layer(unsigned lyr, const std::string& path); @@ -86,7 +88,8 @@ template struct VeryFalse { static const bool value = false; }; template class LayerWriter { public: - LayerWriter(const std::string& /*zipfile_path*/) { + LayerWriter(const std::string& /*zipfile_path*/) + { static_assert(VeryFalse::value, "No layer writer implementation provided!"); } @@ -99,10 +102,6 @@ public: void binary_entry(const std::string& /*fname*/, const std::uint8_t* buf, size_t len); - // Get the name of the archive but only the name part without the path or - // the extension. - std::string get_name() { return ""; } - // Test whether the object can still be used for writing. bool is_ok() { return false; } @@ -253,12 +252,14 @@ public: } template - inline void save(const std::string& path) { + inline void save(const std::string& fpath, const std::string& prjname = "") + { try { - LayerWriter writer(path); + LayerWriter writer(fpath); if(!writer.is_ok()) return; - std::string project = writer.get_name(); + std::string project = prjname.empty()? + boost::filesystem::path(fpath).stem().string() : prjname; writer.next_entry("config.ini"); if(!writer.is_ok()) return; diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp index a1e382acbc..d4443d9155 100644 --- a/src/libslic3r/SLAPrint.hpp +++ b/src/libslic3r/SLAPrint.hpp @@ -320,10 +320,8 @@ struct SLAPrintStatistics } }; -struct SLAminzZipper {}; - // The implementation of creating zipped archives with wxWidgets -template<> class LayerWriter { +template<> class LayerWriter { Zipper m_zip; public: @@ -332,16 +330,12 @@ public: void next_entry(const std::string& fname) { m_zip.add_entry(fname); } void binary_entry(const std::string& fname, - const std::uint8_t* buf, - size_t l) + const std::uint8_t* buf, + size_t l) { m_zip.add_entry(fname, buf, l); } - std::string get_name() const { - return m_zip.get_name(); - } - template inline LayerWriter& operator<<(T&& arg) { m_zip << std::forward(arg); return *this; } @@ -389,9 +383,11 @@ public: // Returns true if the last step was finished with success. bool finished() const override { return this->is_step_done(slaposSliceSupports) && this->Inherited::is_step_done(slapsRasterize); } - template - void export_raster(const std::string& fname) { - if(m_printer) m_printer->save(fname); + template + inline void export_raster(const std::string& fpath, + const std::string& projectname = "") + { + if(m_printer) m_printer->save(fpath, projectname); } const PrintObjects& objects() const { return m_objects; } diff --git a/src/libslic3r/Zipper.cpp b/src/libslic3r/Zipper.cpp index 6b7faaddcb..4466f1b045 100644 --- a/src/libslic3r/Zipper.cpp +++ b/src/libslic3r/Zipper.cpp @@ -4,7 +4,6 @@ #include "Zipper.hpp" #include "miniz/miniz_zip.h" -#include #include #include "I18N.hpp" @@ -213,10 +212,6 @@ void Zipper::finish_entry() m_entry.clear(); } -std::string Zipper::get_name() const { - return boost::filesystem::path(m_impl->m_zipname).stem().string(); -} - void Zipper::finalize() { finish_entry(); diff --git a/src/libslic3r/Zipper.hpp b/src/libslic3r/Zipper.hpp index 6566dad426..7d95ffdac7 100644 --- a/src/libslic3r/Zipper.hpp +++ b/src/libslic3r/Zipper.hpp @@ -81,9 +81,6 @@ public: /// file is up to minz after the erroneous write. void finish_entry(); - /// Gets the name of the archive without the path or extension. - std::string get_name() const; - void finalize(); }; From 251747e6faffa2426acb6bb43ba071e288abc49c Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Thu, 4 Apr 2019 10:28:41 +0200 Subject: [PATCH 21/23] GLGizmoCut: Scale input field --- src/slic3r/GUI/Gizmos/GLGizmoCut.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp index 02d663e93b..5eb0d05839 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp @@ -15,12 +15,6 @@ namespace Slic3r { namespace GUI { - - - - -// GLGizmoCut - class GLGizmoCutPanel : public wxPanel { public: @@ -192,7 +186,7 @@ void GLGizmoCut::on_render_input_window(float x, float y, float bottom_limit, co m_imgui->set_next_window_bg_alpha(0.5f); m_imgui->begin(_(L("Cut")), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); - ImGui::PushItemWidth(100.0f); + ImGui::PushItemWidth(m_imgui->scaled(5.0f)); bool _value_changed = ImGui::InputDouble("Z", &m_cut_z, 0.0f, 0.0f, "%.2f"); m_imgui->checkbox(_(L("Keep upper part")), m_keep_upper); From 70ce79c86e6131862b59e3fc2124d6c6166f9cea Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Thu, 4 Apr 2019 12:31:09 +0200 Subject: [PATCH 22/23] SLA export: Finalize filename when exporting & uploading, set correct project name when uploading --- src/slic3r.cpp | 5 +++-- src/slic3r/GUI/BackgroundSlicingProcess.cpp | 11 ++++++----- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/slic3r.cpp b/src/slic3r.cpp index 958b663059..780efea7b3 100644 --- a/src/slic3r.cpp +++ b/src/slic3r.cpp @@ -397,8 +397,9 @@ int CLI::run(int argc, char **argv) outfile_final = fff_print.print_statistics().finalize_output_path(outfile); } else { outfile = sla_print.output_filepath(outfile); - sla_print.export_raster(outfile); - outfile_final = sla_print.print_statistics().finalize_output_path(outfile); + // We need to finalize the filename beforehand because the export function sets the filename inside the zip metadata + outfile_final = sla_print.print_statistics().finalize_output_path(outfile); + sla_print.export_raster(outfile_final); } if (outfile != outfile_final && Slic3r::rename_file(outfile, outfile_final) != 0) { boost::nowide::cerr << "Renaming file " << outfile << " to " << outfile_final << " failed" << std::endl; diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/src/slic3r/GUI/BackgroundSlicingProcess.cpp index 2601842ef4..c6a73864d6 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.cpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp @@ -98,8 +98,9 @@ void BackgroundSlicingProcess::process_sla() m_print->process(); if (this->set_step_started(bspsGCodeFinalize)) { if (! m_export_path.empty()) { - m_sla_print->export_raster(m_export_path); - m_print->set_status(100, "Masked SLA file exported to " + m_export_path); + const std::string export_path = m_sla_print->print_statistics().finalize_output_path(m_export_path); + m_sla_print->export_raster(export_path); + m_print->set_status(100, "Masked SLA file exported to " + export_path); } else if (! m_upload_job.empty()) { prepare_upload(); } else { @@ -389,7 +390,7 @@ void BackgroundSlicingProcess::prepare_upload() // Generate a unique temp path to which the gcode/zip file is copied/exported boost::filesystem::path source_path = boost::filesystem::temp_directory_path() - / boost::filesystem::unique_path(".printhost.%%%%-%%%%-%%%%-%%%%.gcode"); + / boost::filesystem::unique_path(".Slic3rPE.upload.%%%%-%%%%-%%%%-%%%%"); if (m_print == m_fff_print) { m_print->set_status(95, "Running post-processing scripts"); @@ -399,8 +400,8 @@ void BackgroundSlicingProcess::prepare_upload() run_post_process_scripts(source_path.string(), m_fff_print->config()); m_upload_job.upload_data.upload_path = m_fff_print->print_statistics().finalize_output_path(m_upload_job.upload_data.upload_path.string()); } else { - m_sla_print->export_raster(source_path.string()); - // TODO: Also finalize upload path like with FFF when there are statistics for SLA print + m_upload_job.upload_data.upload_path = m_sla_print->print_statistics().finalize_output_path(m_upload_job.upload_data.upload_path.string()); + m_sla_print->export_raster(source_path.string(), m_upload_job.upload_data.upload_path.string()); } m_print->set_status(100, (boost::format("Scheduling upload to `%1%`. See Window -> Print Host Upload Queue") % m_upload_job.printhost->get_host()).str()); From 6197f48321f9a7646c88d39d8a8c76a59f56543a Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 4 Apr 2019 14:00:31 +0200 Subject: [PATCH 23/23] Use current selection to determine proposed filename when exporting to stl files --- src/libslic3r/Model.cpp | 36 +++++++++++++++++++++++------------- src/libslic3r/Model.hpp | 2 ++ src/slic3r/GUI/Plater.cpp | 14 ++++++++++++-- 3 files changed, 37 insertions(+), 15 deletions(-) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index ba898d9d52..e634dd1383 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -556,19 +556,9 @@ std::string Model::propose_export_file_name_and_path() const for (const ModelObject *model_object : this->objects) for (ModelInstance *model_instance : model_object->instances) if (model_instance->is_printable()) { - input_file = model_object->input_file; - if (! model_object->name.empty()) { - if (input_file.empty()) - // model_object->input_file was empty, just use model_object->name - input_file = model_object->name; - else { - // Replace file name in input_file with model_object->name, but keep the path and file extension. - input_file = (boost::filesystem::path(model_object->name).parent_path().empty()) ? - (boost::filesystem::path(input_file).parent_path() / model_object->name).make_preferred().string() : - model_object->name; - } - } - if (! input_file.empty()) + input_file = model_object->get_export_filename(); + + if (!input_file.empty()) goto end; // Other instances will produce the same name, skip them. break; @@ -1433,6 +1423,26 @@ void ModelObject::print_info() const cout << "volume = " << mesh.volume() << endl; } +std::string ModelObject::get_export_filename() const +{ + std::string ret = input_file; + + if (!name.empty()) + { + if (ret.empty()) + // input_file was empty, just use name + ret = name; + else + { + // Replace file name in input_file with name, but keep the path and file extension. + ret = (boost::filesystem::path(name).parent_path().empty()) ? + (boost::filesystem::path(ret).parent_path() / name).make_preferred().string() : name; + } + } + + return ret; +} + void ModelVolume::set_material_id(t_model_material_id material_id) { m_material_id = material_id; diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 5cf7f49cad..9514012434 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -275,6 +275,8 @@ public: // Print object statistics to console. void print_info() const; + std::string get_export_filename() const; + protected: friend class Print; friend class SLAPrint; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 9cf9768a5e..53d9992839 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1840,8 +1840,18 @@ wxString Plater::priv::get_export_file(GUI::FileType file_type) // Update printbility state of each of the ModelInstances. this->update_print_volume_state(); - // Find the file name of the first printable object. - fs::path output_file = this->model.propose_export_file_name_and_path(); + + const Selection& selection = get_selection(); + int obj_idx = selection.get_object_idx(); + + fs::path output_file; + // first try to get the file name from the current selection + if ((0 <= obj_idx) && (obj_idx < (int)this->model.objects.size())) + output_file = this->model.objects[obj_idx]->get_export_filename(); + + if (output_file.empty()) + // Find the file name of the first printable object. + output_file = this->model.propose_export_file_name_and_path(); wxString dlg_title; switch (file_type) {