From 6ce1011a09943d084f82e96156805fae7fb6a24b Mon Sep 17 00:00:00 2001 From: bubnikv <bubnikv@gmail.com> Date: Thu, 19 Sep 2019 17:16:37 +0200 Subject: [PATCH 01/12] Slic3r -> PrusaSlicer in config snapshot dialog. --- src/slic3r/GUI/ConfigSnapshotDialog.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/ConfigSnapshotDialog.cpp b/src/slic3r/GUI/ConfigSnapshotDialog.cpp index 836a0a4d3..c89e4895e 100644 --- a/src/slic3r/GUI/ConfigSnapshotDialog.cpp +++ b/src/slic3r/GUI/ConfigSnapshotDialog.cpp @@ -42,7 +42,7 @@ static wxString generate_html_row(const Config::Snapshot &snapshot, bool row_eve text += " (" + wxString::FromUTF8(snapshot.comment.data()) + ")"; text += "</b></font><br>"; // End of row header. - text += _(L("slic3r version")) + ": " + snapshot.slic3r_version_captured.to_string() + "<br>"; + text += _(L("PrusaSlicer version")) + ": " + snapshot.slic3r_version_captured.to_string() + "<br>"; text += _(L("print")) + ": " + snapshot.print + "<br>"; text += _(L("filaments")) + ": " + snapshot.filaments.front() + "<br>"; text += _(L("printer")) + ": " + snapshot.printer + "<br>"; @@ -50,9 +50,9 @@ static wxString generate_html_row(const Config::Snapshot &snapshot, bool row_eve bool compatible = true; for (const Config::Snapshot::VendorConfig &vc : snapshot.vendor_configs) { text += _(L("vendor")) + ": " + vc.name +", " + _(L("version")) + ": " + vc.version.config_version.to_string() + - ", " + _(L("min slic3r version")) + ": " + vc.version.min_slic3r_version.to_string(); + ", " + _(L("min PrusaSlicer version")) + ": " + vc.version.min_slic3r_version.to_string(); if (vc.version.max_slic3r_version != Semver::inf()) - text += ", " + _(L("max slic3r version")) + ": " + vc.version.max_slic3r_version.to_string(); + text += ", " + _(L("max PrusaSlicer version")) + ": " + vc.version.max_slic3r_version.to_string(); text += "<br>"; for (const std::pair<std::string, std::set<std::string>> &model : vc.models_variants_installed) { text += _(L("model")) + ": " + model.first + ", " + _(L("variants")) + ": "; From 9e09c52ab008f6e8346972f0591a60e248d78ddb Mon Sep 17 00:00:00 2001 From: Enrico Turri <enricoturri@seznam.cz> Date: Fri, 20 Sep 2019 09:53:35 +0200 Subject: [PATCH 02/12] #2948 - Max zoom takes in account custom bed model size --- src/slic3r/GUI/GLCanvas3D.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index edb9c7830..08e47f30b 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -3372,7 +3372,7 @@ void GLCanvas3D::do_mirror(const std::string& snapshot_type) void GLCanvas3D::set_camera_zoom(double zoom) { const Size& cnv_size = get_canvas_size(); - m_camera.set_zoom(zoom, _max_bounding_box(false, false), cnv_size.get_width(), cnv_size.get_height()); + m_camera.set_zoom(zoom, _max_bounding_box(false, true), cnv_size.get_width(), cnv_size.get_height()); m_dirty = true; } From 8aaff083557a79a041ee17f1d6879a5574e62599 Mon Sep 17 00:00:00 2001 From: YuSanka <yusanka@gmail.com> Date: Fri, 20 Sep 2019 09:57:27 +0200 Subject: [PATCH 03/12] Added Possibility to create "shape" as an independent object from 3dScene, using right click on empty place --- src/slic3r/GUI/GLCanvas3D.cpp | 12 ++++- src/slic3r/GUI/GLCanvas3D.hpp | 5 +- src/slic3r/GUI/Plater.cpp | 91 ++++++++++++++++++++--------------- 3 files changed, 66 insertions(+), 42 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index edb9c7830..6d069df29 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1094,7 +1094,7 @@ void GLCanvas3D::LegendTexture::render(const GLCanvas3D& canvas) const wxDEFINE_EVENT(EVT_GLCANVAS_INIT, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_OBJECT_SELECT, SimpleEvent); -wxDEFINE_EVENT(EVT_GLCANVAS_RIGHT_CLICK, Vec2dEvent); +wxDEFINE_EVENT(EVT_GLCANVAS_RIGHT_CLICK, RBtnEvent); wxDEFINE_EVENT(EVT_GLCANVAS_REMOVE_OBJECT, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_ARRANGE, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_SELECT_ALL, SimpleEvent); @@ -3012,15 +3012,23 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) wxGetApp().obj_manipul()->set_dirty(); // forces a frame render to update the view before the context menu is shown render(); - +/* #et_FIXME Vec2d logical_pos = pos.cast<double>(); #if ENABLE_RETINA_GL const float factor = m_retina_helper->get_scale_factor(); logical_pos = logical_pos.cwiseQuotient(Vec2d(factor, factor)); #endif // ENABLE_RETINA_GL post_event(Vec2dEvent(EVT_GLCANVAS_RIGHT_CLICK, logical_pos)); +*/ } } + // #et_FIXME + Vec2d logical_pos = pos.cast<double>(); +#if ENABLE_RETINA_GL + const float factor = m_retina_helper->get_scale_factor(); + logical_pos = logical_pos.cwiseQuotient(Vec2d(factor, factor)); +#endif // ENABLE_RETINA_GL + post_event(RBtnEvent(EVT_GLCANVAS_RIGHT_CLICK, {logical_pos, m_hover_volume_idxs.empty()})); } mouse_up_cleanup(); diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index b15402a52..e6b10e9ca 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -71,6 +71,9 @@ public: wxDECLARE_EVENT(EVT_GLCANVAS_OBJECT_SELECT, SimpleEvent); using Vec2dEvent = Event<Vec2d>; +// #et_FIXME : RBtnEvent is used instead of Vec2dEvent on EVT_GLCANVAS_RIGHT_CLICK +// _bool_ value is used as a indicator of selection in the 3DScene +using RBtnEvent = Event<std::pair<Vec2d, bool>>; template <size_t N> using Vec2dsEvent = ArrayEvent<Vec2d, N>; using Vec3dEvent = Event<Vec3d>; @@ -78,7 +81,7 @@ template <size_t N> using Vec3dsEvent = ArrayEvent<Vec3d, N>; wxDECLARE_EVENT(EVT_GLCANVAS_INIT, SimpleEvent); wxDECLARE_EVENT(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS, SimpleEvent); -wxDECLARE_EVENT(EVT_GLCANVAS_RIGHT_CLICK, Vec2dEvent); +wxDECLARE_EVENT(EVT_GLCANVAS_RIGHT_CLICK, RBtnEvent); wxDECLARE_EVENT(EVT_GLCANVAS_REMOVE_OBJECT, SimpleEvent); wxDECLARE_EVENT(EVT_GLCANVAS_ARRANGE, SimpleEvent); wxDECLARE_EVENT(EVT_GLCANVAS_SELECT_ALL, SimpleEvent); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 524034ea9..18bc08d27 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1340,6 +1340,8 @@ struct Plater::priv MenuWithSeparators part_menu; // SLA-Object popup menu MenuWithSeparators sla_object_menu; + // Default popup menu (when nothing is selected on 3DScene) + MenuWithSeparators default_menu; // Removed/Prepended Items according to the view mode std::vector<wxMenuItem*> items_increase; @@ -1879,7 +1881,7 @@ struct Plater::priv void on_action_layersediting(SimpleEvent&); void on_object_select(SimpleEvent&); - void on_right_click(Vec2dEvent&); + void on_right_click(RBtnEvent&); void on_wipetower_moved(Vec3dEvent&); void on_wipetower_rotated(Vec3dEvent&); void on_update_geometry(Vec3dsEvent<2>&); @@ -3446,57 +3448,66 @@ void Plater::priv::on_object_select(SimpleEvent& evt) selection_changed(); } -void Plater::priv::on_right_click(Vec2dEvent& evt) +void Plater::priv::on_right_click(RBtnEvent& evt) { int obj_idx = get_selected_object_idx(); + + wxMenu* menu = nullptr; + if (obj_idx == -1) - return; - - wxMenu* menu = printer_technology == ptSLA ? &sla_object_menu : - get_selection().is_single_full_instance() ? // show "Object menu" for each FullInstance instead of FullObject - &object_menu : &part_menu; - - sidebar->obj_list()->append_menu_item_settings(menu); - - if (printer_technology != ptSLA) - sidebar->obj_list()->append_menu_item_change_extruder(menu); - - if (menu != &part_menu) + menu = &default_menu; + else { - /* Remove/Prepend "increase/decrease instances" menu items according to the view mode. - * Suppress to show those items for a Simple mode - */ - const MenuIdentifier id = printer_technology == ptSLA ? miObjectSLA : miObjectFFF; - if (wxGetApp().get_mode() == comSimple) { - if (menu->FindItem(_(L("Add instance"))) != wxNOT_FOUND) - { - /* Detach an items from the menu, but don't delete them - * so that they can be added back later - * (after switching to the Advanced/Expert mode) - */ - menu->Remove(items_increase[id]); - menu->Remove(items_decrease[id]); - menu->Remove(items_set_number_of_copies[id]); + // If in 3DScene is(are) selected volume(s), but right button was clicked on empty space + if (evt.data.second) + return; + + menu = printer_technology == ptSLA ? &sla_object_menu : + get_selection().is_single_full_instance() ? // show "Object menu" for each FullInstance instead of FullObject + &object_menu : &part_menu; + + sidebar->obj_list()->append_menu_item_settings(menu); + + if (printer_technology != ptSLA) + sidebar->obj_list()->append_menu_item_change_extruder(menu); + + if (menu != &part_menu) + { + /* Remove/Prepend "increase/decrease instances" menu items according to the view mode. + * Suppress to show those items for a Simple mode + */ + const MenuIdentifier id = printer_technology == ptSLA ? miObjectSLA : miObjectFFF; + if (wxGetApp().get_mode() == comSimple) { + if (menu->FindItem(_(L("Add instance"))) != wxNOT_FOUND) + { + /* Detach an items from the menu, but don't delete them + * so that they can be added back later + * (after switching to the Advanced/Expert mode) + */ + menu->Remove(items_increase[id]); + menu->Remove(items_decrease[id]); + menu->Remove(items_set_number_of_copies[id]); + } } - } - else { - if (menu->FindItem(_(L("Add instance"))) == wxNOT_FOUND) - { - // Prepend items to the menu, if those aren't not there - menu->Prepend(items_set_number_of_copies[id]); - menu->Prepend(items_decrease[id]); - menu->Prepend(items_increase[id]); + else { + if (menu->FindItem(_(L("Add instance"))) == wxNOT_FOUND) + { + // Prepend items to the menu, if those aren't not there + menu->Prepend(items_set_number_of_copies[id]); + menu->Prepend(items_decrease[id]); + menu->Prepend(items_increase[id]); + } } } } - if (q != nullptr) { + if (q != nullptr && menu) { #ifdef __linux__ // For some reason on Linux the menu isn't displayed if position is specified // (even though the position is sane). q->PopupMenu(menu); #else - q->PopupMenu(menu, (int)evt.data.x(), (int)evt.data.y()); + q->PopupMenu(menu, (int)evt.data.first.x(), (int)evt.data.first.y()); #endif } } @@ -3548,12 +3559,14 @@ bool Plater::priv::init_object_menu() init_common_menu(&part_menu, true); complit_init_part_menu(); + sidebar->obj_list()->create_default_popupmenu(&default_menu); + return true; } void Plater::priv::msw_rescale_object_menu() { - for (MenuWithSeparators* menu : { &object_menu, &sla_object_menu, &part_menu }) + for (MenuWithSeparators* menu : { &object_menu, &sla_object_menu, &part_menu, &default_menu }) msw_rescale_menu(dynamic_cast<wxMenu*>(menu)); } From b241ba16ed403492dad83068e655fec1723305e3 Mon Sep 17 00:00:00 2001 From: Lukas Matena <lukasmatena@seznam.cz> Date: Fri, 20 Sep 2019 10:53:50 +0200 Subject: [PATCH 04/12] Fixed layer profile equality check for wipe tower validation (fixup of b43003d) --- src/libslic3r/Print.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index cbbbf1f1a..4d8482743 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -1236,7 +1236,8 @@ std::string Print::validate() const // The comparison of the profiles is not just about element-wise equality, some layers may not be // explicitely included. Always remember z and height of last reference layer that in the vector - // and compare to that. + // and compare to that. In case some layers are in the vectors multiple times, only the last entry is + // taken into account and compared. size_t i = 0; // index into tested profile size_t j = 0; // index into reference profile coordf_t ref_z = -1.; @@ -1244,8 +1245,12 @@ std::string Print::validate() const coordf_t ref_height = -1.; while (i < layer_height_profile.size()) { coordf_t this_z = layer_height_profile[i]; + // find the last entry with this z + while (i+2 < layer_height_profile.size() && layer_height_profile[i+2] == this_z) + i += 2; + coordf_t this_height = layer_height_profile[i+1]; - if (next_ref_z < this_z + EPSILON) { + if (ref_height < -1. || next_ref_z < this_z + EPSILON) { ref_z = next_ref_z; do { // one layer can be in the vector several times ref_height = layer_height_profile_tallest[j+1]; From d66bf7e1e198b66feb78af9d7787490428995015 Mon Sep 17 00:00:00 2001 From: Enrico Turri <enricoturri@seznam.cz> Date: Fri, 20 Sep 2019 11:19:06 +0200 Subject: [PATCH 05/12] Follow-up of 8aaff083557a79a041ee17f1d6879a5574e62599 -> Do not show the new context menu when the user pans the scene + cleanup --- src/slic3r/GUI/GLCanvas3D.cpp | 13 +++---------- src/slic3r/GUI/GLCanvas3D.hpp | 1 - 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 21cd72a22..715d9f806 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -3012,23 +3012,16 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) wxGetApp().obj_manipul()->set_dirty(); // forces a frame render to update the view before the context menu is shown render(); -/* #et_FIXME - Vec2d logical_pos = pos.cast<double>(); -#if ENABLE_RETINA_GL - const float factor = m_retina_helper->get_scale_factor(); - logical_pos = logical_pos.cwiseQuotient(Vec2d(factor, factor)); -#endif // ENABLE_RETINA_GL - post_event(Vec2dEvent(EVT_GLCANVAS_RIGHT_CLICK, logical_pos)); -*/ } } - // #et_FIXME Vec2d logical_pos = pos.cast<double>(); #if ENABLE_RETINA_GL const float factor = m_retina_helper->get_scale_factor(); logical_pos = logical_pos.cwiseQuotient(Vec2d(factor, factor)); #endif // ENABLE_RETINA_GL - post_event(RBtnEvent(EVT_GLCANVAS_RIGHT_CLICK, {logical_pos, m_hover_volume_idxs.empty()})); + if (!m_mouse.dragging) + // do not post the event if the user is panning the scene + post_event(RBtnEvent(EVT_GLCANVAS_RIGHT_CLICK, { logical_pos, m_hover_volume_idxs.empty() })); } mouse_up_cleanup(); diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index e6b10e9ca..fb767360c 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -71,7 +71,6 @@ public: wxDECLARE_EVENT(EVT_GLCANVAS_OBJECT_SELECT, SimpleEvent); using Vec2dEvent = Event<Vec2d>; -// #et_FIXME : RBtnEvent is used instead of Vec2dEvent on EVT_GLCANVAS_RIGHT_CLICK // _bool_ value is used as a indicator of selection in the 3DScene using RBtnEvent = Event<std::pair<Vec2d, bool>>; template <size_t N> using Vec2dsEvent = ArrayEvent<Vec2d, N>; From 7e060f84bd534fb027bdc3a1f4b48cce912090bd Mon Sep 17 00:00:00 2001 From: YuSanka <yusanka@gmail.com> Date: Fri, 20 Sep 2019 11:30:29 +0200 Subject: [PATCH 06/12] Forcing of explicit SetWidth for the columns under OSX, as an attempt to fix a narrow column width on 4(5)K monitors under OSX --- src/slic3r/GUI/GUI_ObjectList.cpp | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 47be4b5eb..1d5d8f1a5 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -255,21 +255,30 @@ void ObjectList::create_objects_ctrl() EnableDropTarget(wxDF_UNICODETEXT); #endif // wxUSE_DRAG_AND_DROP && wxUSE_UNICODE + const int em = wxGetApp().em_unit(); + // column ItemName(Icon+Text) of the view control: // And Icon can be consisting of several bitmaps AppendColumn(new wxDataViewColumn(_(L("Name")), new BitmapTextRenderer(), - colName, 20*wxGetApp().em_unit()/*200*/, wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE)); + colName, 20*em, wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE)); // column PrintableProperty (Icon) of the view control: - AppendBitmapColumn(" ", colPrint, wxDATAVIEW_CELL_INERT, int(2 * wxGetApp().em_unit()), + AppendBitmapColumn(" ", colPrint, wxDATAVIEW_CELL_INERT, 3*em, wxALIGN_CENTER_HORIZONTAL, wxDATAVIEW_COL_RESIZABLE); // column Extruder of the view control: AppendColumn(create_objects_list_extruder_column(4)); // column ItemEditing of the view control: - AppendBitmapColumn(_(L("Editing")), colEditing, wxDATAVIEW_CELL_INERT, int(2.5 * wxGetApp().em_unit())/*25*/, + AppendBitmapColumn(_(L("Editing")), colEditing, wxDATAVIEW_CELL_INERT, 3*em, wxALIGN_CENTER_HORIZONTAL, wxDATAVIEW_COL_RESIZABLE); + + if (wxOSX) + { + GetColumn(colName)->SetWidth(20*em); + GetColumn(colPrint)->SetWidth(3*em); + GetColumn(colExtruder)->SetWidth(8*em); + } } void ObjectList::create_popup_menus() @@ -822,12 +831,18 @@ void ObjectList::list_manipulation(bool evt_context_menu/* = false*/) show_context_menu(evt_context_menu); else if (title == _("Name")) { - int obj_idx, vol_idx; - get_selected_item_indexes(obj_idx, vol_idx, item); + if (wxOSX) + show_context_menu(evt_context_menu); // return context menu under OSX (related to #2909) - if (is_windows10() && get_mesh_errors_count(obj_idx, vol_idx) > 0 && - pt.x > 2*wxGetApp().em_unit() && pt.x < 4*wxGetApp().em_unit() ) - fix_through_netfabb(); + if (is_windows10()) + { + int obj_idx, vol_idx; + get_selected_item_indexes(obj_idx, vol_idx, item); + + if (get_mesh_errors_count(obj_idx, vol_idx) > 0 && + pt.x > 2*wxGetApp().em_unit() && pt.x < 4*wxGetApp().em_unit() ) + fix_through_netfabb(); + } } #ifndef __WXMSW__ From 656569b0e9e836c628f85cabc16e6805382ac729 Mon Sep 17 00:00:00 2001 From: Lukas Matena <lukasmatena@seznam.cz> Date: Fri, 20 Sep 2019 16:45:43 +0200 Subject: [PATCH 07/12] Fix of https://github.com/prusa3d/PrusaSlicer/issues/2953 printf-like function argument mismatch: num was long, which was obfuscated by the auto keyword --- src/slic3r/GUI/Plater.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 18bc08d27..28474cac9 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -4336,14 +4336,14 @@ void Plater::set_number_of_copies(/*size_t num*/) ModelObject* model_object = p->model.objects[obj_idx]; - const auto num = wxGetNumberFromUser( " ", _("Enter the number of copies:"), + const int num = wxGetNumberFromUser( " ", _("Enter the number of copies:"), _("Copies of the selected object"), model_object->instances.size(), 0, 1000, this ); if (num < 0) return; Plater::TakeSnapshot snapshot(this, wxString::Format(_(L("Set numbers of copies to %d")), num)); - int diff = (int)num - (int)model_object->instances.size(); + int diff = num - (int)model_object->instances.size(); if (diff > 0) increase_instances(diff); else if (diff < 0) From 927ad5776ce309ed4155e8b6a36500738304f2bb Mon Sep 17 00:00:00 2001 From: Vojtech Kral <vojtech@kral.hk> Date: Fri, 20 Sep 2019 17:14:28 +0200 Subject: [PATCH 08/12] avrdude: Cherry-pick rev 1421 from upstream: Submitted by Reinhard Max patch #8311: Add IPv6 support to the -Pnet:host:port option * ser_posix.c (net_open): Rewrite to use getaddrinfo() rather than gethostbyname() Fix #2918 --- src/avrdude/ChangeLog | 9 ++++ src/avrdude/avrdude.1 | 7 +++ src/avrdude/configure.ac | 2 +- src/avrdude/doc/avrdude.texi | 5 ++ src/avrdude/ser_posix.c | 99 +++++++++++++++++++++--------------- 5 files changed, 81 insertions(+), 41 deletions(-) diff --git a/src/avrdude/ChangeLog b/src/avrdude/ChangeLog index 975f52317..879fbf957 100644 --- a/src/avrdude/ChangeLog +++ b/src/avrdude/ChangeLog @@ -1,3 +1,12 @@ +2018-01-17 Joerg Wunsch <j.gnu@uriah.heep.sax.de> +(cherry-picked) + Submitted by Reinhard Max + patch #8311: Add IPv6 support to the -Pnet:host:port option + * ser_posix.c (net_open): Rewrite to use getaddrinfo() + rather than gethostbyname() + * avrdude.1: Document IPv6 feature + * doc/avrdude.texi: (Dito) + 2016-05-10 Joerg Wunsch <j.gnu@uriah.heep.sax.de> Submitted by Hannes Jochriem: diff --git a/src/avrdude/avrdude.1 b/src/avrdude/avrdude.1 index 65fc7b1d6..47ca4edde 100644 --- a/src/avrdude/avrdude.1 +++ b/src/avrdude/avrdude.1 @@ -505,12 +505,19 @@ network connection to (TCP) on .Ar host is established. +Square brackets may be placed around +.Ar host +to improve readability, for numeric IPv6 addresses (e.g. +.Li net:[2001:db8::42]:1337 ) . The remote endpoint is assumed to be a terminal or console server that connects the network stream to a local serial port where the actual programmer has been attached to. The port is assumed to be properly configured, for example using a transparent 8-bit data connection without parity at 115200 Baud for a STK500. +.Pp +Note: The ability to handle IPv6 hostnames and addresses is limited to +Posix systems (by now). .It Fl q Disable (or quell) output of the progress bar while reading or writing to the device. Specify it a second time for even quieter operation. diff --git a/src/avrdude/configure.ac b/src/avrdude/configure.ac index a23a959f2..d14fc545f 100644 --- a/src/avrdude/configure.ac +++ b/src/avrdude/configure.ac @@ -214,7 +214,7 @@ AC_HEADER_TIME AC_CHECK_LIB([ws2_32], [puts]) # Checks for library functions. -AC_CHECK_FUNCS([memset select strcasecmp strdup strerror strncasecmp strtol strtoul gettimeofday usleep]) +AC_CHECK_FUNCS([memset select strcasecmp strdup strerror strncasecmp strtol strtoul gettimeofday usleep getaddrinfo]) AC_MSG_CHECKING([for a Win32 HID libray]) SAVED_LIBS="${LIBS}" diff --git a/src/avrdude/doc/avrdude.texi b/src/avrdude/doc/avrdude.texi index 6941389df..7062a9920 100644 --- a/src/avrdude/doc/avrdude.texi +++ b/src/avrdude/doc/avrdude.texi @@ -557,6 +557,9 @@ higher level protocol (as opposed to bit-bang style programmers), In this case, instead of trying to open a local device, a TCP network connection to (TCP) @var{port} on @var{host} is established. +Square brackets may be placed around @var{host} to improve +readability for numeric IPv6 addresses (e.g. +@code{net:[2001:db8::42]:1337}). The remote endpoint is assumed to be a terminal or console server that connects the network stream to a local serial port where the actual programmer has been attached to. @@ -564,6 +567,8 @@ The port is assumed to be properly configured, for example using a transparent 8-bit data connection without parity at 115200 Baud for a STK500. +Note: The ability to handle IPv6 hostnames and addresses is limited to +Posix systems (by now). @item -q Disable (or quell) output of the progress bar while reading or writing diff --git a/src/avrdude/ser_posix.c b/src/avrdude/ser_posix.c index 9992f78e3..dfa02f9fe 100644 --- a/src/avrdude/ser_posix.c +++ b/src/avrdude/ser_posix.c @@ -150,6 +150,7 @@ static int ser_setspeed(union filedescriptor *fd, long baud) return 0; } +#include "ac_cfg.h" // Timeout read & write variants // Additionally to the regular -1 on I/O error, they return -2 on timeout @@ -221,23 +222,35 @@ ssize_t write_timeout(int fd, const void *buf, size_t count, long timeout) static int net_open(const char *port, union filedescriptor *fdp) { - char *hstr, *pstr, *end; - unsigned int pnum; - int fd; - struct sockaddr_in sockaddr; - struct hostent *hp; +#ifdef HAVE_GETADDRINFO + char *hp, *hstr, *pstr; + int s, fd, ret = -1; + struct addrinfo hints; + struct addrinfo *result, *rp; - if ((hstr = strdup(port)) == NULL) { + if ((hstr = hp = strdup(port)) == NULL) { avrdude_message(MSG_INFO, "%s: net_open(): Out of memory!\n", progname); return -1; } - if (((pstr = strchr(hstr, ':')) == NULL) || (pstr == hstr)) { + /* + * As numeric IPv6 addresses use colons as separators, we need to + * look for the last colon here, which separates the port number or + * service name from the host or IP address. + */ + if (((pstr = strrchr(hstr, ':')) == NULL) || (pstr == hstr)) { avrdude_message(MSG_INFO, "%s: net_open(): Mangled host:port string \"%s\"\n", progname, hstr); - free(hstr); - return -1; + goto error; + } + + /* + * Remove brackets from the host part, if present. + */ + if (*hstr == '[' && *(pstr-1) == ']') { + hstr++; + *(pstr-1) = '\0'; } /* @@ -245,43 +258,49 @@ net_open(const char *port, union filedescriptor *fdp) */ *pstr++ = '\0'; - pnum = strtoul(pstr, &end, 10); + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + s = getaddrinfo(hstr, pstr, &hints, &result); - if ((*pstr == '\0') || (*end != '\0') || (pnum == 0) || (pnum > 65535)) { - avrdude_message(MSG_INFO, "%s: net_open(): Bad port number \"%s\"\n", - progname, pstr); - free(hstr); - return -1; + if (s != 0) { + avrdude_message(MSG_INFO, + "%s: net_open(): Cannot resolve " + "host=\"%s\", port=\"%s\": %s\n", + progname, hstr, pstr, gai_strerror(s)); + goto error; } - - if ((hp = gethostbyname(hstr)) == NULL) { - avrdude_message(MSG_INFO, "%s: net_open(): unknown host \"%s\"\n", - progname, hstr); - free(hstr); - return -1; + for (rp = result; rp != NULL; rp = rp->ai_next) { + fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if (fd == -1) { + /* This one failed, loop over */ + continue; + } + if (connect(fd, rp->ai_addr, rp->ai_addrlen) != -1) { + /* Success, we are connected */ + break; + } + close(fd); } - - free(hstr); - - if ((fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { - avrdude_message(MSG_INFO, "%s: net_open(): Cannot open socket: %s\n", - progname, strerror(errno)); - return -1; + if (rp == NULL) { + avrdude_message(MSG_INFO, "%s: net_open(): Cannot connect: %s\n", + progname, strerror(errno)); } - - memset(&sockaddr, 0, sizeof(struct sockaddr_in)); - sockaddr.sin_family = AF_INET; - sockaddr.sin_port = htons(pnum); - memcpy(&(sockaddr.sin_addr.s_addr), hp->h_addr, sizeof(struct in_addr)); - - if (connect(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr))) { - avrdude_message(MSG_INFO, "%s: net_open(): Connect failed: %s\n", - progname, strerror(errno)); - return -1; + else { + fdp->ifd = fd; + ret = 0; } + freeaddrinfo(result); - fdp->ifd = fd; - return 0; +error: + free(hp); + return ret; +#else + avrdude_message(MSG_INFO, + "%s: Networking is not supported on your platform.\n" + "If you need it, please open a bug report.\n", progname); + return -1; +#endif /* HAVE_GETADDRINFO */ } From 4e22761f95e4490a90353600c4569eee71fceb13 Mon Sep 17 00:00:00 2001 From: YuSanka <yusanka@gmail.com> Date: Mon, 23 Sep 2019 10:17:53 +0200 Subject: [PATCH 09/12] Fix of #2977 --- src/slic3r/GUI/GUI_ObjectList.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 1d5d8f1a5..d4766ee72 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -810,8 +810,13 @@ void ObjectList::list_manipulation(bool evt_context_menu/* = false*/) */ if (!item) { - if (wxOSX && col == nullptr) - UnselectAll(); + if (col == nullptr) { + if (wxOSX) + UnselectAll(); + else + return; + } + if (evt_context_menu) { show_context_menu(evt_context_menu); return; @@ -1330,7 +1335,7 @@ wxMenu* ObjectList::append_submenu_add_generic(wxMenu* menu, const ModelVolumeTy for (auto& item : { L("Box"), L("Cylinder"), L("Sphere"), L("Slab") }) { - if (type == ModelVolumeType::INVALID && item == "Slab") + if (type == ModelVolumeType::INVALID && strncmp(item, "Slab", 4) == 0) continue; append_menu_item(sub_menu, wxID_ANY, _(item), "", [this, type, item](wxCommandEvent&) { load_generic_subobject(item, type); }, "", menu); From 4aec14ddabf35537cc53678e6cb21d6eb9410dd0 Mon Sep 17 00:00:00 2001 From: YuSanka <yusanka@gmail.com> Date: Mon, 23 Sep 2019 11:11:43 +0200 Subject: [PATCH 10/12] =?UTF-8?q?Replace=20"mm3/s"=20with=20"mm=C2=B3/s"?= =?UTF-8?q?=20in=20preview=20legend=20for=20a=20"Volumetric=20flow=20rate"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/libslic3r/GCode/PreviewData.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libslic3r/GCode/PreviewData.cpp b/src/libslic3r/GCode/PreviewData.cpp index 74de2f532..76f21daeb 100644 --- a/src/libslic3r/GCode/PreviewData.cpp +++ b/src/libslic3r/GCode/PreviewData.cpp @@ -359,7 +359,7 @@ std::string GCodePreviewData::get_legend_title() const case Extrusion::Feedrate: return L("Speed (mm/s)"); case Extrusion::VolumetricRate: - return L("Volumetric flow rate (mm3/s)"); + return L("Volumetric flow rate (mm³/s)"); case Extrusion::Tool: return L("Tool"); case Extrusion::ColorPrint: From a6f5fe7bea91e4b89e9a462df1fec2d371b1a30d Mon Sep 17 00:00:00 2001 From: tamasmeszaros <meszaros.q@gmail.com> Date: Mon, 23 Sep 2019 11:58:39 +0200 Subject: [PATCH 11/12] Fix arrange crash with incorrect geometries. Guard the case with tests. --- .../libnest2d/backends/clipper/geometries.hpp | 19 ++-- .../include/libnest2d/geometry_traits.hpp | 2 +- .../include/libnest2d/placers/nfpplacer.hpp | 73 +------------- .../selections/selection_boilerplate.hpp | 2 +- src/libnest2d/tests/test.cpp | 98 +++++++++++++------ src/libslic3r/Arrange.cpp | 18 ++-- 6 files changed, 92 insertions(+), 120 deletions(-) diff --git a/src/libnest2d/include/libnest2d/backends/clipper/geometries.hpp b/src/libnest2d/include/libnest2d/backends/clipper/geometries.hpp index 56330e15e..57da6ec12 100644 --- a/src/libnest2d/include/libnest2d/backends/clipper/geometries.hpp +++ b/src/libnest2d/include/libnest2d/backends/clipper/geometries.hpp @@ -81,17 +81,16 @@ inline void offset(PolygonImpl& sh, TCoord<PointImpl> distance, const PolygonTag using ClipperLib::etClosedPolygon; using ClipperLib::Paths; - // If the input is not at least a triangle, we can not do this algorithm - if(sh.Contour.size() <= 3 || - std::any_of(sh.Holes.begin(), sh.Holes.end(), - [](const PathImpl& p) { return p.size() <= 3; }) - ) throw GeometryException(GeomErr::OFFSET); - - ClipperOffset offs; Paths result; - offs.AddPath(sh.Contour, jtMiter, etClosedPolygon); - offs.AddPaths(sh.Holes, jtMiter, etClosedPolygon); - offs.Execute(result, static_cast<double>(distance)); + + try { + ClipperOffset offs; + offs.AddPath(sh.Contour, jtMiter, etClosedPolygon); + offs.AddPaths(sh.Holes, jtMiter, etClosedPolygon); + offs.Execute(result, static_cast<double>(distance)); + } catch (ClipperLib::clipperException &) { + throw GeometryException(GeomErr::OFFSET); + } // Offsetting reverts the orientation and also removes the last vertex // so boost will not have a closed polygon. diff --git a/src/libnest2d/include/libnest2d/geometry_traits.hpp b/src/libnest2d/include/libnest2d/geometry_traits.hpp index 827e2d8ba..72e239a70 100644 --- a/src/libnest2d/include/libnest2d/geometry_traits.hpp +++ b/src/libnest2d/include/libnest2d/geometry_traits.hpp @@ -1144,7 +1144,7 @@ inline bool isInside(const TBGuest& ibb, const TBHost& box, auto minY = getY(box.minCorner()); auto maxY = getY(box.maxCorner()); - return iminX > minX && imaxX < maxX && iminY > minY && imaxY < maxY; + return iminX >= minX && imaxX <= maxX && iminY >= minY && imaxY <= maxY; } template<class S, class TB> diff --git a/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp b/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp index 1a341d691..686857a87 100644 --- a/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp +++ b/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp @@ -3,9 +3,6 @@ #include <cassert> -// For caching nfps -#include <unordered_map> - // For parallel for #include <functional> #include <iterator> @@ -76,55 +73,6 @@ inline void enumerate( } -namespace __itemhash { - -using Key = size_t; - -template<class S> -Key hash(const _Item<S>& item) { - using Point = TPoint<S>; - using Segment = _Segment<Point>; - - static const int N = 26; - static const int M = N*N - 1; - - std::string ret; - auto& rhs = item.rawShape(); - auto& ctr = sl::contour(rhs); - auto it = ctr.begin(); - auto nx = std::next(it); - - double circ = 0; - while(nx != ctr.end()) { - Segment seg(*it++, *nx++); - Radians a = seg.angleToXaxis(); - double deg = Degrees(a); - int ms = 'A', ls = 'A'; - while(deg > N) { ms++; deg -= N; } - ls += int(deg); - ret.push_back(char(ms)); ret.push_back(char(ls)); - circ += std::sqrt(seg.template sqlength<double>()); - } - - it = ctr.begin(); nx = std::next(it); - - while(nx != ctr.end()) { - Segment seg(*it++, *nx++); - auto l = int(M * std::sqrt(seg.template sqlength<double>()) / circ); - int ms = 'A', ls = 'A'; - while(l > N) { ms++; l -= N; } - ls += l; - ret.push_back(char(ms)); ret.push_back(char(ls)); - } - - return std::hash<std::string>()(ret); -} - -template<class S> -using Hash = std::unordered_map<Key, nfp::NfpResult<S>>; - -} - namespace placers { template<class RawShape> @@ -529,17 +477,9 @@ class _NofitPolyPlacer: public PlacerBoilerplate<_NofitPolyPlacer<RawShape, TBin using MaxNfpLevel = nfp::MaxNfpLevel<RawShape>; - using ItemKeys = std::vector<__itemhash::Key>; - // Norming factor for the optimization function const double norm_; - // Caching calculated nfps - __itemhash::Hash<RawShape> nfpcache_; - - // Storing item hash keys - ItemKeys item_keys_; - public: using Pile = nfp::Shapes<RawShape>; @@ -636,15 +576,12 @@ public: private: using Shapes = TMultiShape<RawShape>; - using ItemRef = std::reference_wrapper<Item>; - using ItemWithHash = const std::pair<ItemRef, __itemhash::Key>; - Shapes calcnfp(const ItemWithHash itsh, Lvl<nfp::NfpLevel::CONVEX_ONLY>) + Shapes calcnfp(const Item &trsh, Lvl<nfp::NfpLevel::CONVEX_ONLY>) { using namespace nfp; Shapes nfps(items_.size()); - const Item& trsh = itsh.first; // ///////////////////////////////////////////////////////////////////// // TODO: this is a workaround and should be solved in Item with mutexes @@ -678,12 +615,11 @@ private: template<class Level> - Shapes calcnfp( const ItemWithHash itsh, Level) + Shapes calcnfp(const Item &trsh, Level) { // Function for arbitrary level of nfp implementation using namespace nfp; Shapes nfps; - const Item& trsh = itsh.first; auto& orb = trsh.transformedShape(); bool orbconvex = trsh.isContourConvex(); @@ -849,8 +785,6 @@ private: remlist.insert(remlist.end(), remaining.from, remaining.to); } - size_t itemhash = __itemhash::hash(item); - if(items_.empty()) { setInitialPosition(item); best_overfit = overfit(item.transformedShape(), bin_); @@ -875,7 +809,7 @@ private: // it is disjunct from the current merged pile placeOutsideOfBin(item); - nfps = calcnfp({item, itemhash}, Lvl<MaxNfpLevel::value>()); + nfps = calcnfp(item, Lvl<MaxNfpLevel::value>()); auto iv = item.referenceVertex(); @@ -1112,7 +1046,6 @@ private: if(can_pack) { ret = PackResult(item); - item_keys_.emplace_back(itemhash); } else { ret = PackResult(best_overfit); } diff --git a/src/libnest2d/include/libnest2d/selections/selection_boilerplate.hpp b/src/libnest2d/include/libnest2d/selections/selection_boilerplate.hpp index 2df9a26c3..36fec7164 100644 --- a/src/libnest2d/include/libnest2d/selections/selection_boilerplate.hpp +++ b/src/libnest2d/include/libnest2d/selections/selection_boilerplate.hpp @@ -43,7 +43,7 @@ protected: Placer p{bin}; p.configure(pcfg); - if (!p.pack(cpy)) it = c.erase(it); + if (itm.area() <= 0 || !p.pack(cpy)) it = c.erase(it); else it++; } } diff --git a/src/libnest2d/tests/test.cpp b/src/libnest2d/tests/test.cpp index 4a6691415..5ba28228a 100644 --- a/src/libnest2d/tests/test.cpp +++ b/src/libnest2d/tests/test.cpp @@ -40,7 +40,7 @@ struct NfpImpl<S, NfpLevel::CONVEX_ONLY> } } -std::vector<libnest2d::Item>& prusaParts() { +static std::vector<libnest2d::Item>& prusaParts() { static std::vector<libnest2d::Item> ret; if(ret.empty()) { @@ -51,7 +51,7 @@ std::vector<libnest2d::Item>& prusaParts() { return ret; } -TEST(BasicFunctionality, Angles) +TEST(GeometryAlgorithms, Angles) { using namespace libnest2d; @@ -109,7 +109,7 @@ TEST(BasicFunctionality, Angles) } // Simple test, does not use gmock -TEST(BasicFunctionality, creationAndDestruction) +TEST(Nesting, ItemCreationAndDestruction) { using namespace libnest2d; @@ -572,26 +572,74 @@ TEST(GeometryAlgorithms, convexHull) { } -TEST(GeometryAlgorithms, NestTest) { +TEST(Nesting, NestPrusaPartsShouldFitIntoTwoBins) { + + // Get the input items and define the bin. std::vector<Item> input = prusaParts(); - - libnest2d::nest(input, Box(250000000, 210000000), [](unsigned cnt) { - std::cout << "parts left: " << cnt << std::endl; + auto bin = Box(250000000, 210000000); + + // Do the nesting. Check in each step if the remaining items are less than + // in the previous step. (Some algorithms can place more items in one step) + size_t pcount = input.size(); + libnest2d::nest(input, bin, [&pcount](unsigned cnt) { + ASSERT_TRUE(cnt < pcount); + pcount = cnt; }); - + + // Get the number of logical bins: search for the max binId... auto max_binid_it = std::max_element(input.begin(), input.end(), [](const Item &i1, const Item &i2) { return i1.binId() < i2.binId(); }); - - size_t bins = max_binid_it == input.end() ? 0 : max_binid_it->binId() + 1; - ASSERT_EQ(bins, 2u); - + auto bins = size_t(max_binid_it == input.end() ? 0 : + max_binid_it->binId() + 1); + + // For prusa parts, 2 bins should be enough... + ASSERT_LE(bins, 2u); + + // All parts should be processed by the algorithm ASSERT_TRUE( std::all_of(input.begin(), input.end(), [](const Item &itm) { return itm.binId() != BIN_ID_UNSET; })); + + // Gather the items into piles of arranged polygons... + using Pile = TMultiShape<ClipperLib::Polygon>; + std::vector<Pile> piles(bins); + + for (auto &itm : input) + piles[size_t(itm.binId())].emplace_back(itm.transformedShape()); + + // Now check all the piles, the bounding box of each pile should be inside + // the defined bin. + for (auto &pile : piles) { + auto bb = sl::boundingBox(pile); + ASSERT_TRUE(sl::isInside(bb, bin)); + } +} + +TEST(Nesting, NestEmptyItemShouldBeUntouched) { + auto bin = Box(250000000, 210000000); // dummy bin + + std::vector<Item> items; + items.emplace_back(Item{}); // Emplace empty item + items.emplace_back(Item{0, 200, 0}); // Emplace zero area item + + libnest2d::nest(items, bin); + + for (auto &itm : items) ASSERT_EQ(itm.binId(), BIN_ID_UNSET); +} + +TEST(Nesting, NestLargeItemShouldBeUntouched) { + auto bin = Box(250000000, 210000000); // dummy bin + + std::vector<Item> items; + items.emplace_back(Rectangle{250000001, 210000001}); // Emplace large item + + libnest2d::nest(items, bin); + + ASSERT_EQ(items.front().binId(), BIN_ID_UNSET); } namespace { @@ -966,26 +1014,20 @@ using Ratio = boost::rational<boost::multiprecision::int128_t>; } -TEST(RotatingCalipers, MinAreaBBCClk) { - auto u = [](ClipperLib::cInt n) { return n*1000000; }; - PolygonImpl poly({ {u(0), u(0)}, {u(4), u(1)}, {u(2), u(4)}}); +//TEST(GeometryAlgorithms, MinAreaBBCClk) { +// auto u = [](ClipperLib::cInt n) { return n*1000000; }; +// PolygonImpl poly({ {u(0), u(0)}, {u(4), u(1)}, {u(2), u(4)}}); - long double arearef = refMinAreaBox(poly); - long double area = minAreaBoundingBox<PolygonImpl, Unit, Ratio>(poly).area(); +// long double arearef = refMinAreaBox(poly); +// long double area = minAreaBoundingBox<PolygonImpl, Unit, Ratio>(poly).area(); - ASSERT_LE(std::abs(area - arearef), 500e6 ); -} +// ASSERT_LE(std::abs(area - arearef), 500e6 ); +//} -TEST(RotatingCalipers, AllPrusaMinBB) { - // /size_t idx = 0; +TEST(GeometryAlgorithms, MinAreaBBWithRotatingCalipers) { long double err_epsilon = 500e6l; for(ClipperLib::Path rinput : PRINTER_PART_POLYGONS) { - // ClipperLib::Path rinput = PRINTER_PART_POLYGONS[idx]; - // rinput.pop_back(); - // std::reverse(rinput.begin(), rinput.end()); - - // PolygonImpl poly(removeCollinearPoints<PathImpl, PointImpl, Unit>(rinput, 1000000)); PolygonImpl poly(rinput); long double arearef = refMinAreaBox(poly); @@ -993,8 +1035,6 @@ TEST(RotatingCalipers, AllPrusaMinBB) { long double area = cast<long double>(bb.area()); bool succ = std::abs(arearef - area) < err_epsilon; - // std::cout << idx++ << " " << (succ? "ok" : "failed") << " ref: " -// << arearef << " actual: " << area << std::endl; ASSERT_TRUE(succ); } @@ -1011,8 +1051,6 @@ TEST(RotatingCalipers, AllPrusaMinBB) { bool succ = std::abs(arearef - area) < err_epsilon; - // std::cout << idx++ << " " << (succ? "ok" : "failed") << " ref: " -// << arearef << " actual: " << area << std::endl; ASSERT_TRUE(succ); } diff --git a/src/libslic3r/Arrange.cpp b/src/libslic3r/Arrange.cpp index 52168c929..20dfd8926 100644 --- a/src/libslic3r/Arrange.cpp +++ b/src/libslic3r/Arrange.cpp @@ -618,19 +618,21 @@ void arrange(ArrangePolygons & arrangables, items.reserve(arrangables.size()); // Create Item from Arrangeable - auto process_arrangeable = - [](const ArrangePolygon &arrpoly, std::vector<Item> &outp) + auto process_arrangeable = [](const ArrangePolygon &arrpoly, + std::vector<Item> & outp) { - Polygon p = arrpoly.poly.contour; - const Vec2crd & offs = arrpoly.translation; - double rotation = arrpoly.rotation; + Polygon p = arrpoly.poly.contour; + const Vec2crd &offs = arrpoly.translation; + double rotation = arrpoly.rotation; if (p.is_counter_clockwise()) p.reverse(); clppr::Polygon clpath(Slic3rMultiPoint_to_ClipperPath(p)); - - auto firstp = clpath.Contour.front(); - clpath.Contour.emplace_back(firstp); + + if (!clpath.Contour.empty()) { + auto firstp = clpath.Contour.front(); + clpath.Contour.emplace_back(firstp); + } outp.emplace_back(std::move(clpath)); outp.back().rotation(rotation); From c0c937425f17a03a484ac6af28a2a515dbf4d17b Mon Sep 17 00:00:00 2001 From: YuSanka <yusanka@gmail.com> Date: Mon, 23 Sep 2019 14:24:53 +0200 Subject: [PATCH 12/12] Added missed comment to https://github.com/prusa3d/PrusaSlicer/commit/7e060f84bd534fb027bdc3a1f4b48cce912090bd --- src/slic3r/GUI/GUI_ObjectList.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index d4766ee72..573fbe980 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -273,6 +273,8 @@ void ObjectList::create_objects_ctrl() AppendBitmapColumn(_(L("Editing")), colEditing, wxDATAVIEW_CELL_INERT, 3*em, wxALIGN_CENTER_HORIZONTAL, wxDATAVIEW_COL_RESIZABLE); + // For some reason under OSX on 4K(5K) monitors in wxDataViewColumn constructor doesn't set width of column. + // Therefore, force set column width. if (wxOSX) { GetColumn(colName)->SetWidth(20*em); @@ -3682,10 +3684,10 @@ void ObjectList::msw_rescale() // update min size !!! A width of control shouldn't be a wxDefaultCoord SetMinSize(wxSize(1, 15 * em)); - GetColumn(colName)->SetWidth(19 * em); - GetColumn(colPrint)->SetWidth( 2 * em); + GetColumn(colName )->SetWidth(20 * em); + GetColumn(colPrint )->SetWidth( 3 * em); GetColumn(colExtruder)->SetWidth( 8 * em); - GetColumn(colEditing)->SetWidth( 2 * em); + GetColumn(colEditing )->SetWidth( 3 * em); // rescale all icons, used by ObjectList msw_rescale_icons();