From 2c51e432e340a921a8204d2bbd7c7cb153f1e34a 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 6c8fdcab73c..61e98d5425a 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 0119160a1bf929a29b9cea7394397d50c35949f4 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 f00e908ce56..86b4ee4475b 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 b48aee34151320d3813c2e930c9dd56955356080 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 7dc920517bb..809b32d901a 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 5b1a8d6a14990b59e8862fe1cc1a6eeeb21664d4 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 75f13cdcf0f..5be7f9100a1 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 380f5fbfa570addd99adcaaff815d352988fbf25 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 6c04c7781aa..42c6fbf7549 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 c145380c963..0d9a79978d4 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 a65a4be75bc..527846f9d9f 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 4080c33570d26ab99ef582b9ab6cadb6fa685916 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 86b4ee4475b..4c6e542f4de 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 3ebc21ebcd6872dd91e64bf53ebb75d1c472d3b3 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 b5b9a008d01..ba898d9d527 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 224bb802eb5..c0dcc659d96 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 b65df6e5602474fbd33974d8a114554703ac021c 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 4c0879ad3cf..cd995bc0942 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 e44e8af02a8a8a921d91bb3de5d3353f5a8dd690 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 5be7f9100a1..2264c541e8f 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 7e8113774bb..bb3cf06ce42 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 d226efefe26a75ddec6bda1181a2b594432fc1bf 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 7103ca12dc6..ca245029c14 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 53e40cc0491118a235bc9ea71f0fac02f0551669 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 1b4d4edf9e2..8a6a71b1b92 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 1c762dcd78f2b3c0bd7f2f62eedc4f29ef154b73 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 c1bf491e140..b593054c4ab 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 af4c7a1d4542200a29a265cf679f87202f21a91d 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 ca245029c14..db25e6332fe 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 dcfc8bb47a7fe5393c913a607f1a6025055539a7 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 00000000000..07adb66101e --- /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 00000000000..b5d80e434a2 --- /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 00000000000..8877722e333 --- /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 00000000000..fcb1f99c9ed --- /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 00000000000..c1421420109 --- /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 00000000000..ec1518f2525 --- /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 00000000000..91e103ec704 --- /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 00000000000..9242761b61a --- /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 00000000000..84036593818 --- /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 00000000000..65c7592c835 --- /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 00000000000..5d8f23cfc38 --- /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 00000000000..7966da8d8f6 --- /dev/null +++ b/resources/icons/wrench.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + From 9a59ca6aca6af684dcccf79478ecdc96c9ed0882 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 d1ad4f5752e..321d9a3427a 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 29dfd914f960b71b1d0b7a57994a7752598ad9e6 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 7718a8cbd55..da5dec21d5c 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 16baa1629e8..4c7f999ffc0 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 0cb70d28b98..ce5eb3c77a8 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 b48ca20448b..68369d9d03d 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 631050f297e..a91dae02657 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 55544f28e38..09096cb059c 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 2054073d00c7a4f993d11096307e2783713e2567 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 c0dcc659d96..c725fae432d 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 f1284ed8ecb22df4a56641c731e78be29c10a64c 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 435d9548f8d..bc9b7d5b5f1 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 70c144347e0b8cc935e1d4135c3bf186b46771b2 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 bc9b7d5b5f1..9cf9768a5ea 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 71601620832fc3f06c3b7cbc4426f0ee0d492d2d 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 7943901339e..c13f0bc2a39 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 04b993a529b..ce62f7cb0fb 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 a1e382acbcf..d4443d91551 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 6b7faaddcbf..4466f1b045d 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 6566dad426a..7d95ffdac7a 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 7665c74da82e46dbaffe116acffb720e1c6ce5ff 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 02d663e93b9..5eb0d05839d 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 c8cca95e25c2f4856a144420b679530bbc40d278 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 958b6630590..780efea7b3e 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 2601842ef42..c6a73864d6a 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 3ecd0dd48d4a2d3b8b63fa329c005359bd289863 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 ba898d9d527..e634dd1383d 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 5cf7f49cadb..95140124342 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 9cf9768a5ea..53d99928394 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) {