From 17c2f3d81306d0d1f280821ae49ee128e9edf683 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Wed, 19 Dec 2018 15:40:07 +0100 Subject: [PATCH 01/26] Http: Set a sane default connection timeout --- src/slic3r/Utils/Http.cpp | 9 +++++++++ src/slic3r/Utils/Http.hpp | 2 ++ 2 files changed, 11 insertions(+) diff --git a/src/slic3r/Utils/Http.cpp b/src/slic3r/Utils/Http.cpp index 6e6c9ed44..27f713127 100644 --- a/src/slic3r/Utils/Http.cpp +++ b/src/slic3r/Utils/Http.cpp @@ -32,6 +32,7 @@ class CurlGlobalInit struct Http::priv { enum { + DEFAULT_TIMEOUT = 10, DEFAULT_SIZE_LIMIT = 5 * 1024 * 1024, }; @@ -84,6 +85,7 @@ Http::priv::priv(const std::string &url) throw std::runtime_error(std::string("Could not construct Curl object")); } + ::curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, DEFAULT_TIMEOUT); ::curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); // curl makes a copy internally ::curl_easy_setopt(curl, CURLOPT_USERAGENT, SLIC3R_FORK_NAME "/" SLIC3R_VERSION); ::curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, &error_buffer.front()); @@ -293,6 +295,13 @@ Http::~Http() } +Http& Http::timeout(long timeout) +{ + if (timeout < 1) { timeout = priv::DEFAULT_TIMEOUT; } + if (p) { ::curl_easy_setopt(p->curl, CURLOPT_CONNECTTIMEOUT, timeout); } + return *this; +} + Http& Http::size_limit(size_t sizeLimit) { if (p) { p->limit = sizeLimit; } diff --git a/src/slic3r/Utils/Http.hpp b/src/slic3r/Utils/Http.hpp index fd3f8830d..9406a82f2 100644 --- a/src/slic3r/Utils/Http.hpp +++ b/src/slic3r/Utils/Http.hpp @@ -55,6 +55,8 @@ public: Http& operator=(const Http &) = delete; Http& operator=(Http &&) = delete; + // Sets a maximum connection timeout in seconds + Http& timeout(long timeout); // Sets a maximum size of the data that can be received. // A value of zero sets the default limit, which is is 5MB. Http& size_limit(size_t sizeLimit); From 4c55f1ce9e57537abf9502ef9f4af9b7bf8da579 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Wed, 19 Dec 2018 15:58:01 +0100 Subject: [PATCH 02/26] DoubleSlider issues (1 & 3 from SPE-686) + added icon for "Keyboard shortcuts" dialog --- resources/icons/Slic3r_32px.png | Bin 0 -> 1771 bytes src/slic3r/GUI/GUI_Preview.cpp | 3 ++- src/slic3r/GUI/wxExtensions.cpp | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 resources/icons/Slic3r_32px.png diff --git a/resources/icons/Slic3r_32px.png b/resources/icons/Slic3r_32px.png new file mode 100644 index 0000000000000000000000000000000000000000..6bf5a9cd144b3059b70071bc978ca369b7b54778 GIT binary patch literal 1771 zcmV;P)~26#zC zK~z}7?U!9_99I>`f9Kwro!zy)j@ORkq)wbP2~r3&n5L+OBtj*53QdAai^@k4>O&w3Mrvomw={!Q8F$XGZ5|iW&1q;7`DWjJaCJAa_6?hRCr5Bx~*IwQ(u~Y)$p>p|j@-eZQM39O>=t!t=Zp zo-3u6L6#kH4uB*{$Y;IeE1&H9%M;%cIdLHV+n4rS{ubwxe*!TF(49s^0|USZ<|5tu!iBC8ixe`M%nAst zHJ<0Kf@y_#WdG7XzOeVLZ}9Go3o_;sH!fZ~U9JTZq#(QhFd1a8mHmCqj1Uo$Bq0a_ zeBWOM(*)7jzPgI!^@F~qKJGxkLP*# zzK`d5c%HW`R9~z;bRf3TI2gZxt!-7ecspHF;-lDH4u!0<-joO3HGsMfg0 z?!P*Dq<21+w}-MArAX?m1aSqDV067`v;#?+DK?Zd^UcX9il|g7IOo#J>Gj?yNWC1S+S?$AFo$sIK!05R_Wg^O%jGiFYLzeydFJ7F7LNDM8}+82r5bCJ zaCH=*F;_1`Q~?uJQxMxOGHZ*~Fb7=lwf*&HKN!AxbXWP-?CdOOJ~37P+=#E#RI!Ix z>9+1!3t<_OumNMu^(I8el~u-^bEl<>$1OC~Y>vs7pB4|)DUzXW*nuvbYM%i~y`dEo zLAcoXRs4OuXteJ~4q$*PbwXkmfC@5l7+bivErf|74jUlOKz$M7DnKO#X&a688Y2NL z0gjPR*O-`mjGBz%oVV%~m^vg8*yMeyFF{gkq^|G_G!u8rn!9)LKfLc*BK0h>&Eagr zTWiuyO+%E;`MB1w_cLe##W6N>PM&eLW02+tsTo4|UHK;U%vmJpLV2LmzDA_sZ4=1E zVB^OBmC^qi@M6a&JvT10y!m)~q`b=W)c7ivEdSkj9ylXouG-1X%8iR|P2&_uk=fXh zv{kmicYxh+u^S1WuUUT6>0;%G*M5Ipp8ELD)vvtot1hi| zQ7P4}l=6MwSDxp!bxhp26o9Hc>5>$rM=3R$B*}K5d(S3{4{vwFr}l8)!6EkbXX$TU zV4=>!>(g9$_$mMZ N002ovPDHLkV1i@hUjYCB literal 0 HcmV?d00001 diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index 735b55125..2885a3d16 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -587,7 +587,8 @@ void Preview::create_double_slider() auto& config = wxGetApp().preset_bundle->project_config; ((config.option("colorprint_heights"))->values) = (m_slider->GetTicksValues()); m_schedule_background_process(); - int type = m_choice_view_type->FindString(_(L("Color Print"))); + bool color_print = !config.option("colorprint_heights")->values.empty(); + int type = m_choice_view_type->FindString(color_print ? _(L("Color Print")) : _(L("Feature type")) ); if (m_choice_view_type->GetSelection() != type) { m_choice_view_type->SetSelection(type); if ((0 <= type) && (type < (int)GCodePreviewData::Extrusion::Num_View_Types)) diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index 2daba5df4..b8b76f049 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -2043,7 +2043,7 @@ void PrusaDoubleSlider::enter_window(wxMouseEvent& event, const bool enter) // - value decrease (if wxSL_HORIZONTAL) void PrusaDoubleSlider::move_current_thumb(const bool condition) { - m_is_one_layer = wxGetKeyState(WXK_CONTROL); +// m_is_one_layer = wxGetKeyState(WXK_CONTROL); int delta = condition ? -1 : 1; if (is_horizontal()) delta *= -1; From c40b8aba2410e09984d9025c383e10287955e7a6 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Wed, 19 Dec 2018 17:38:41 +0100 Subject: [PATCH 03/26] Fixed recreate_GUI() after language change. --- src/slic3r/GUI/GUI_App.cpp | 20 +++++++++++++++++--- src/slic3r/GUI/GUI_App.hpp | 1 - src/slic3r/GUI/MainFrame.cpp | 12 ++++-------- src/slic3r/GUI/MainFrame.hpp | 8 ++------ 4 files changed, 23 insertions(+), 18 deletions(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 2998ea7f3..bbba1d93b 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -137,7 +137,7 @@ bool GUI_App::OnInit() std::cerr << "Creating main frame..." << std::endl; if (wxImage::FindHandler(wxBITMAP_TYPE_PNG) == nullptr) wxImage::AddHandler(new wxPNGHandler()); - mainframe = new MainFrame(no_plater, false); + mainframe = new MainFrame(); sidebar().obj_list()->init_objects(); // propagate model objects to object list update_mode(); SetTopWindow(mainframe); @@ -277,8 +277,8 @@ void GUI_App::recreate_GUI() { std::cerr << "recreate_GUI" << std::endl; - auto topwindow = GetTopWindow(); - mainframe = new MainFrame(no_plater,false); + MainFrame* topwindow = dynamic_cast(GetTopWindow()); + mainframe = new MainFrame(); sidebar().obj_list()->init_objects(); // propagate model objects to object list update_mode(); @@ -287,6 +287,20 @@ void GUI_App::recreate_GUI() topwindow->Destroy(); } + m_printhost_job_queue.reset(new PrintHostJobQueue(mainframe->printhost_queue_dlg())); + + CallAfter([this]() { + // temporary workaround for the correct behavior of the Scrolled sidebar panel + auto& panel = sidebar(); + if (panel.obj_list()->GetMinHeight() > 200) { + wxWindowUpdateLocker noUpdates_sidebar(&panel); + panel.obj_list()->SetMinSize(wxSize(-1, 200)); + panel.Layout(); + } + }); + + mainframe->Show(true); + // On OSX the UI was not initialized correctly if the wizard was called // before the UI was up and running. CallAfter([]() { diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index 81175b7ca..bd64a3ac5 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -71,7 +71,6 @@ static wxString dots("…", wxConvUTF8); class GUI_App : public wxApp { - bool no_plater{ false }; bool app_conf_exists{ false }; // Lock to guard the callback stack diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 2211023f0..871d50a3d 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -28,10 +28,8 @@ namespace Slic3r { namespace GUI { -MainFrame::MainFrame(const bool no_plater, const bool loaded) : +MainFrame::MainFrame() : wxFrame(NULL, wxID_ANY, SLIC3R_BUILD, wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE), - m_no_plater(no_plater), - m_loaded(loaded), m_printhost_queue_dlg(new PrintHostQueueDialog(this)) { // Load the icon either from the exe, or from the ico file. @@ -125,11 +123,9 @@ void MainFrame::init_tabpanel() } }); - if (!m_no_plater) { - m_plater = new Slic3r::GUI::Plater(m_tabpanel, this); - wxGetApp().plater_ = m_plater; - m_tabpanel->AddPage(m_plater, _(L("Plater"))); - } + m_plater = new Slic3r::GUI::Plater(m_tabpanel, this); + wxGetApp().plater_ = m_plater; + m_tabpanel->AddPage(m_plater, _(L("Plater"))); // The following event is emited by Tab implementation on config value change. Bind(EVT_TAB_VALUE_CHANGED, &MainFrame::on_value_changed, this); diff --git a/src/slic3r/GUI/MainFrame.hpp b/src/slic3r/GUI/MainFrame.hpp index fab6aea90..e0411b6da 100644 --- a/src/slic3r/GUI/MainFrame.hpp +++ b/src/slic3r/GUI/MainFrame.hpp @@ -42,10 +42,7 @@ struct PresetTab { class MainFrame : public wxFrame { - bool m_no_plater; - bool m_loaded; - int m_lang_ch_event; - int m_preferences_event; + bool m_loaded {false}; wxString m_qs_last_input_file = wxEmptyString; wxString m_qs_last_output_file = wxEmptyString; @@ -71,8 +68,7 @@ class MainFrame : public wxFrame bool can_delete_all() const; public: - MainFrame() {} - MainFrame(const bool no_plater, const bool loaded); + MainFrame(); ~MainFrame() {} Plater* plater() { return m_plater; } From 3b2c28fa89994230b86a0eb6e681d3ab670e3e6e Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Wed, 19 Dec 2018 18:43:03 +0100 Subject: [PATCH 04/26] Printhost: Polish error handling, bugfixes --- src/slic3r/GUI/PrintHostDialogs.cpp | 10 ++++++++-- src/slic3r/Utils/Duet.cpp | 4 ++-- src/slic3r/Utils/Duet.hpp | 2 +- src/slic3r/Utils/Http.cpp | 15 +++++++++++---- src/slic3r/Utils/OctoPrint.cpp | 21 +++++++++------------ src/slic3r/Utils/OctoPrint.hpp | 2 +- src/slic3r/Utils/PrintHost.cpp | 26 +++++++++++++++----------- src/slic3r/Utils/PrintHost.hpp | 6 +++++- 8 files changed, 52 insertions(+), 34 deletions(-) diff --git a/src/slic3r/GUI/PrintHostDialogs.cpp b/src/slic3r/GUI/PrintHostDialogs.cpp index 8ac8615a8..586fe3d83 100644 --- a/src/slic3r/GUI/PrintHostDialogs.cpp +++ b/src/slic3r/GUI/PrintHostDialogs.cpp @@ -102,7 +102,7 @@ PrintHostQueueDialog::PrintHostQueueDialog(wxWindow *parent) job_list->AppendTextColumn("Filename", wxDATAVIEW_CELL_INERT); auto *btnsizer = new wxBoxSizer(wxHORIZONTAL); - auto *btn_cancel = new wxButton(this, wxID_DELETE, _(L("Cancel selected"))); + auto *btn_cancel = new wxButton(this, wxID_DELETE, _(L("Cancel selected"))); // TODO: enable based on status ("show error" for failed jobs) auto *btn_close = new wxButton(this, wxID_CANCEL, _(L("Close"))); btnsizer->Add(btn_cancel, 0, wxRIGHT, SPACING); btnsizer->AddStretchSpacer(); @@ -140,7 +140,13 @@ void PrintHostQueueDialog::on_error(Event &evt) { wxCHECK_RET(evt.job_id < job_list->GetItemCount(), "Out of bounds access to job list"); - // TODO + job_list->SetValue(wxVariant(0), evt.job_id, 1); + job_list->SetValue(wxVariant(_(L("Error"))), evt.job_id, 2); + + // TODO: keep the error for repeated display + + auto errormsg = wxString::Format("%s\n%s", _(L("Error uploading to print host:")), evt.error); + GUI::show_error(nullptr, std::move(errormsg)); } diff --git a/src/slic3r/Utils/Duet.cpp b/src/slic3r/Utils/Duet.cpp index 1772ae8ef..fd77fc130 100644 --- a/src/slic3r/Utils/Duet.cpp +++ b/src/slic3r/Utils/Duet.cpp @@ -46,7 +46,7 @@ bool Duet::test(wxString &msg) const wxString Duet::get_test_ok_msg () const { - return wxString::Format("%s", _(L("Connection to Duet works correctly."))); + return _(L("Connection to Duet works correctly.")); } wxString Duet::get_test_failed_msg (wxString &msg) const @@ -135,7 +135,7 @@ wxString Duet::get_test_failed_msg (wxString &msg) const // return res; // } -bool Duet::upload(PrintHostUpload upload_data, Http::ProgressFn prorgess_fn, Http::ErrorFn error_fn) const +bool Duet::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const { // XXX: TODO throw "unimplemented"; diff --git a/src/slic3r/Utils/Duet.hpp b/src/slic3r/Utils/Duet.hpp index d0f5b3009..e053f91ef 100644 --- a/src/slic3r/Utils/Duet.hpp +++ b/src/slic3r/Utils/Duet.hpp @@ -22,7 +22,7 @@ public: virtual bool test(wxString &curl_msg) const; virtual wxString get_test_ok_msg () const; virtual wxString get_test_failed_msg (wxString &msg) const; - virtual bool upload(PrintHostUpload upload_data, Http::ProgressFn prorgess_fn, Http::ErrorFn error_fn) const; + virtual bool upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const; virtual bool has_auto_discovery() const; virtual bool can_test() const; virtual std::string get_host() const { return host; } diff --git a/src/slic3r/Utils/Http.cpp b/src/slic3r/Utils/Http.cpp index 27f713127..30478cb01 100644 --- a/src/slic3r/Utils/Http.cpp +++ b/src/slic3r/Utils/Http.cpp @@ -64,6 +64,7 @@ struct Http::priv static int xfercb_legacy(void *userp, double dltotal, double dlnow, double ultotal, double ulnow); static size_t form_file_read_cb(char *buffer, size_t size, size_t nitems, void *userp); + void set_timeout(long timeout); void form_add_file(const char *name, const fs::path &path, const char* filename); void set_post_body(const fs::path &path); @@ -85,7 +86,7 @@ Http::priv::priv(const std::string &url) throw std::runtime_error(std::string("Could not construct Curl object")); } - ::curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, DEFAULT_TIMEOUT); + set_timeout(DEFAULT_TIMEOUT); ::curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); // curl makes a copy internally ::curl_easy_setopt(curl, CURLOPT_USERAGENT, SLIC3R_FORK_NAME "/" SLIC3R_VERSION); ::curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, &error_buffer.front()); @@ -169,6 +170,12 @@ size_t Http::priv::form_file_read_cb(char *buffer, size_t size, size_t nitems, v return stream->gcount(); } +void Http::priv::set_timeout(long timeout) +{ + ::curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, timeout); + ::curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout); +} + void Http::priv::form_add_file(const char *name, const fs::path &path, const char* filename) { // We can't use CURLFORM_FILECONTENT, because curl doesn't support Unicode filenames on Windows @@ -205,10 +212,10 @@ void Http::priv::set_post_body(const fs::path &path) std::string Http::priv::curl_error(CURLcode curlcode) { - return (boost::format("%1% (%2%): %3%") + return (boost::format("%1%:\n%2%\n[Error %3%]") % ::curl_easy_strerror(curlcode) + % error_buffer.c_str() % curlcode - % error_buffer ).str(); } @@ -298,7 +305,7 @@ Http::~Http() Http& Http::timeout(long timeout) { if (timeout < 1) { timeout = priv::DEFAULT_TIMEOUT; } - if (p) { ::curl_easy_setopt(p->curl, CURLOPT_CONNECTTIMEOUT, timeout); } + if (p) { p->set_timeout(timeout); } return *this; } diff --git a/src/slic3r/Utils/OctoPrint.cpp b/src/slic3r/Utils/OctoPrint.cpp index cf5fc2f54..af9d6e4f0 100644 --- a/src/slic3r/Utils/OctoPrint.cpp +++ b/src/slic3r/Utils/OctoPrint.cpp @@ -62,7 +62,7 @@ bool OctoPrint::test(wxString &msg) const const auto text = ptree.get_optional("text"); res = validate_version_text(text); if (! res) { - msg = wxString::Format("Mismatched type of print host: %s", text ? *text : "OctoPrint"); + msg = wxString::Format(_(L("Mismatched type of print host: %s")), text ? *text : "OctoPrint"); } } catch (...) { @@ -77,28 +77,24 @@ bool OctoPrint::test(wxString &msg) const wxString OctoPrint::get_test_ok_msg () const { - return wxString::Format("%s", _(L("Connection to OctoPrint works correctly."))); + return _(L("Connection to OctoPrint works correctly.")); } wxString OctoPrint::get_test_failed_msg (wxString &msg) const { return wxString::Format("%s: %s\n\n%s", - _(L("Could not connect to OctoPrint")), msg, _(L("Note: OctoPrint version at least 1.1.0 is required."))); + _(L("Could not connect to OctoPrint")), msg, _(L("Note: OctoPrint version at least 1.1.0 is required."))); } -bool OctoPrint::upload(PrintHostUpload upload_data, Http::ProgressFn prorgess_fn, Http::ErrorFn error_fn) const +bool OctoPrint::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const { const auto upload_filename = upload_data.upload_path.filename(); const auto upload_parent_path = upload_data.upload_path.parent_path(); wxString test_msg; if (! test(test_msg)) { - - // FIXME: - - // auto errormsg = wxString::Format("%s: %s", errortitle, test_msg); - // GUI::show_error(&progress_dialog, std::move(errormsg)); - // return false; + error_fn(std::move(test_msg)); + return false; } bool res = true; @@ -122,7 +118,8 @@ bool OctoPrint::upload(PrintHostUpload upload_data, Http::ProgressFn prorgess_fn }) .on_error([&](std::string body, std::string error, unsigned status) { BOOST_LOG_TRIVIAL(error) << boost::format("Octoprint: Error uploading file: %1%, HTTP %2%, body: `%3%`") % error % status % body; - error_fn(std::move(body), std::move(error), status); + // error_fn(std::move(body), std::move(error), status); + error_fn(format_error(body, error, status)); res = false; }) .on_progress([&](Http::Progress progress, bool &cancel) { @@ -192,7 +189,7 @@ SLAHost::~SLAHost() {} wxString SLAHost::get_test_ok_msg () const { - return wxString::Format("%s", _(L("Connection to Prusa SLA works correctly."))); + return _(L("Connection to Prusa SLA works correctly.")); } wxString SLAHost::get_test_failed_msg (wxString &msg) const diff --git a/src/slic3r/Utils/OctoPrint.hpp b/src/slic3r/Utils/OctoPrint.hpp index 57aae672a..1e739c99d 100644 --- a/src/slic3r/Utils/OctoPrint.hpp +++ b/src/slic3r/Utils/OctoPrint.hpp @@ -23,7 +23,7 @@ public: virtual bool test(wxString &curl_msg) const; virtual wxString get_test_ok_msg () const; virtual wxString get_test_failed_msg (wxString &msg) const; - virtual bool upload(PrintHostUpload upload_data, Http::ProgressFn prorgess_fn, Http::ErrorFn error_fn) const; + virtual bool upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const; virtual bool has_auto_discovery() const; virtual bool can_test() const; virtual std::string get_host() const { return host; } diff --git a/src/slic3r/Utils/PrintHost.cpp b/src/slic3r/Utils/PrintHost.cpp index 5c4507816..934436a19 100644 --- a/src/slic3r/Utils/PrintHost.cpp +++ b/src/slic3r/Utils/PrintHost.cpp @@ -2,10 +2,12 @@ #include #include +#include #include #include #include +#include #include #include "libslic3r/PrintConfig.hpp" @@ -58,7 +60,6 @@ struct PrintHostJobQueue::priv void start_bg_thread(); void bg_thread_main(); void progress_fn(Http::Progress progress, bool &cancel); - void error_fn(std::string body, std::string error, unsigned http_status); void perform_job(PrintHostJob the_job); }; @@ -100,6 +101,9 @@ void PrintHostJobQueue::priv::bg_thread_main() } job_id++; } + } catch (const std::exception &e) { + auto evt = new PrintHostQueueDialog::Event(GUI::EVT_PRINTHOST_ERROR, queue_dialog->GetId(), job_id, e.what()); + wxQueueEvent(queue_dialog, evt); } catch (...) { wxTheApp->OnUnhandledException(); } @@ -136,28 +140,28 @@ void PrintHostJobQueue::priv::progress_fn(Http::Progress progress, bool &cancel) } } -void PrintHostJobQueue::priv::error_fn(std::string body, std::string error, unsigned http_status) -{ - // TODO -} - void PrintHostJobQueue::priv::perform_job(PrintHostJob the_job) { if (bg_exit || the_job.empty()) { return; } - BOOST_LOG_TRIVIAL(debug) << boost::format("PrintHostJobQueue/bg_thread: Got job: `%1%` -> `%1%`") + BOOST_LOG_TRIVIAL(debug) << boost::format("PrintHostJobQueue/bg_thread: Got job: `%1%` -> `%2%`") % the_job.upload_data.upload_path % the_job.printhost->get_host(); const fs::path gcode_path = the_job.upload_data.source_path; - the_job.printhost->upload(std::move(the_job.upload_data), + bool success = the_job.printhost->upload(std::move(the_job.upload_data), [this](Http::Progress progress, bool &cancel) { this->progress_fn(std::move(progress), cancel); }, - [this](std::string body, std::string error, unsigned http_status) { this->error_fn(std::move(body), std::move(error), http_status); } + [this](wxString error) { + auto evt = new PrintHostQueueDialog::Event(GUI::EVT_PRINTHOST_ERROR, queue_dialog->GetId(), job_id, std::move(error)); + wxQueueEvent(queue_dialog, evt); + } ); - auto evt = new PrintHostQueueDialog::Event(GUI::EVT_PRINTHOST_PROGRESS, queue_dialog->GetId(), job_id, 100); - wxQueueEvent(queue_dialog, evt); + if (success) { + auto evt = new PrintHostQueueDialog::Event(GUI::EVT_PRINTHOST_PROGRESS, queue_dialog->GetId(), job_id, 100); + wxQueueEvent(queue_dialog, evt); + } boost::system::error_code ec; fs::remove(gcode_path, ec); diff --git a/src/slic3r/Utils/PrintHost.hpp b/src/slic3r/Utils/PrintHost.hpp index 52ef38058..a6c7a4723 100644 --- a/src/slic3r/Utils/PrintHost.hpp +++ b/src/slic3r/Utils/PrintHost.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -28,10 +29,13 @@ class PrintHost public: virtual ~PrintHost(); + typedef Http::ProgressFn ProgressFn; + typedef std::function ErrorFn; + virtual bool test(wxString &curl_msg) const = 0; virtual wxString get_test_ok_msg () const = 0; virtual wxString get_test_failed_msg (wxString &msg) const = 0; - virtual bool upload(PrintHostUpload upload_data, Http::ProgressFn prorgess_fn, Http::ErrorFn error_fn) const = 0; + virtual bool upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const = 0; virtual bool has_auto_discovery() const = 0; virtual bool can_test() const = 0; virtual std::string get_host() const = 0; From 64f46999d210f2e63a061c70f9d9d9c831e9727f Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 20 Dec 2018 08:38:46 +0100 Subject: [PATCH 05/26] New icons for sla support points gizmo overlay --- .../overlay/sla_support_points_hover.png | Bin 3282 -> 2057 bytes .../icons/overlay/sla_support_points_off.png | Bin 1512 -> 1947 bytes .../icons/overlay/sla_support_points_on.png | Bin 1435 -> 2869 bytes 3 files changed, 0 insertions(+), 0 deletions(-) diff --git a/resources/icons/overlay/sla_support_points_hover.png b/resources/icons/overlay/sla_support_points_hover.png index 6303232b24de8cbdc9f930fa33582591d9a8e454..55955f3d6f1d8e1821a1b5f1212f78efb907b1d0 100644 GIT binary patch literal 2057 zcmaJ?d0Z2B79S3|BTx@6!Ex9w!ZMl6LUB;P6S;4@YDHxW`6VDyzhJ8 zcYUTok-m=R6Y2v108N%E&ZN#{=k4V|J^!RH9;c2FQj$YvnY3gXZXp1n#*|NhG6P;f zWD>ZhqWB__003?_y)uW)k#FFuO$Ivdw4s+9%oG{`5|YZzxVn%a!F-}XZxle&XZj#e zuMt4mY&k=277;pqYNdt9s!Ug^D+|>;4V07!CY19j2L^(~!E!^9(aJ9uK+pa1sduLu zfxzb`WT60>CzT^tfFhHH0NHd7tVUUEFpft@IZPIh7Ykwxl#4L92+D*}4xh!~V;Hz_ zK~yx0M$69>OBZ5Mk^s_?q?wN(Wo2dbGA7+*DL_yjkB2ZY1jAs;0=8BdNxU33S|b-d zhzYCOqBoOzlM!@!#PdxhqyVCr&Zl57%jGW|8?6h4qDqF8<7Nb=t~KW)M7G#&nwN>zk-EYo6pnmm^h3xxG2mbI6N3< zYFRLg$6&CyY8D=cVbB6z^HK%pCzaArnV1&|@$>U>7Kg#+!pt}}6UNyr45kzqjA}3~ zhoeSuHHUx@iX!41o|lGcQAJIt^Yz7QP{NDlB8=2VS*X?dtHr7S0QV4?Sg0%?nQU2~ zs@xcS{;sxR1d@BNX?&wQB)VvS)28m!%&Ju4@Qf;_R<+SLH+bg83>Y)mZr`1^cF9UX zQ^PrlP#KUGlCtqTXh2!{f&BOBKb`1pxO98Gr%e0#iDv7~Z$hRIRz>tpzZFrYZK`v$ zNA3H2Y(`y_OEM4uxYvA<-c8$j@%vKW_Uw;c|9MWw28LT)TkAh;FTS>X%ld{wVAbQ= zn|;G>x4SBzj?{!0{}Nu4He3kGe(e3?`iA2AKLd)4!`K8q5HqH@rvg4pqMi1VACm~a z+GdH{U=7zFcde;Dn zV5DdG)}0vJBV+aZY|;Kf_K|Q8_n1?A4%An77QF7?yL06GPk;3paxKG!RUO_OblPP~ z6IZk;y3%{Zf6P{@&dc)C26bn6_D9;1|D8B+LNfj}cy`qD*-9aKb6NN9v1HD)`;Jc= z!v^sKmr4{t-7DN?;WMpyxx(h(eLHfYsPf6GkZl=HTcIRXOUt{QW1WU|ldi0!DT#X1|nW$bqRY3Ddu1wr4I(Bl7#Q!gCFI=tBo_?{(#Y@q3$7f6P8k z3k`T6WRq__yz4HEJ=(L!fqZ!%9X|UNEy}UvVB2}SF0Ik`mTnm`w#bxZ?2Dc z^sg$dPt6}5#RIB$OKj8K=&JBcyBZt#;QF$;_=DB&FFiEd z_KkXQ)seu$s@%CYVmv3vv9$B@tp~$_m!RM$vT76pya3l400e$vo{h8v+Y}kfUIVIg P{+wl!bn)?&yt@AZI_VI& delta 3278 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 M07*qoM6N<$f_b@Sr2qf` diff --git a/resources/icons/overlay/sla_support_points_off.png b/resources/icons/overlay/sla_support_points_off.png index b654366d578df6a7407d9124264fc818deef9423..7bf84a3e647ea4232ed940b3e9609d4707310a52 100644 GIT binary patch literal 1947 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 diff --git a/resources/icons/overlay/sla_support_points_on.png b/resources/icons/overlay/sla_support_points_on.png index 8c1e69565076723113a310ffad661ba0a4376977..879b9b24128b825efd77c29f9d84aa7b0449f1c1 100644 GIT binary patch literal 2869 zcmaJ@dpuNWA3wrm-LfPaE%T0&(wO_08BL5CqKph(W^2QkIl~xpF*7oxB9wHYyrkVN zmo~XywoNKB)?%dJ7cK@RN)ILt3B9rB z3;9$&=zzz7BoIZ$3veg`h9E$Z9k5swj|U0@aa?DbLm=NxE)^p_Mw%-82NXO(AcarCb5UFj z8H*x-Bnpa)7Z6Yc3I;#|cOz9+t}^fk-q25xrPEe=DYC5>%m!+rL@^I{ejKpakkDIn+8j&ZBYw zSn2A)r0-TeANgA7ox0t;F*OC@;U0@wwVAIJa!?Ahzf!CXXo50knV>fJO|!F+81^i21_YJn^KJs`{(f&V`PKt!-_! zICK4nF)@JIDJC*ONM2`nz{khO%+k`YX<+i2f6n~osSfvevwLc9#lzjbq5d4E$ zlmVOUD2Cm%4an`p<8YP@jg1cX``<+PsRO+8^Yabc+S*+v(+%YXOH3 z-{2IDYOXX~-SOnfxd(^PXWbrEADxRTOG`_mTx|Y=8ulBLD-a0A3be9HOOrMIe(i-W ztt$IVLvJaKeT^Y%h>-{ox5DA@3q^1sYeHa#_S1(M{hT@Z?kmzkgRIFaUgJ4aAhFsG z9`n7QzZWq$Ci!GRl^=&=PQT_;oZ%@53J$ilrqQZ>v%PH(+C*1WR%ZCJ*=-}k!y$ts zBc3$Xcz1ejZEb9BuFZUsw^~_xI`-gg`L(I>p1S0;x9_4u+&w&=tu-?nDE!QGPY7pq z%n+}-xVRXK!1rb4<>!<4yC`I`*4tsdu&yUhp17DQ;@TMqJGC& zfG;C5GV+Ww!W`;&k9~)2_3ivhS{QNRbtJ?K?oxuC0R&(KEaiK=9w=+A|NKFC*`Gwc z?pJ^aBx_No*HBqCMfUO{zUGpvY;T3yWkdH&gHYB_x|W#b%3M4 z17G(L@y=0{(=-*$*;r&zp;6)b?5ORL^$h_SYHRS61vI|DQLELL@7=rCS5Q!JrKhK7 zmtPRK)wbivov@V2sNydc?yVtOmHz&?X^o8YA>Ph%$m-%-K-*iBWL%-p`u<8feIhtK zoJg~=Y1j@M`7uFnw!FOjZOBT%K=~)j%d5o%el~YtaIliNd2`50_un6Pbm)84pudsy z)x20eHXiN%(lP~~Vx3;?Xy??MbE_-Dx^{{^#$5O+oUkfsw(DxUy^dOHU3+e3?|c%f zBbs58ik+XIzeS(>wq8HhwZ<%_v3*~upEw~zrcm6No}9d)Y4E7DsA%LwNafmq!T##l z?)HY%vN;88)XUw}s-^j1`_GmdYqXvVj<7s64p$v6p+?!rdRcQWf|L#ChsEc9od^=w zov!rvUD#W%XPj1L9^0!JalJg^`R?`RJeWxIhe3UPJ?eUB{JF!ZQ@22Hg`w-LZ1+JyJ({25}3I)vYq7Qv~cpXoSt#%m)eh=wGUL0j7FHa zdbQJBPPS>ezGXz~+a1dPJi6qWE9)#dIAgndM@WXiZbL`X;B1KJ^MTAq$MoE1Or&92 zKIdm>Ei4@!1lZnJ(% z814d3clfEbF_+E$+$_o{$~fwW{QONvNyK>9`b#IanOCpcr|V#Xdf)fURm+P$M}um& zc7zkffUEu8f$^Azl&SDNtq zZgsq_vk%ucZ1^KI_s0|8efM3($jFGL5p%X?U!3*>#CdmSUds6R_{v`6+xjjlVBoINu%L13)T#e=cXt;L_t(|ob8)Wh#OTL$3OEjJ82S< z?gk2#LaJCRrPXD%XxvuUi;K2G@us!S25JvpJP4kvpm-ES5VVDCx2$;ZAgI*RgO#>c zkuBJ&P+GQI+)H8E&ALf8$^7xKlkM#6Q(K(|Aes#G=G+^6(Wwx(NI7Ca(e?3e4~)tj zC>-H?x5s-)?0*ce7FBmz+75sO{d$&pH;r{0kz=6U(?YaSSC$1sz3M!Go@HJZ3;}Yh z$Fv#%B`g@OW|(p(%|EIcrow_@R)*rHv=RU%5@KXI!-dYI`NwjG3y}~bv=D@50T7W8 zBgLbf^G2F~6pwPw3_?R68(sv%f)_T@Kkvk*(~OjLet)i4UN-=;U}z(p^R3W#nx|Bq zt4?M00+2AWYJzw0g#QJDk&$nhU1-|P`lj4WlJ^aO&G zBLXbfw%7E4WSBAE75R*jrDWZ<_JB?H!k(Z6%$na3V4L~f0oGoyI%iJwai}x1UEn%! z70@jELVv&zu*bdGgu-i!6~2OdJwO=QHO&Oib>Q~~<$LKU2vUwdKox)x5|6ky)dfo6 zJZ-UX)vV_d(`O+7MH}O$dsAIt7Mk`)&8+7VZHya$ENJ82**98!z~%Zu*eZ&UAl9)N zuZenGuMQH#MM7b;Gc(?!eLV}2CSzTQl_9YMHh(L;EcMd7|MKxmq|<2(!yuHFyE+Qg z=$Z5X_K9iIsT74mf%rR#d(L%X9$=*>0`Tvri=<*P?%cV)f5_kZ# zlPWPu;>wjP41c+AeT4|HqkHWK7J%CMj$t5!9O$p$SVDEcSK zh$ zp9)u^XL!X&J-!ksMBKUcs$P5t$$n5 zbx)JH+C~ULspNb=7oA|VtaGu^@vUTxDD_s1|MvE;3=R$w4zG+XhSB^*bF(^<)Lc@n zPO(^IYHEu8r=DL|Cpy7sN#g=dZuVMDnNh+ao?AZ3Pfmq1@84$o_U)_Njhw8N8HTa0 zUd=H{lGglovT^IyEp~kLm}488CVzObtnmvi-08NHGbGD`CmLNCZ=aYZl}aJR+QG%@ zXw7kZ0Gyn*?gOY+t4vQ%v-9J}>xwilc-Lq#x3DWoQ`g@8gH$R-JRWxpM!gCg5y)aE8>s*|+2gM}k}*Qm~qub*YhmMtWcNfL^r%?EdhZg zPTGvzx2dysT;0000 Date: Thu, 20 Dec 2018 10:55:50 +0100 Subject: [PATCH 06/26] Improvements of assigning the layer span to the layer slider on slice update. --- src/slic3r/GUI/GUI_Preview.cpp | 105 ++++++++++++++++++-------------- src/slic3r/GUI/GUI_Preview.hpp | 6 +- src/slic3r/GUI/wxExtensions.cpp | 15 +++++ src/slic3r/GUI/wxExtensions.hpp | 21 ++++--- 4 files changed, 88 insertions(+), 59 deletions(-) diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index 735b55125..579cd7e5e 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -214,7 +214,6 @@ Preview::Preview(wxNotebook* notebook, DynamicPrintConfig* config, BackgroundSli , m_preferred_color_mode("feature") , m_loaded(false) , m_enabled(false) - , m_force_sliders_full_range(false) , m_schedule_background_process(schedule_background_process_func) { #if ENABLE_REMOVE_TABS_FROM_PLATER @@ -514,14 +513,14 @@ void Preview::show_hide_ui_elements(const std::string& what) void Preview::reset_sliders() { m_enabled = false; - reset_double_slider(); +// reset_double_slider(); m_double_slider_sizer->Hide((size_t)0); } void Preview::update_sliders(const std::vector& layers_z) { m_enabled = true; - update_double_slider(layers_z, m_force_sliders_full_range); + update_double_slider(layers_z); m_double_slider_sizer->Show((size_t)0); Layout(); } @@ -597,26 +596,70 @@ void Preview::create_double_slider() }); } +// Find an index of a value in a sorted vector, which is in . +// Returns -1 if there is no such member. +static int find_close_layer_idx(const std::vector& zs, double &z, double eps) +{ + if (zs.empty()) + return -1; + auto it_h = std::lower_bound(zs.begin(), zs.end(), z); + if (it_h == zs.end()) { + auto it_l = it_h; + -- it_l; + if (z - *it_l < eps) + return int(zs.size() - 1); + } else if (it_h == zs.begin()) { + if (*it_h - z < eps) + return 0; + } else { + auto it_l = it_h; + -- it_l; + double dist_l = z - *it_l; + double dist_h = *it_h - z; + if (std::min(dist_l, dist_h) < eps) { + return (dist_l < dist_h) ? int(it_l - zs.begin()) : int(it_h - zs.begin()); + } + } + return -1; +} + void Preview::update_double_slider(const std::vector& layers_z, bool force_sliders_full_range) { + // Save the initial slider span. + double z_low = m_slider->GetLowerValueD(); + double z_high = m_slider->GetHigherValueD(); + bool was_empty = m_slider->GetMaxValue() == 0; + bool span_changed = layers_z.empty() || std::abs(layers_z.back() - m_slider->GetMaxValueD()) > 1e-6; + force_sliders_full_range |= was_empty | span_changed; + bool snap_to_min = force_sliders_full_range || m_slider->is_lower_at_min(); + bool snap_to_max = force_sliders_full_range || m_slider->is_higher_at_max(); + std::vector> values; fill_slider_values(values, layers_z); - - m_slider->SetMaxValue(layers_z.size() - 1); - if (force_sliders_full_range) - m_slider->SetHigherValue(layers_z.size() - 1); - m_slider->SetSliderValues(values); - const double z_low = m_slider->GetLowerValueD(); - const double z_high = m_slider->GetHigherValueD(); + assert(m_slider->GetMinValue() == 0); + m_slider->SetMaxValue(layers_z.empty() ? 0 : layers_z.size() - 1); + + int idx_low = 0; + int idx_high = m_slider->GetMaxValue(); + if (! layers_z.empty()) { + if (! snap_to_min) { + int idx_new = find_close_layer_idx(layers_z, z_low, 1e-6); + if (idx_new != -1) + idx_low = idx_new; + } + if (! snap_to_max) { + int idx_new = find_close_layer_idx(layers_z, z_high, 1e-6); + if (idx_new != -1) + idx_high = idx_new; + } + } + m_slider->SetSelectionSpan(idx_low, idx_high); const auto& config = wxGetApp().preset_bundle->project_config; const std::vector &ticks_from_config = (config.option("colorprint_heights"))->values; - m_slider->SetTicksValues(ticks_from_config); - set_double_slider_thumbs(layers_z, z_low, z_high); - bool color_print_enable = (wxGetApp().plater()->printer_technology() == ptFFF); if (color_print_enable) { const auto& config = wxGetApp().preset_bundle->full_config(); @@ -638,8 +681,7 @@ void Preview::fill_slider_values(std::vector> &values, // All ticks that would end up outside the slider range should be erased. // TODO: this should be placed into more appropriate part of code, // this function is e.g. not called when the last object is deleted - auto& config = wxGetApp().preset_bundle->project_config; - std::vector &ticks_from_config = (config.option("colorprint_heights"))->values; + std::vector &ticks_from_config = (wxGetApp().preset_bundle->project_config.option("colorprint_heights"))->values; unsigned int old_size = ticks_from_config.size(); ticks_from_config.erase(std::remove_if(ticks_from_config.begin(), ticks_from_config.end(), [values](double val) { return values.back().second < val; }), @@ -648,32 +690,6 @@ void Preview::fill_slider_values(std::vector> &values, m_schedule_background_process(); } -void Preview::set_double_slider_thumbs(const std::vector &layers_z, - const double z_low, - const double z_high) -{ - // Force slider full range only when slider is created. - // Support selected diapason on the all next steps - if (z_high == 0.0) { - m_slider->SetLowerValue(0); - m_slider->SetHigherValue(layers_z.size() - 1); - return; - } - - for (int i = layers_z.size() - 1; i >= 0; i--) -// if (z_low >= layers_z[i]) { - if (fabs(z_low - layers_z[i]) <= 1e-6) { - m_slider->SetLowerValue(i); - break; - } - for (int i = layers_z.size() - 1; i >= 0; i--) -// if (z_high >= layers_z[i]) { - if (fabs(z_high-layers_z[i]) <= 1e-6) { - m_slider->SetHigherValue(i); - break; - } -} - void Preview::reset_double_slider() { m_slider->SetHigherValue(0); @@ -692,7 +708,7 @@ void Preview::update_double_slider_from_canvas(wxKeyEvent& event) if (key == 'U' || key == 'D') { const int new_pos = key == 'U' ? m_slider->GetHigherValue() + 1 : m_slider->GetHigherValue() - 1; m_slider->SetHigherValue(new_pos); - if (event.ShiftDown()) m_slider->SetLowerValue(m_slider->GetHigherValue()); + if (event.ShiftDown() || m_slider->is_one_layer()) m_slider->SetLowerValue(m_slider->GetHigherValue()); } else if (key == 'S') m_slider->ChangeOneLayerLock(); @@ -778,12 +794,8 @@ void Preview::load_print_as_fff() if (IsShown()) { - // used to set the sliders to the extremes of the current zs range - m_force_sliders_full_range = false; - if (gcode_preview_data_valid) { - m_force_sliders_full_range = (m_canvas->get_volumes_count() == 0); m_canvas->load_gcode_preview(*m_gcode_preview_data, colors); show_hide_ui_elements("full"); @@ -849,7 +861,6 @@ void Preview::load_print_as_sla() { std::vector layer_zs; std::copy(zs.begin(), zs.end(), std::back_inserter(layer_zs)); - m_force_sliders_full_range = true; update_sliders(layer_zs); } diff --git a/src/slic3r/GUI/GUI_Preview.hpp b/src/slic3r/GUI/GUI_Preview.hpp index 534191633..bd71adcb5 100644 --- a/src/slic3r/GUI/GUI_Preview.hpp +++ b/src/slic3r/GUI/GUI_Preview.hpp @@ -117,7 +117,6 @@ class Preview : public wxPanel bool m_loaded; bool m_enabled; - bool m_force_sliders_full_range; PrusaDoubleSlider* m_slider {nullptr}; @@ -177,12 +176,9 @@ private: // Create/Update/Reset double slider on 3dPreview void create_double_slider(); - void update_double_slider(const std::vector& layers_z, bool force_sliders_full_range); + void update_double_slider(const std::vector& layers_z, bool force_sliders_full_range = false); void fill_slider_values(std::vector> &values, const std::vector &layers_z); - void set_double_slider_thumbs( const std::vector &layers_z, - const double z_low, - const double z_high); void reset_double_slider(); // update DoubleSlider after keyDown in canvas void update_double_slider_from_canvas(wxKeyEvent& event); diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index 2daba5df4..787c2a2a2 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -1506,6 +1506,21 @@ void PrusaDoubleSlider::SetHigherValue(const int higher_val) ProcessWindowEvent(e); } +void PrusaDoubleSlider::SetSelectionSpan(const int lower_val, const int higher_val) +{ + m_lower_value = std::max(lower_val, m_min_value); + m_higher_value = std::max(std::min(higher_val, m_max_value), m_lower_value); + if (m_lower_value < m_higher_value) + m_is_one_layer = false; + + Refresh(); + Update(); + + wxCommandEvent e(wxEVT_SCROLL_CHANGED); + e.SetEventObject(this); + ProcessWindowEvent(e); +} + void PrusaDoubleSlider::SetMaxValue(const int max_value) { m_max_value = max_value; diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp index e8fba1ea2..b951c5635 100644 --- a/src/slic3r/GUI/wxExtensions.hpp +++ b/src/slic3r/GUI/wxExtensions.hpp @@ -697,18 +697,20 @@ public: const wxString& name = wxEmptyString); ~PrusaDoubleSlider() {} - int GetLowerValue() const { - return m_lower_value; - } - int GetHigherValue() const { - return m_higher_value; - } + int GetMinValue() const { return m_min_value; } + int GetMaxValue() const { return m_max_value; } + double GetMinValueD() { return m_values.empty() ? 0. : m_values[m_min_value].second; } + double GetMaxValueD() { return m_values.empty() ? 0. : m_values[m_max_value].second; } + int GetLowerValue() const { return m_lower_value; } + int GetHigherValue() const { return m_higher_value; } int GetActiveValue() const; double GetLowerValueD() { return get_double_value(ssLower); } double GetHigherValueD() { return get_double_value(ssHigher); } wxSize DoGetBestSize() const override; void SetLowerValue(const int lower_val); void SetHigherValue(const int higher_val); + // Set low and high slider position. If the span is non-empty, disable the "one layer" mode. + void SetSelectionSpan(const int lower_val, const int higher_val); void SetMaxValue(const int max_value); void SetKoefForLabels(const double koef) { m_label_koef = koef; @@ -726,6 +728,12 @@ public: EnableTickManipulation(false); } + bool is_horizontal() const { return m_style == wxSL_HORIZONTAL; } + bool is_one_layer() const { return m_is_one_layer; } + bool is_lower_at_min() const { return m_lower_value == m_min_value; } + bool is_higher_at_max() const { return m_higher_value == m_max_value; } + bool is_full_span() const { return this->is_lower_at_min() && this->is_higher_at_max(); } + void OnPaint(wxPaintEvent& ) { render();} void OnLeftDown(wxMouseEvent& event); void OnMotion(wxMouseEvent& event); @@ -762,7 +770,6 @@ protected: bool is_point_in_rect(const wxPoint& pt, const wxRect& rect); int is_point_near_tick(const wxPoint& pt); - bool is_horizontal() const { return m_style == wxSL_HORIZONTAL; } double get_scroll_step(); wxString get_label(const SelectedSlider& selection) const; From 54fae970329609c1231e475095aa80d3d28e54ef Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 20 Dec 2018 11:14:53 +0100 Subject: [PATCH 07/26] Visual hints in the 3D scene when sidebar matrix fields have focus -> Completed VBOs case --- src/libslic3r/Technologies.hpp | 2 +- src/slic3r/GUI/3DScene.cpp | 160 +++++++++++++++++++++++++++++++-- src/slic3r/GUI/3DScene.hpp | 18 +++- src/slic3r/GUI/GLCanvas3D.cpp | 76 +++++++++------- src/slic3r/GUI/GLCanvas3D.hpp | 9 +- 5 files changed, 214 insertions(+), 51 deletions(-) diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index 797272223..5d49c3675 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -43,7 +43,7 @@ // Renders a small sphere in the center of the bounding box of the current selection when no gizmo is active #define ENABLE_RENDER_SELECTION_CENTER (0 && ENABLE_1_42_0) // Show visual hints in the 3D scene when sidebar matrix fields have focus -#define ENABLE_SIDEBAR_VISUAL_HINTS (0 && ENABLE_1_42_0) +#define ENABLE_SIDEBAR_VISUAL_HINTS (1 && ENABLE_1_42_0) #endif // _technologies_h_ diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 012203450..b431cf8bc 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -1872,6 +1872,7 @@ GUI::GLCanvas3DManager _3DScene::s_canvas_mgr; GLModel::GLModel() : m_useVBOs(false) { + m_volume.shader_outside_printer_detection_enabled = false; } GLModel::~GLModel() @@ -1879,11 +1880,36 @@ GLModel::~GLModel() m_volume.release_geometry(); } -void GLModel::set_color(float* color, unsigned int size) +void GLModel::set_color(const float* color, unsigned int size) { m_volume.set_render_color(color, size); } +const Vec3d& GLModel::get_offset() const +{ + return m_volume.get_volume_offset(); +} + +void GLModel::set_offset(const Vec3d& offset) +{ + m_volume.set_volume_offset(offset); +} + +const Vec3d& GLModel::get_rotation() const +{ + return m_volume.get_volume_rotation(); +} + +void GLModel::set_rotation(const Vec3d& rotation) +{ + m_volume.set_volume_rotation(rotation); +} + +const Vec3d& GLModel::get_scale() const +{ + return m_volume.get_volume_scaling_factor(); +} + void GLModel::set_scale(const Vec3d& scale) { m_volume.set_volume_scaling_factor(scale); @@ -1910,8 +1936,9 @@ void GLModel::render_VBOs() const GLint current_program_id; ::glGetIntegerv(GL_CURRENT_PROGRAM, ¤t_program_id); GLint color_id = (current_program_id > 0) ? glGetUniformLocation(current_program_id, "uniform_color") : -1; + GLint print_box_detection_id = (current_program_id > 0) ? glGetUniformLocation(current_program_id, "print_box.volume_detection") : -1; - m_volume.render_VBOs(color_id, -1, -1); + m_volume.render_VBOs(color_id, print_box_detection_id, -1); ::glBindBuffer(GL_ARRAY_BUFFER, 0); ::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); @@ -1922,17 +1949,12 @@ void GLModel::render_VBOs() const ::glDisable(GL_BLEND); } -GLArrow::GLArrow() - : GLModel() -{ -} - bool GLArrow::on_init(bool useVBOs) { Pointf3s vertices; std::vector triangles; - // top face + // bottom face vertices.emplace_back(0.5, 0.0, -0.1); vertices.emplace_back(0.5, 2.0, -0.1); vertices.emplace_back(1.0, 2.0, -0.1); @@ -1941,7 +1963,7 @@ bool GLArrow::on_init(bool useVBOs) vertices.emplace_back(-0.5, 2.0, -0.1); vertices.emplace_back(-0.5, 0.0, -0.1); - // bottom face + // top face vertices.emplace_back(0.5, 0.0, 0.1); vertices.emplace_back(0.5, 2.0, 0.1); vertices.emplace_back(1.0, 2.0, 0.1); @@ -1990,6 +2012,126 @@ bool GLArrow::on_init(bool useVBOs) m_volume.finalize_geometry(m_useVBOs); return true; } + +GLCurvedArrow::GLCurvedArrow(unsigned int resolution) + : GLModel() + , m_resolution(resolution) +{ + if (m_resolution == 0) + m_resolution = 1; +} + +bool GLCurvedArrow::on_init(bool useVBOs) +{ + Pointf3s vertices; + std::vector triangles; + + double ext_radius = 2.5; + double int_radius = 1.5; + double step = 0.5 * (double)PI / (double)m_resolution; + + unsigned int vertices_per_level = 4 + 2 * m_resolution; + + // bottom face + vertices.emplace_back(0.0, 1.5, -0.1); + vertices.emplace_back(0.0, 1.0, -0.1); + vertices.emplace_back(-1.0, 2.0, -0.1); + vertices.emplace_back(0.0, 3.0, -0.1); + vertices.emplace_back(0.0, 2.5, -0.1); + + for (unsigned int i = 1; i <= m_resolution; ++i) + { + double angle = (double)i * step; + double x = ext_radius * ::sin(angle); + double y = ext_radius * ::cos(angle); + + vertices.emplace_back(x, y, -0.1); + } + + for (unsigned int i = 0; i < m_resolution; ++i) + { + double angle = (double)i * step; + double x = int_radius * ::cos(angle); + double y = int_radius * ::sin(angle); + + vertices.emplace_back(x, y, -0.1); + } + + // top face + vertices.emplace_back(0.0, 1.5, 0.1); + vertices.emplace_back(0.0, 1.0, 0.1); + vertices.emplace_back(-1.0, 2.0, 0.1); + vertices.emplace_back(0.0, 3.0, 0.1); + vertices.emplace_back(0.0, 2.5, 0.1); + + for (unsigned int i = 1; i <= m_resolution; ++i) + { + double angle = (double)i * step; + double x = ext_radius * ::sin(angle); + double y = ext_radius * ::cos(angle); + + vertices.emplace_back(x, y, 0.1); + } + + for (unsigned int i = 0; i < m_resolution; ++i) + { + double angle = (double)i * step; + double x = int_radius * ::cos(angle); + double y = int_radius * ::sin(angle); + + vertices.emplace_back(x, y, 0.1); + } + + // bottom face + triangles.emplace_back(0, 1, 2); + triangles.emplace_back(0, 2, 4); + triangles.emplace_back(4, 2, 3); + + int first_id = 4; + int last_id = (int)vertices_per_level; + triangles.emplace_back(last_id, 0, first_id); + triangles.emplace_back(last_id, first_id, first_id + 1); + for (unsigned int i = 1; i < m_resolution; ++i) + { + triangles.emplace_back(last_id - i, last_id - i + 1, first_id + i); + triangles.emplace_back(last_id - i, first_id + i, first_id + i + 1); + } + + // top face + last_id += 1; + triangles.emplace_back(last_id + 0, last_id + 2, last_id + 1); + triangles.emplace_back(last_id + 0, last_id + 4, last_id + 2); + triangles.emplace_back(last_id + 4, last_id + 3, last_id + 2); + + first_id = last_id + 4; + last_id = last_id + 4 + 2 * (int)m_resolution; + triangles.emplace_back(last_id, first_id, (int)vertices_per_level + 1); + triangles.emplace_back(last_id, first_id + 1, first_id); + for (unsigned int i = 1; i < m_resolution; ++i) + { + triangles.emplace_back(last_id - i, first_id + i, last_id - i + 1); + triangles.emplace_back(last_id - i, first_id + i + 1, first_id + i); + } + + // side face + for (unsigned int i = 0; i < 4 + 2 * (int)m_resolution; ++i) + { + triangles.emplace_back(i, vertices_per_level + 2 + i, i + 1); + triangles.emplace_back(i, vertices_per_level + 1 + i, vertices_per_level + 2 + i); + } + triangles.emplace_back(vertices_per_level, vertices_per_level + 1, 0); + triangles.emplace_back(vertices_per_level, 2 * vertices_per_level + 1, vertices_per_level + 1); + + m_useVBOs = useVBOs; + + if (m_useVBOs) + m_volume.indexed_vertex_array.load_mesh_full_shading(TriangleMesh(vertices, triangles)); + else + m_volume.indexed_vertex_array.load_mesh_flat_shading(TriangleMesh(vertices, triangles)); + + m_volume.finalize_geometry(m_useVBOs); + return true; +} #endif // ENABLE_SIDEBAR_VISUAL_HINTS std::string _3DScene::get_gl_info(bool format_as_html, bool extensions) diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index 22b80d627..09bb54e2f 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -595,7 +595,13 @@ public: bool init(bool useVBOs) { return on_init(useVBOs); } - void set_color(float* color, unsigned int size); + void set_color(const float* color, unsigned int size); + + const Vec3d& get_offset() const; + void set_offset(const Vec3d& offset); + const Vec3d& get_rotation() const; + void set_rotation(const Vec3d& rotation); + const Vec3d& get_scale() const; void set_scale(const Vec3d& scale); void render() const; @@ -609,8 +615,16 @@ private: class GLArrow : public GLModel { +protected: + virtual bool on_init(bool useVBOs); +}; + +class GLCurvedArrow : public GLModel +{ + unsigned int m_resolution; + public: - GLArrow(); + explicit GLCurvedArrow(unsigned int resolution); protected: virtual bool on_init(bool useVBOs); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 3c4debba0..77d0f0776 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -73,6 +73,11 @@ static const float DEFAULT_BG_LIGHT_COLOR[3] = { 0.753f, 0.753f, 0.753f }; static const float ERROR_BG_DARK_COLOR[3] = { 0.478f, 0.192f, 0.039f }; static const float ERROR_BG_LIGHT_COLOR[3] = { 0.753f, 0.192f, 0.039f }; +#if ENABLE_SIDEBAR_VISUAL_HINTS +static const float UNIFORM_SCALE_COLOR[3] = { 1.0f, 0.38f, 0.0f }; +static const float AXES_COLOR[3][3] = { { 1.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, { 0.0f, 0.0f, 1.0f } }; +#endif // ENABLE_SIDEBAR_VISUAL_HINTS + namespace Slic3r { namespace GUI { @@ -1154,12 +1159,6 @@ GLCanvas3D::Selection::VolumeCache::VolumeCache(const Vec3d& position, const Vec } #endif // ENABLE_MODELVOLUME_TRANSFORM -#if ENABLE_SIDEBAR_VISUAL_HINTS -const float GLCanvas3D::Selection::RED[3] = { 1.0f, 0.0f, 0.0f }; -const float GLCanvas3D::Selection::GREEN[3] = { 0.0f, 1.0f, 0.0f }; -const float GLCanvas3D::Selection::BLUE[3] = { 0.0f, 0.0f, 1.0f }; -#endif // ENABLE_SIDEBAR_VISUAL_HINTS - GLCanvas3D::Selection::Selection() : m_volumes(nullptr) , m_model(nullptr) @@ -1167,6 +1166,7 @@ GLCanvas3D::Selection::Selection() , m_type(Empty) , m_valid(false) , m_bounding_box_dirty(true) + , m_curved_arrow(16) { #if ENABLE_RENDER_SELECTION_CENTER m_quadric = ::gluNewQuadric(); @@ -1192,13 +1192,16 @@ void GLCanvas3D::Selection::set_volumes(GLVolumePtrs* volumes) #if ENABLE_SIDEBAR_VISUAL_HINTS bool GLCanvas3D::Selection::init(bool useVBOs) { - if (m_arrow.init(useVBOs)) - { - m_arrow.set_scale(5.0 * Vec3d::Ones()); - return true; - } + if (!m_arrow.init(useVBOs)) + return false; - return false; + m_arrow.set_scale(5.0 * Vec3d::Ones()); + + if (!m_curved_arrow.init(useVBOs)) + return false; + + m_curved_arrow.set_scale(5.0 * Vec3d::Ones()); + return true; } #endif // ENABLE_SIDEBAR_VISUAL_HINTS @@ -2094,14 +2097,22 @@ void GLCanvas3D::Selection::render_sidebar_hints(const std::string& sidebar_fiel else if (is_single_volume() || is_single_modifier()) { const GLVolume* volume = (*m_volumes)[*m_list.begin()]; - Transform3d orient_matrix = volume->get_instance_transformation().get_matrix(true, false, true, true) * volume->get_volume_transformation().get_matrix(true, false, true, true); + Transform3d orient_matrix = volume->get_instance_transformation().get_matrix(true, false, true, true); const Vec3d& offset = get_bounding_box().center(); ::glTranslated(offset(0), offset(1), offset(2)); ::glMultMatrixd(orient_matrix.data()); } else + { ::glTranslated(center(0), center(1), center(2)); + if (requires_local_axes()) + { + const GLVolume* volume = (*m_volumes)[*m_list.begin()]; + Transform3d orient_matrix = volume->get_instance_transformation().get_matrix(true, false, true, true); + ::glMultMatrixd(orient_matrix.data()); + } + } if (boost::starts_with(sidebar_field, "position")) _render_sidebar_position_hints(sidebar_field); @@ -2544,6 +2555,18 @@ void GLCanvas3D::Selection::_render_sidebar_position_hints(const std::string& si void GLCanvas3D::Selection::_render_sidebar_rotation_hints(const std::string& sidebar_field) const { + if (boost::ends_with(sidebar_field, "x")) + { + ::glRotated(90.0, 0.0, 1.0, 0.0); + _render_sidebar_rotation_hint(X); + } + else if (boost::ends_with(sidebar_field, "y")) + { + ::glRotated(-90.0, 1.0, 0.0, 0.0); + _render_sidebar_rotation_hint(Y); + } + else if (boost::ends_with(sidebar_field, "z")) + _render_sidebar_rotation_hint(Z); } void GLCanvas3D::Selection::_render_sidebar_scale_hints(const std::string& sidebar_field) const @@ -2579,33 +2602,22 @@ void GLCanvas3D::Selection::_render_sidebar_size_hints(const std::string& sideba void GLCanvas3D::Selection::_render_sidebar_position_hint(Axis axis) const { - float color[3]; - switch (axis) - { - case X: { ::memcpy((void*)color, (const void*)RED, 3 * sizeof(float)); break; } - case Y: { ::memcpy((void*)color, (const void*)GREEN, 3 * sizeof(float)); break; } - case Z: { ::memcpy((void*)color, (const void*)BLUE, 3 * sizeof(float)); break; } - } - - m_arrow.set_color(color, 3); + m_arrow.set_color(AXES_COLOR[axis], 3); m_arrow.render(); } -void GLCanvas3D::Selection::_render_sidebar_rotation_hint(Axis axis, double length) const +void GLCanvas3D::Selection::_render_sidebar_rotation_hint(Axis axis) const { + m_curved_arrow.set_color(AXES_COLOR[axis], 3); + m_curved_arrow.render(); + + ::glRotated(180.0, 0.0, 0.0, 1.0); + m_curved_arrow.render(); } void GLCanvas3D::Selection::_render_sidebar_scale_hint(Axis axis) const { - float color[3]; - switch (axis) - { - case X: { ::memcpy((void*)color, (const void*)RED, 3 * sizeof(float)); break; } - case Y: { ::memcpy((void*)color, (const void*)GREEN, 3 * sizeof(float)); break; } - case Z: { ::memcpy((void*)color, (const void*)BLUE, 3 * sizeof(float)); break; } - } - - m_arrow.set_color(color, 3); + m_arrow.set_color((requires_uniform_scale() ? UNIFORM_SCALE_COLOR : AXES_COLOR[axis]), 3); ::glTranslated(0.0, 5.0, 0.0); m_arrow.render(); diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 413d625f1..8e9d44a4b 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -369,12 +369,6 @@ class GLCanvas3D public: class Selection { -#if ENABLE_SIDEBAR_VISUAL_HINTS - static const float RED[3]; - static const float GREEN[3]; - static const float BLUE[3]; -#endif // ENABLE_SIDEBAR_VISUAL_HINTS - public: typedef std::set IndicesList; @@ -504,6 +498,7 @@ public: #endif // ENABLE_RENDER_SELECTION_CENTER #if ENABLE_SIDEBAR_VISUAL_HINTS mutable GLArrow m_arrow; + mutable GLCurvedArrow m_curved_arrow; #endif // ENABLE_SIDEBAR_VISUAL_HINTS public: @@ -619,7 +614,7 @@ public: void _render_sidebar_scale_hints(const std::string& sidebar_field) const; void _render_sidebar_size_hints(const std::string& sidebar_field) const; void _render_sidebar_position_hint(Axis axis) const; - void _render_sidebar_rotation_hint(Axis axis, double length) const; + void _render_sidebar_rotation_hint(Axis axis) const; void _render_sidebar_scale_hint(Axis axis) const; void _render_sidebar_size_hint(Axis axis, double length) const; #endif // ENABLE_SIDEBAR_VISUAL_HINTS From 11da45e32fb623a8a2717964f091f998c13b692e Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 20 Dec 2018 11:42:26 +0100 Subject: [PATCH 08/26] Visual hints in the 3D scene when sidebar matrix fields have focus -> legacy render case --- src/slic3r/GUI/3DScene.cpp | 22 ++++++++++++++++++++-- src/slic3r/GUI/3DScene.hpp | 1 + 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index b431cf8bc..961d4822a 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -1920,8 +1920,7 @@ void GLModel::render() const if (m_useVBOs) render_VBOs(); else - { - } + render_legacy(); } void GLModel::render_VBOs() const @@ -1949,6 +1948,25 @@ void GLModel::render_VBOs() const ::glDisable(GL_BLEND); } +void GLModel::render_legacy() const +{ + ::glEnable(GL_LIGHTING); + ::glEnable(GL_BLEND); + ::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + ::glCullFace(GL_BACK); + ::glEnableClientState(GL_VERTEX_ARRAY); + ::glEnableClientState(GL_NORMAL_ARRAY); + + m_volume.render_legacy(); + + ::glDisableClientState(GL_VERTEX_ARRAY); + ::glDisableClientState(GL_NORMAL_ARRAY); + + ::glDisable(GL_BLEND); + ::glDisable(GL_LIGHTING); +} + bool GLArrow::on_init(bool useVBOs) { Pointf3s vertices; diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index 09bb54e2f..76cacabbd 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -611,6 +611,7 @@ protected: private: void render_VBOs() const; + void render_legacy() const; }; class GLArrow : public GLModel From a5b846f7fc3569854fd977b55dc4aeca5929f116 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Thu, 20 Dec 2018 12:08:06 +0100 Subject: [PATCH 09/26] Improved edge normal detection. Also removed some warnings. --- .../include/libnest2d/placers/nfpplacer.hpp | 4 +- src/libslic3r/ModelArrange.cpp | 14 ++----- src/libslic3r/SLA/SLASupportTreeIGL.cpp | 39 +++++++++++++------ 3 files changed, 34 insertions(+), 23 deletions(-) diff --git a/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp b/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp index 14ed3d22c..28659c512 100644 --- a/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp +++ b/src/libnest2d/include/libnest2d/placers/nfpplacer.hpp @@ -545,8 +545,8 @@ public: _NofitPolyPlacer& operator=(const _NofitPolyPlacer&) = default; #ifndef BP2D_COMPILER_MSVC12 // MSVC2013 does not support default move ctors - _NofitPolyPlacer(_NofitPolyPlacer&&) BP2D_NOEXCEPT = default; - _NofitPolyPlacer& operator=(_NofitPolyPlacer&&) BP2D_NOEXCEPT = default; + _NofitPolyPlacer(_NofitPolyPlacer&&) /*BP2D_NOEXCEPT*/ = default; + _NofitPolyPlacer& operator=(_NofitPolyPlacer&&) /*BP2D_NOEXCEPT*/ = default; #endif static inline double overfit(const Box& bb, const RawShape& bin) { diff --git a/src/libslic3r/ModelArrange.cpp b/src/libslic3r/ModelArrange.cpp index d182f1501..562527290 100644 --- a/src/libslic3r/ModelArrange.cpp +++ b/src/libslic3r/ModelArrange.cpp @@ -135,11 +135,6 @@ objfunc(const PointImpl& bincenter, const ItemGroup& remaining ) { - using Coord = TCoord; - - static const double ROUNDNESS_RATIO = 0.5; - static const double DENSITY_RATIO = 1.0 - ROUNDNESS_RATIO; - // We will treat big items (compared to the print bed) differently auto isBig = [bin_area](double a) { return a/bin_area > BIG_ITEM_TRESHOLD ; @@ -629,11 +624,12 @@ BedShapeHint bedShape(const Polyline &bed) { avg_dist /= vertex_distances.size(); Circle ret(center, avg_dist); - for (auto el: vertex_distances) + for(auto el : vertex_distances) { - if (abs(el - avg_dist) > 10 * SCALED_EPSILON) + if (std::abs(el - avg_dist) > 10 * SCALED_EPSILON) { ret = Circle(); - break; + break; + } } return ret; @@ -665,8 +661,6 @@ bool arrange(Model &model, std::function progressind, std::function stopcondition) { - using ArrangeResult = _IndexedPackGroup; - bool ret = true; // Get the 2D projected shapes with their 3D model instance pointers diff --git a/src/libslic3r/SLA/SLASupportTreeIGL.cpp b/src/libslic3r/SLA/SLASupportTreeIGL.cpp index 5d40bb514..49290b3b8 100644 --- a/src/libslic3r/SLA/SLASupportTreeIGL.cpp +++ b/src/libslic3r/SLA/SLASupportTreeIGL.cpp @@ -107,7 +107,8 @@ PointSet normals(const PointSet& points, const EigenMesh3D& emesh, // structure EigenMesh3D mesh; Eigen::VectorXi SVI, SVJ; - igl::remove_duplicate_vertices(emesh.V, emesh.F, 1e-6, + static const double dEPS = 1e-6; + igl::remove_duplicate_vertices(emesh.V, emesh.F, dEPS, mesh.V, SVI, SVJ, mesh.F); igl::point_mesh_squared_distance( points, mesh.V, mesh.F, dists, I, C); @@ -155,6 +156,7 @@ PointSet normals(const PointSet& points, const EigenMesh3D& emesh, ia = trindex(0); ib = trindex(2); } + // vector for the neigboring triangles including the detected one. std::vector neigh; if(ic >= 0) { // The point is right on a vertex of the triangle for(int n = 0; n < mesh.F.rows(); ++n) { @@ -175,17 +177,32 @@ PointSet normals(const PointSet& points, const EigenMesh3D& emesh, } } - if(!neigh.empty()) { // there were neighbors to count with + // Calculate the normals for the neighboring triangles + std::vector neighnorms; neighnorms.reserve(neigh.size()); + for(const Vec3i& tri : neigh) { + const Vec3d& pt1 = mesh.V.row(tri(0)); + const Vec3d& pt2 = mesh.V.row(tri(1)); + const Vec3d& pt3 = mesh.V.row(tri(2)); + Eigen::Vector3d U = pt2 - pt1; + Eigen::Vector3d V = pt3 - pt1; + neighnorms.emplace_back(U.cross(V).normalized()); + } + + // Throw out duplicates. They would case trouble with summing. + auto lend = std::unique(neighnorms.begin(), neighnorms.end(), + [](const Vec3d& n1, const Vec3d& n2) { + // Compare normals for equivalence. This is controvers stuff. + // We will go for the third significant digit precision. + auto deq = [](double a, double b) { return std::abs(a-b) < 1e-3; }; + return deq(n1(X), n2(X)) && deq(n1(Y), n2(Y)) && deq(n1(Z), n2(Z)); + }); + + if(!neighnorms.empty()) { // there were neighbors to count with + // sum up the normals and than normalize the result again. + // This unification seems to be enough. Vec3d sumnorm(0, 0, 0); - for(const Vec3i& tri : neigh) { - const Vec3d& pt1 = mesh.V.row(tri(0)); - const Vec3d& pt2 = mesh.V.row(tri(1)); - const Vec3d& pt3 = mesh.V.row(tri(2)); - Eigen::Vector3d U = pt2 - pt1; - Eigen::Vector3d V = pt3 - pt1; - sumnorm += U.cross(V).normalized(); - } - sumnorm /= neigh.size(); + sumnorm = std::accumulate(neighnorms.begin(), lend, sumnorm); + sumnorm.normalize(); ret.row(i) = sumnorm; } else { // point lies safely within its triangle From 780e3c700e9f5e1d9beb7b16b0a62067bf4e7d31 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 20 Dec 2018 12:51:42 +0100 Subject: [PATCH 10/26] Attempt to reduce ugly artifacts when switching to preview for the 1st time --- src/slic3r/GUI/Plater.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index cba53cf17..6a8bcc79b 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1162,9 +1162,9 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) hsizer->Add(sidebar, 0, wxEXPAND | wxLEFT | wxRIGHT, 0); q->SetSizer(hsizer); -#if ENABLE_REMOVE_TABS_FROM_PLATER - set_current_panel(view3D); -#endif // ENABLE_REMOVE_TABS_FROM_PLATER +//#if ENABLE_REMOVE_TABS_FROM_PLATER +// set_current_panel(view3D); +//#endif // ENABLE_REMOVE_TABS_FROM_PLATER init_object_menu(); @@ -1251,6 +1251,10 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) update_ui_from_settings(); q->Layout(); + +#if ENABLE_REMOVE_TABS_FROM_PLATER + set_current_panel(view3D); +#endif // ENABLE_REMOVE_TABS_FROM_PLATER } void Plater::priv::update(bool force_full_scene_refresh) From 3fbc4afc9593108bc1486dfb76ce7887ce141e65 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Thu, 20 Dec 2018 12:52:16 +0100 Subject: [PATCH 11/26] Upgraded "Keyboard shortcuts" dialog --- src/slic3r/GUI/KBShortcutsDialog.cpp | 100 +++++++++++++++------------ src/slic3r/GUI/SysInfoDialog.cpp | 2 +- 2 files changed, 58 insertions(+), 44 deletions(-) diff --git a/src/slic3r/GUI/KBShortcutsDialog.cpp b/src/slic3r/GUI/KBShortcutsDialog.cpp index b3edbc9a8..12929b2cc 100644 --- a/src/slic3r/GUI/KBShortcutsDialog.cpp +++ b/src/slic3r/GUI/KBShortcutsDialog.cpp @@ -3,6 +3,7 @@ #include "libslic3r/Utils.hpp" #include "GUI.hpp" #include +#include "GUI_App.hpp" namespace Slic3r { namespace GUI { @@ -19,41 +20,46 @@ KBShortcutsDialog::KBShortcutsDialog() // fonts wxFont head_font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT).Bold(); - head_font.SetPointSize(19); - - wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); - font.SetPointSize(10); - wxFont bold_font = font.Bold(); #ifdef __WXOSX__ - font.SetPointSize(12); - bold_font.SetPointSize(14); -#endif /*__WXOSX__*/ + head_font.SetPointSize(14); +#else + head_font.SetPointSize(12); +#endif // __WXOSX__ + + const wxFont& font = wxGetApp().small_font(); + const wxFont& bold_font = wxGetApp().bold_font(); fill_shortcuts(); - auto panel = new wxScrolledWindow(this, wxID_ANY, wxDefaultPosition, wxSize(500, 600)); - panel->SetScrollbars(0, 20, 1, 2); - auto sizer = new wxBoxSizer(wxVERTICAL); - panel->SetSizer(sizer); + auto panel = new wxPanel(this); + auto main_grid_sizer = new wxFlexGridSizer(2, 10, 10); + panel->SetSizer(main_grid_sizer); main_sizer->Add(panel, 1, wxEXPAND | wxALL, 0); + wxBoxSizer* l_sizer = new wxBoxSizer(wxVERTICAL); + main_grid_sizer->Add(l_sizer, 0); + + wxBoxSizer* r_sizer = new wxBoxSizer(wxVERTICAL); + main_grid_sizer->Add(r_sizer, 0); + for (auto& sc : m_full_shortcuts) { + auto sizer = sc.first == _(L("Main Shortcuts")) ? l_sizer : r_sizer; wxBoxSizer* hsizer = new wxBoxSizer(wxHORIZONTAL); - sizer->Add(hsizer, 0, wxEXPAND | wxTOP, 25); + sizer->Add(hsizer, 0, wxEXPAND | wxTOP | wxBOTTOM, 10); // logo auto *logo = new wxStaticBitmap(panel, wxID_ANY, logo_bmp); hsizer->Add(logo, 0, wxEXPAND | wxLEFT | wxRIGHT, 15); // head - wxStaticText* head = new wxStaticText(panel, wxID_ANY, sc.first, wxDefaultPosition, wxSize(400,-1)); + wxStaticText* head = new wxStaticText(panel, wxID_ANY, sc.first, wxDefaultPosition, wxSize(200,-1)); head->SetFont(head_font); hsizer->Add(head, 0, wxALIGN_CENTER_VERTICAL); // Shortcuts list - auto grid_sizer = new wxFlexGridSizer(2, 10, 25); - sizer->Add(grid_sizer, 0, wxEXPAND | wxLEFT | wxTOP, 10); + auto grid_sizer = new wxFlexGridSizer(2, 5, 15); + sizer->Add(grid_sizer, 0, wxEXPAND | wxLEFT| wxRIGHT, 15); for (auto pair : sc.second) { @@ -69,9 +75,9 @@ KBShortcutsDialog::KBShortcutsDialog() wxStdDialogButtonSizer* buttons = this->CreateStdDialogButtonSizer(wxOK); - this->SetEscapeId(wxID_CLOSE); + this->SetEscapeId(wxID_OK); this->Bind(wxEVT_BUTTON, &KBShortcutsDialog::onCloseDialog, this, wxID_OK); - main_sizer->Add(buttons, 0, wxEXPAND | wxALL, 15); + main_sizer->Add(buttons, 0, wxEXPAND | wxRIGHT | wxBOTTOM, 15); this->Bind(wxEVT_LEFT_DOWN, &KBShortcutsDialog::onCloseDialog, this); @@ -81,32 +87,40 @@ KBShortcutsDialog::KBShortcutsDialog() void KBShortcutsDialog::fill_shortcuts() { +#ifdef __WXOSX__ + const std::string ctrl = "Cmd+"; // #ys_FIXME_cmd_smb // Change it for the accorded symbol + const std::string alt = "Alt+"; // #ys_FIXME_cmd_smb // Change it for the accorded symbol +#else + const std::string ctrl = "Ctrl+"; + const std::string alt = "Alt+"; +#endif // __WXOSX__ + Shortcuts main_shortcuts; main_shortcuts.reserve(25); - main_shortcuts.push_back(Shortcut("Ctrl+O", L("Open project STL/OBJ/AMF/3MF with config, delete bed"))); - main_shortcuts.push_back(Shortcut("Ctrl+I", L("Import STL//OBJ/AMF/3MF without config, keep bed"))); - main_shortcuts.push_back(Shortcut("Ctrl+L", L("Load Config from .ini/amf/3mf/gcode"))); - main_shortcuts.push_back(Shortcut("Ctrl+Alt+L", L("Load Config from .ini/amf/3mf/gcode and merge"))); - main_shortcuts.push_back(Shortcut("Ctrl+G", L("Export Gcode"))); - main_shortcuts.push_back(Shortcut("Ctrl+S", L("Save project (3MF)"))); - main_shortcuts.push_back(Shortcut("Ctrl+R", L("(Re)slice"))); - main_shortcuts.push_back(Shortcut("Ctrl+U", L("Quick slice"))); - main_shortcuts.push_back(Shortcut("Ctrl+Alt+U", L("Quick slice and Save as"))); - main_shortcuts.push_back(Shortcut("Ctrl+Shift+U", L("Repeat last quick slice"))); - main_shortcuts.push_back(Shortcut("Ctrl+1", L("Select Plater Tab"))); - main_shortcuts.push_back(Shortcut("Ctrl+2", L("Select Print Settings Tab"))); - main_shortcuts.push_back(Shortcut("Ctrl+3", L("Select Filament Setting Tab"))); - main_shortcuts.push_back(Shortcut("Ctrl+4", L("Select Printer Setting Tab"))); - main_shortcuts.push_back(Shortcut("Ctrl+5", L("Switch to 3D"))); - main_shortcuts.push_back(Shortcut("Ctrl+6", L("Switch to Preview"))); - main_shortcuts.push_back(Shortcut("Ctrl+P", L("Preferences"))); - main_shortcuts.push_back(Shortcut("0-6", L("Camera view "))); - main_shortcuts.push_back(Shortcut("+", L("Add Instance to selected object "))); - main_shortcuts.push_back(Shortcut("-", L("Remove Instance from selected object"))); - main_shortcuts.push_back(Shortcut("?", L("Show keyboard shortcuts list"))); - main_shortcuts.push_back(Shortcut("PgUp/PgDn", L("Switch between 3D and Preview"))); - main_shortcuts.push_back(Shortcut("Shift+LeftMouse",L("Select multiple object/Move multiple object"))); + main_shortcuts.push_back(Shortcut(ctrl+"O" ,L("Open project STL/OBJ/AMF/3MF with config, delete bed"))); + main_shortcuts.push_back(Shortcut(ctrl+"I" ,L("Import STL//OBJ/AMF/3MF without config, keep bed"))); + main_shortcuts.push_back(Shortcut(ctrl+"L" ,L("Load Config from .ini/amf/3mf/gcode"))); + main_shortcuts.push_back(Shortcut(ctrl+"G" ,L("Export Gcode"))); + main_shortcuts.push_back(Shortcut(ctrl+"S" ,L("Save project (3MF)"))); + main_shortcuts.push_back(Shortcut(ctrl+alt+"L" ,L("Load Config from .ini/amf/3mf/gcode and merge"))); + main_shortcuts.push_back(Shortcut(ctrl+"R" ,L("(Re)slice"))); + main_shortcuts.push_back(Shortcut(ctrl+"U" ,L("Quick slice"))); + main_shortcuts.push_back(Shortcut(ctrl+"Shift+U" ,L("Repeat last quick slice"))); + main_shortcuts.push_back(Shortcut(ctrl+"1" ,L("Select Plater Tab"))); + main_shortcuts.push_back(Shortcut(ctrl+alt+"U" ,L("Quick slice and Save as"))); + main_shortcuts.push_back(Shortcut(ctrl+"2" ,L("Select Print Settings Tab"))); + main_shortcuts.push_back(Shortcut(ctrl+"3" ,L("Select Filament Setting Tab"))); + main_shortcuts.push_back(Shortcut(ctrl+"4" ,L("Select Printer Setting Tab"))); + main_shortcuts.push_back(Shortcut(ctrl+"5" ,L("Switch to 3D"))); + main_shortcuts.push_back(Shortcut(ctrl+"6" ,L("Switch to Preview"))); + main_shortcuts.push_back(Shortcut(ctrl+"P" ,L("Preferences"))); + main_shortcuts.push_back(Shortcut("0-6" ,L("Camera view "))); + main_shortcuts.push_back(Shortcut("+" ,L("Add Instance to selected object "))); + main_shortcuts.push_back(Shortcut("-" ,L("Remove Instance from selected object"))); + main_shortcuts.push_back(Shortcut("?" ,L("Show keyboard shortcuts list"))); + main_shortcuts.push_back(Shortcut("PgUp/PgDn" ,L("Switch between 3D and Preview"))); + main_shortcuts.push_back(Shortcut("Shift+LeftMouse" ,L("Select multiple object/Move multiple object"))); m_full_shortcuts.emplace(_(L("Main Shortcuts")), main_shortcuts); @@ -115,9 +129,9 @@ void KBShortcutsDialog::fill_shortcuts() plater_shortcuts.reserve(20); plater_shortcuts.push_back(Shortcut("A", L("Arrange"))); - plater_shortcuts.push_back(Shortcut("Ctrl+A", L("Select All objects"))); + plater_shortcuts.push_back(Shortcut(ctrl+"A", L("Select All objects"))); plater_shortcuts.push_back(Shortcut("Del", L("Delete selected"))); - plater_shortcuts.push_back(Shortcut("Ctrl+Del", L("Delete all"))); + plater_shortcuts.push_back(Shortcut(ctrl+"Del", L("Delete all"))); plater_shortcuts.push_back(Shortcut("M", L("Gizmo move"))); plater_shortcuts.push_back(Shortcut("S", L("Gizmo scale"))); plater_shortcuts.push_back(Shortcut("R", L("Gizmo rotate"))); diff --git a/src/slic3r/GUI/SysInfoDialog.cpp b/src/slic3r/GUI/SysInfoDialog.cpp index f7f1cfedb..110bfaf44 100644 --- a/src/slic3r/GUI/SysInfoDialog.cpp +++ b/src/slic3r/GUI/SysInfoDialog.cpp @@ -116,7 +116,7 @@ SysInfoDialog::SysInfoDialog() buttons->Insert(0, btn_copy_to_clipboard, 0, wxLEFT, 5); btn_copy_to_clipboard->Bind(wxEVT_BUTTON, &SysInfoDialog::onCopyToClipboard, this); - this->SetEscapeId(wxID_CLOSE); + this->SetEscapeId(wxID_OK); this->Bind(wxEVT_BUTTON, &SysInfoDialog::onCloseDialog, this, wxID_OK); main_sizer->Add(buttons, 0, wxEXPAND | wxRIGHT | wxBOTTOM, 3); From 68684dd0037a76d1f74e7368159bfc2a43ae6d9d Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 20 Dec 2018 13:20:21 +0100 Subject: [PATCH 12/26] Removed obsolete GLCanvas3D::m_shader_enabled --- src/slic3r/GUI/GLCanvas3D.cpp | 10 +--------- src/slic3r/GUI/GLCanvas3D.hpp | 2 -- src/slic3r/GUI/GUI_Preview.cpp | 2 -- src/slic3r/GUI/Plater.cpp | 1 - 4 files changed, 1 insertion(+), 14 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 77d0f0776..66d4622fe 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -3830,7 +3830,6 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas) , m_legend_texture_enabled(false) , m_picking_enabled(false) , m_moving_enabled(false) - , m_shader_enabled(false) , m_dynamic_background_enabled(false) , m_multisample_allowed(false) , m_regenerate_volumes(true) @@ -4144,11 +4143,6 @@ void GLCanvas3D::enable_toolbar(bool enable) m_toolbar.set_enabled(enable); } -void GLCanvas3D::enable_shader(bool enable) -{ - m_shader_enabled = enable; -} - void GLCanvas3D::enable_force_zoom_to_bed(bool enable) { m_force_zoom_to_bed_enabled = enable; @@ -6322,9 +6316,7 @@ void GLCanvas3D::_render_objects() const ::glEnable(GL_LIGHTING); ::glEnable(GL_DEPTH_TEST); - if (!m_shader_enabled) - _render_volumes(false); - else if (m_use_VBOs) + if (m_use_VBOs) { if (m_picking_enabled) { diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 8e9d44a4b..0cd6cb9b9 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -850,7 +850,6 @@ private: bool m_legend_texture_enabled; bool m_picking_enabled; bool m_moving_enabled; - bool m_shader_enabled; bool m_dynamic_background_enabled; bool m_multisample_allowed; bool m_regenerate_volumes; @@ -950,7 +949,6 @@ public: void enable_moving(bool enable); void enable_gizmos(bool enable); void enable_toolbar(bool enable); - void enable_shader(bool enable); void enable_force_zoom_to_bed(bool enable); void enable_dynamic_background(bool enable); void allow_multisample(bool allow); diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index 988a7b6a1..459bd9e5b 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -70,7 +70,6 @@ bool View3D::init(wxWindow* parent, Model* model, DynamicPrintConfig* config, Ba m_canvas->set_config(config); m_canvas->enable_gizmos(true); m_canvas->enable_toolbar(true); - m_canvas->enable_shader(true); m_canvas->enable_force_zoom_to_bed(true); #if !ENABLE_IMGUI @@ -257,7 +256,6 @@ bool Preview::init(wxNotebook* notebook, DynamicPrintConfig* config, BackgroundS _3DScene::add_canvas(m_canvas_widget); m_canvas = _3DScene::get_canvas(this->m_canvas_widget); m_canvas->allow_multisample(GLCanvas3DManager::can_multisample()); - m_canvas->enable_shader(true); m_canvas->set_config(m_config); m_canvas->set_process(process); m_canvas->enable_legend_texture(true); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 6a8bcc79b..db19180b4 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1132,7 +1132,6 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) this->canvas3D->set_config(config); this->canvas3D->enable_gizmos(true); this->canvas3D->enable_toolbar(true); - this->canvas3D->enable_shader(true); this->canvas3D->enable_force_zoom_to_bed(true); #endif // ENABLE_REMOVE_TABS_FROM_PLATER From afc5ed0c624b585cb41c365b591e3a917d80a096 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Thu, 20 Dec 2018 11:50:08 +0100 Subject: [PATCH 13/26] Printhost: Error message stashing, improvements --- src/slic3r/GUI/PrintHostDialogs.cpp | 78 +++++++++++++++++++++++++---- src/slic3r/GUI/PrintHostDialogs.hpp | 25 +++++++++ src/slic3r/Utils/PrintHost.cpp | 1 + 3 files changed, 95 insertions(+), 9 deletions(-) diff --git a/src/slic3r/GUI/PrintHostDialogs.cpp b/src/slic3r/GUI/PrintHostDialogs.cpp index 586fe3d83..3ab4821bd 100644 --- a/src/slic3r/GUI/PrintHostDialogs.cpp +++ b/src/slic3r/GUI/PrintHostDialogs.cpp @@ -95,22 +95,46 @@ PrintHostQueueDialog::PrintHostQueueDialog(wxWindow *parent) auto *topsizer = new wxBoxSizer(wxVERTICAL); job_list = new wxDataViewListCtrl(this, wxID_ANY); + // Note: Keep these in sync with Column job_list->AppendTextColumn("ID", wxDATAVIEW_CELL_INERT); job_list->AppendProgressColumn("Progress", wxDATAVIEW_CELL_INERT); job_list->AppendTextColumn("Status", wxDATAVIEW_CELL_INERT); job_list->AppendTextColumn("Host", wxDATAVIEW_CELL_INERT); job_list->AppendTextColumn("Filename", wxDATAVIEW_CELL_INERT); + job_list->AppendTextColumn("error_message", wxDATAVIEW_CELL_INERT, -1, wxALIGN_CENTER, wxDATAVIEW_COL_HIDDEN); auto *btnsizer = new wxBoxSizer(wxHORIZONTAL); - auto *btn_cancel = new wxButton(this, wxID_DELETE, _(L("Cancel selected"))); // TODO: enable based on status ("show error" for failed jobs) + btn_cancel = new wxButton(this, wxID_DELETE, _(L("Cancel selected"))); + btn_cancel->Disable(); + btn_error = new wxButton(this, wxID_ANY, _(L("Show error message"))); + btn_error->Disable(); auto *btn_close = new wxButton(this, wxID_CANCEL, _(L("Close"))); btnsizer->Add(btn_cancel, 0, wxRIGHT, SPACING); + btnsizer->Add(btn_error, 0); btnsizer->AddStretchSpacer(); btnsizer->Add(btn_close); topsizer->Add(job_list, 1, wxEXPAND | wxBOTTOM, SPACING); topsizer->Add(btnsizer, 0, wxEXPAND); SetSizer(topsizer); + + job_list->Bind(wxEVT_DATAVIEW_SELECTION_CHANGED, [this](wxDataViewEvent&) { on_list_select(); }); + + btn_cancel->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { + int selected = job_list->GetSelectedRow(); + if (selected == wxNOT_FOUND) { return; } + + const JobState state = get_state(selected); + if (state < ST_ERROR) { + // TODO: cancel + } + }); + + btn_error->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { + int selected = job_list->GetSelectedRow(); + if (selected == wxNOT_FOUND) { return; } + GUI::show_error(nullptr, job_list->GetTextValue(selected, COL_ERRORMSG)); + }); } void PrintHostQueueDialog::append_job(const PrintHostJob &job) @@ -123,29 +147,65 @@ void PrintHostQueueDialog::append_job(const PrintHostJob &job) fields.push_back(wxVariant(_(L("Enqueued")))); fields.push_back(wxVariant(job.printhost->get_host())); fields.push_back(wxVariant(job.upload_data.upload_path.string())); - job_list->AppendItem(fields); + fields.push_back(wxVariant("")); + job_list->AppendItem(fields, static_cast(ST_NEW)); +} + +PrintHostQueueDialog::JobState PrintHostQueueDialog::get_state(int idx) +{ + wxCHECK_MSG(idx >= 0 && idx < job_list->GetItemCount(), ST_ERROR, "Out of bounds access to job list"); + return static_cast(job_list->GetItemData(job_list->RowToItem(idx))); +} + +void PrintHostQueueDialog::set_state(int idx, JobState state) +{ + wxCHECK_RET(idx >= 0 && idx < job_list->GetItemCount(), "Out of bounds access to job list"); + job_list->SetItemData(job_list->RowToItem(idx), static_cast(state)); +} + +void PrintHostQueueDialog::on_list_select() +{ + int selected = job_list->GetSelectedRow(); + if (selected != wxNOT_FOUND) { + const JobState state = get_state(selected); + btn_cancel->Enable(state < ST_ERROR); + btn_error->Enable(state == ST_ERROR); + Layout(); + } else { + btn_cancel->Disable(); + } } void PrintHostQueueDialog::on_progress(Event &evt) { wxCHECK_RET(evt.job_id < job_list->GetItemCount(), "Out of bounds access to job list"); - const wxVariant status(evt.progress < 100 ? _(L("Uploading")) : _(L("Complete"))); + if (evt.progress < 100) { + set_state(evt.job_id, ST_PROGRESS); + job_list->SetValue(wxVariant(evt.progress), evt.job_id, COL_PROGRESS); + job_list->SetValue(_(L("Uploading")), evt.job_id, COL_STATUS); + } else { + set_state(evt.job_id, ST_COMPLETED); + job_list->SetValue(wxVariant(100), evt.job_id, COL_PROGRESS); + job_list->SetValue(_(L("Complete")), evt.job_id, COL_STATUS); + } - job_list->SetValue(wxVariant(evt.progress), evt.job_id, 1); - job_list->SetValue(status, evt.job_id, 2); + on_list_select(); } void PrintHostQueueDialog::on_error(Event &evt) { wxCHECK_RET(evt.job_id < job_list->GetItemCount(), "Out of bounds access to job list"); - job_list->SetValue(wxVariant(0), evt.job_id, 1); - job_list->SetValue(wxVariant(_(L("Error"))), evt.job_id, 2); - - // TODO: keep the error for repeated display + set_state(evt.job_id, ST_ERROR); auto errormsg = wxString::Format("%s\n%s", _(L("Error uploading to print host:")), evt.error); + job_list->SetValue(wxVariant(0), evt.job_id, COL_PROGRESS); + job_list->SetValue(wxVariant(_(L("Error"))), evt.job_id, COL_STATUS); + job_list->SetValue(wxVariant(errormsg), evt.job_id, COL_ERRORMSG); // Stashes the error message into a hidden column for later + + on_list_select(); + GUI::show_error(nullptr, std::move(errormsg)); } diff --git a/src/slic3r/GUI/PrintHostDialogs.hpp b/src/slic3r/GUI/PrintHostDialogs.hpp index e38acee32..b8b5d62bb 100644 --- a/src/slic3r/GUI/PrintHostDialogs.hpp +++ b/src/slic3r/GUI/PrintHostDialogs.hpp @@ -13,10 +13,12 @@ #include "MsgDialog.hpp" #include "../Utils/PrintHost.hpp" +class wxButton; class wxTextCtrl; class wxCheckBox; class wxDataViewListCtrl; + namespace Slic3r { struct PrintHostJob; @@ -60,11 +62,34 @@ public: void append_job(const PrintHostJob &job); private: + enum Column { + COL_ID, + COL_PROGRESS, + COL_STATUS, + COL_HOST, + COL_FILENAME, + COL_ERRORMSG, + }; + + enum JobState { + ST_NEW, + ST_PROGRESS, + ST_ERROR, + ST_CANCELLING, + ST_CANCELLED, + ST_COMPLETED, + }; + + wxButton *btn_cancel; + wxButton *btn_error; wxDataViewListCtrl *job_list; // Note: EventGuard prevents delivery of progress evts to a freed PrintHostQueueDialog EventGuard on_progress_evt; EventGuard on_error_evt; + JobState get_state(int idx); + void set_state(int idx, JobState); + void on_list_select(); void on_progress(Event&); void on_error(Event&); }; diff --git a/src/slic3r/Utils/PrintHost.cpp b/src/slic3r/Utils/PrintHost.cpp index 934436a19..5d0275d2b 100644 --- a/src/slic3r/Utils/PrintHost.cpp +++ b/src/slic3r/Utils/PrintHost.cpp @@ -127,6 +127,7 @@ void PrintHostJobQueue::priv::progress_fn(Http::Progress progress, bool &cancel) } else if (cancel_id > job_id) { jobs->at(cancel_id - job_id).cancelled = true; } + // TODO: emit cancelled } cancels->clear(); From 2d0dc6b050ebf9288f187fa7f321d6394bdcc4ad Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Thu, 20 Dec 2018 13:36:49 +0100 Subject: [PATCH 14/26] Printhost: Cancelation, bugfixes --- src/libslic3r/Channel.hpp | 3 +- src/slic3r/GUI/PrintHostDialogs.cpp | 28 ++++++- src/slic3r/GUI/PrintHostDialogs.hpp | 3 + src/slic3r/Utils/Http.cpp | 6 +- src/slic3r/Utils/PrintHost.cpp | 109 +++++++++++++++++++++------- src/slic3r/Utils/PrintHost.hpp | 2 + 6 files changed, 118 insertions(+), 33 deletions(-) diff --git a/src/libslic3r/Channel.hpp b/src/libslic3r/Channel.hpp index 9cf025f2c..68369af63 100644 --- a/src/libslic3r/Channel.hpp +++ b/src/libslic3r/Channel.hpp @@ -77,8 +77,7 @@ public: } } - // Unlocked observers/hints - // Thread unsafe! Keep in mind you need to re-verify the result after locking! + // Unlocked observer/hint. Thread unsafe! Keep in mind you need to re-verify the result after locking. size_t size_hint() const noexcept { return m_queue.size(); } LockedConstPtr lock_read() const diff --git a/src/slic3r/GUI/PrintHostDialogs.cpp b/src/slic3r/GUI/PrintHostDialogs.cpp index 3ab4821bd..8c0c0fc85 100644 --- a/src/slic3r/GUI/PrintHostDialogs.cpp +++ b/src/slic3r/GUI/PrintHostDialogs.cpp @@ -14,6 +14,7 @@ #include #include "GUI.hpp" +#include "GUI_App.hpp" #include "MsgDialog.hpp" #include "I18N.hpp" #include "../Utils/PrintHost.hpp" @@ -59,7 +60,8 @@ bool PrintHostSendDialog::start_print() const wxDEFINE_EVENT(EVT_PRINTHOST_PROGRESS, PrintHostQueueDialog::Event); -wxDEFINE_EVENT(EVT_PRINTHOST_ERROR, PrintHostQueueDialog::Event); +wxDEFINE_EVENT(EVT_PRINTHOST_ERROR, PrintHostQueueDialog::Event); +wxDEFINE_EVENT(EVT_PRINTHOST_CANCEL, PrintHostQueueDialog::Event); PrintHostQueueDialog::Event::Event(wxEventType eventType, int winid, size_t job_id) : wxEvent(winid, eventType) @@ -87,6 +89,7 @@ PrintHostQueueDialog::PrintHostQueueDialog(wxWindow *parent) : wxDialog(parent, wxID_ANY, _(L("Print host upload queue")), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) , on_progress_evt(this, EVT_PRINTHOST_PROGRESS, &PrintHostQueueDialog::on_progress, this) , on_error_evt(this, EVT_PRINTHOST_ERROR, &PrintHostQueueDialog::on_error, this) + , on_cancel_evt(this, EVT_PRINTHOST_CANCEL, &PrintHostQueueDialog::on_cancel, this) { enum { HEIGHT = 800, WIDTH = 400, SPACING = 5 }; @@ -127,6 +130,7 @@ PrintHostQueueDialog::PrintHostQueueDialog(wxWindow *parent) const JobState state = get_state(selected); if (state < ST_ERROR) { // TODO: cancel + GUI::wxGetApp().printhost_job_queue().cancel(selected); } }); @@ -161,6 +165,15 @@ void PrintHostQueueDialog::set_state(int idx, JobState state) { wxCHECK_RET(idx >= 0 && idx < job_list->GetItemCount(), "Out of bounds access to job list"); job_list->SetItemData(job_list->RowToItem(idx), static_cast(state)); + + switch (state) { + case ST_NEW: job_list->SetValue(_(L("Enqueued")), idx, COL_STATUS); break; + case ST_PROGRESS: job_list->SetValue(_(L("Uploading")), idx, COL_STATUS); break; + case ST_ERROR: job_list->SetValue(_(L("Error")), idx, COL_STATUS); break; + case ST_CANCELLING: job_list->SetValue(_(L("Cancelling")), idx, COL_STATUS); break; + case ST_CANCELLED: job_list->SetValue(_(L("Cancelled")), idx, COL_STATUS); break; + case ST_COMPLETED: job_list->SetValue(_(L("Completed")), idx, COL_STATUS); break; + } } void PrintHostQueueDialog::on_list_select() @@ -183,11 +196,9 @@ void PrintHostQueueDialog::on_progress(Event &evt) if (evt.progress < 100) { set_state(evt.job_id, ST_PROGRESS); job_list->SetValue(wxVariant(evt.progress), evt.job_id, COL_PROGRESS); - job_list->SetValue(_(L("Uploading")), evt.job_id, COL_STATUS); } else { set_state(evt.job_id, ST_COMPLETED); job_list->SetValue(wxVariant(100), evt.job_id, COL_PROGRESS); - job_list->SetValue(_(L("Complete")), evt.job_id, COL_STATUS); } on_list_select(); @@ -201,7 +212,6 @@ void PrintHostQueueDialog::on_error(Event &evt) auto errormsg = wxString::Format("%s\n%s", _(L("Error uploading to print host:")), evt.error); job_list->SetValue(wxVariant(0), evt.job_id, COL_PROGRESS); - job_list->SetValue(wxVariant(_(L("Error"))), evt.job_id, COL_STATUS); job_list->SetValue(wxVariant(errormsg), evt.job_id, COL_ERRORMSG); // Stashes the error message into a hidden column for later on_list_select(); @@ -209,5 +219,15 @@ void PrintHostQueueDialog::on_error(Event &evt) GUI::show_error(nullptr, std::move(errormsg)); } +void PrintHostQueueDialog::on_cancel(Event &evt) +{ + wxCHECK_RET(evt.job_id < job_list->GetItemCount(), "Out of bounds access to job list"); + + set_state(evt.job_id, ST_CANCELLED); + job_list->SetValue(wxVariant(0), evt.job_id, COL_PROGRESS); + + on_list_select(); +} + }} diff --git a/src/slic3r/GUI/PrintHostDialogs.hpp b/src/slic3r/GUI/PrintHostDialogs.hpp index b8b5d62bb..ee3fe26d8 100644 --- a/src/slic3r/GUI/PrintHostDialogs.hpp +++ b/src/slic3r/GUI/PrintHostDialogs.hpp @@ -86,16 +86,19 @@ private: // Note: EventGuard prevents delivery of progress evts to a freed PrintHostQueueDialog EventGuard on_progress_evt; EventGuard on_error_evt; + EventGuard on_cancel_evt; JobState get_state(int idx); void set_state(int idx, JobState); void on_list_select(); void on_progress(Event&); void on_error(Event&); + void on_cancel(Event&); }; wxDECLARE_EVENT(EVT_PRINTHOST_PROGRESS, PrintHostQueueDialog::Event); wxDECLARE_EVENT(EVT_PRINTHOST_ERROR, PrintHostQueueDialog::Event); +wxDECLARE_EVENT(EVT_PRINTHOST_CANCEL, PrintHostQueueDialog::Event); }} diff --git a/src/slic3r/Utils/Http.cpp b/src/slic3r/Utils/Http.cpp index 30478cb01..2561348bb 100644 --- a/src/slic3r/Utils/Http.cpp +++ b/src/slic3r/Utils/Http.cpp @@ -149,7 +149,9 @@ int Http::priv::xfercb(void *userp, curl_off_t dltotal, curl_off_t dlnow, curl_o self->progressfn(progress, cb_cancel); } - return self->cancel || cb_cancel; + if (cb_cancel) { self->cancel = true; } + + return self->cancel; } int Http::priv::xfercb_legacy(void *userp, double dltotal, double dlnow, double ultotal, double ulnow) @@ -278,7 +280,7 @@ void Http::priv::http_perform() } else { long http_status = 0; ::curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_status); - + if (http_status >= 400) { if (errorfn) { errorfn(std::move(buffer), std::string(), http_status); } } else { diff --git a/src/slic3r/Utils/PrintHost.cpp b/src/slic3r/Utils/PrintHost.cpp index 5d0275d2b..d50d6c6bd 100644 --- a/src/slic3r/Utils/PrintHost.cpp +++ b/src/slic3r/Utils/PrintHost.cpp @@ -49,6 +49,7 @@ struct PrintHostJobQueue::priv Channel channel_cancels; size_t job_id = 0; int prev_progress = -1; + fs::path source_to_remove; std::thread bg_thread; bool bg_exit = false; @@ -57,9 +58,14 @@ struct PrintHostJobQueue::priv priv(PrintHostJobQueue *q) : q(q) {} + void emit_progress(int progress); + void emit_error(wxString error); + void emit_cancel(size_t id); void start_bg_thread(); void bg_thread_main(); void progress_fn(Http::Progress progress, bool &cancel); + void remove_source(const fs::path &path); + void remove_source(); void perform_job(PrintHostJob the_job); }; @@ -78,6 +84,24 @@ PrintHostJobQueue::~PrintHostJobQueue() } } +void PrintHostJobQueue::priv::emit_progress(int progress) +{ + auto evt = new PrintHostQueueDialog::Event(GUI::EVT_PRINTHOST_PROGRESS, queue_dialog->GetId(), job_id, progress); + wxQueueEvent(queue_dialog, evt); +} + +void PrintHostJobQueue::priv::emit_error(wxString error) +{ + auto evt = new PrintHostQueueDialog::Event(GUI::EVT_PRINTHOST_ERROR, queue_dialog->GetId(), job_id, std::move(error)); + wxQueueEvent(queue_dialog, evt); +} + +void PrintHostJobQueue::priv::emit_cancel(size_t id) +{ + auto evt = new PrintHostQueueDialog::Event(GUI::EVT_PRINTHOST_CANCEL, queue_dialog->GetId(), id); + wxQueueEvent(queue_dialog, evt); +} + void PrintHostJobQueue::priv::start_bg_thread() { if (bg_thread.joinable()) { return; } @@ -96,21 +120,43 @@ void PrintHostJobQueue::priv::bg_thread_main() // Pick up jobs from the job channel: while (! bg_exit) { auto job = channel_jobs.pop(); // Sleeps in a cond var if there are no jobs + source_to_remove = job.upload_data.source_path; + + BOOST_LOG_TRIVIAL(debug) << boost::format("PrintHostJobQueue/bg_thread: Received job: [%1%]: `%2%` -> `%3%`, cancelled: %4%") + % job_id + % job.upload_data.upload_path + % job.printhost->get_host() + % job.cancelled; + if (! job.cancelled) { perform_job(std::move(job)); } + + remove_source(); job_id++; } } catch (const std::exception &e) { - auto evt = new PrintHostQueueDialog::Event(GUI::EVT_PRINTHOST_ERROR, queue_dialog->GetId(), job_id, e.what()); - wxQueueEvent(queue_dialog, evt); + emit_error(e.what()); } catch (...) { wxTheApp->OnUnhandledException(); } + + // Cleanup leftover files, if any + remove_source(); + auto jobs = channel_jobs.lock_rw(); + for (const PrintHostJob &job : *jobs) { + remove_source(job.upload_data.source_path); + } } void PrintHostJobQueue::priv::progress_fn(Http::Progress progress, bool &cancel) { + if (cancel) { + // When cancel is true from the start, Http indicates request has been cancelled + emit_cancel(job_id); + return; + } + if (bg_exit) { cancel = true; return; @@ -125,49 +171,57 @@ void PrintHostJobQueue::priv::progress_fn(Http::Progress progress, bool &cancel) if (cancel_id == job_id) { cancel = true; } else if (cancel_id > job_id) { - jobs->at(cancel_id - job_id).cancelled = true; + const size_t idx = cancel_id - job_id - 1; + if (idx < jobs->size()) { + jobs->at(idx).cancelled = true; + BOOST_LOG_TRIVIAL(debug) << boost::format("PrintHostJobQueue: Job id %1% cancelled") % cancel_id; + emit_cancel(cancel_id); + } } - // TODO: emit cancelled } cancels->clear(); } - int gui_progress = progress.ultotal > 0 ? 100*progress.ulnow / progress.ultotal : 0; - if (gui_progress != prev_progress) { - auto evt = new PrintHostQueueDialog::Event(GUI::EVT_PRINTHOST_PROGRESS, queue_dialog->GetId(), job_id, gui_progress); - wxQueueEvent(queue_dialog, evt); - prev_progress = gui_progress; + if (! cancel) { + int gui_progress = progress.ultotal > 0 ? 100*progress.ulnow / progress.ultotal : 0; + if (gui_progress != prev_progress) { + emit_progress(gui_progress); + prev_progress = gui_progress; + } } } +void PrintHostJobQueue::priv::remove_source(const fs::path &path) +{ + if (! path.empty()) { + boost::system::error_code ec; + fs::remove(path, ec); + if (ec) { + BOOST_LOG_TRIVIAL(error) << boost::format("PrintHostJobQueue: Error removing file `%1%`: %2%") % path % ec; + } + } +} + +void PrintHostJobQueue::priv::remove_source() +{ + remove_source(source_to_remove); + source_to_remove.clear(); +} + void PrintHostJobQueue::priv::perform_job(PrintHostJob the_job) { if (bg_exit || the_job.empty()) { return; } - BOOST_LOG_TRIVIAL(debug) << boost::format("PrintHostJobQueue/bg_thread: Got job: `%1%` -> `%2%`") - % the_job.upload_data.upload_path - % the_job.printhost->get_host(); - - const fs::path gcode_path = the_job.upload_data.source_path; - bool success = the_job.printhost->upload(std::move(the_job.upload_data), [this](Http::Progress progress, bool &cancel) { this->progress_fn(std::move(progress), cancel); }, [this](wxString error) { - auto evt = new PrintHostQueueDialog::Event(GUI::EVT_PRINTHOST_ERROR, queue_dialog->GetId(), job_id, std::move(error)); - wxQueueEvent(queue_dialog, evt); + emit_error(std::move(error)); } ); if (success) { - auto evt = new PrintHostQueueDialog::Event(GUI::EVT_PRINTHOST_PROGRESS, queue_dialog->GetId(), job_id, 100); - wxQueueEvent(queue_dialog, evt); - } - - boost::system::error_code ec; - fs::remove(gcode_path, ec); - if (ec) { - BOOST_LOG_TRIVIAL(error) << boost::format("PrintHostJobQueue: Error removing file `%1%`: %2%") % gcode_path % ec; + emit_progress(100); } } @@ -178,5 +232,10 @@ void PrintHostJobQueue::enqueue(PrintHostJob job) p->channel_jobs.push(std::move(job)); } +void PrintHostJobQueue::cancel(size_t id) +{ + p->channel_cancels.push(id); +} + } diff --git a/src/slic3r/Utils/PrintHost.hpp b/src/slic3r/Utils/PrintHost.hpp index a6c7a4723..39b93f5fb 100644 --- a/src/slic3r/Utils/PrintHost.hpp +++ b/src/slic3r/Utils/PrintHost.hpp @@ -55,6 +55,7 @@ struct PrintHostJob PrintHostJob(PrintHostJob &&other) : upload_data(std::move(other.upload_data)) , printhost(std::move(other.printhost)) + , cancelled(other.cancelled) {} PrintHostJob(DynamicPrintConfig *config) @@ -66,6 +67,7 @@ struct PrintHostJob { upload_data = std::move(other.upload_data); printhost = std::move(other.printhost); + cancelled = other.cancelled; return *this; } From ece3c74380ce9dae3abcbf5293bf1f7eb7a82aaa Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Thu, 20 Dec 2018 13:44:44 +0100 Subject: [PATCH 15/26] Printhost: Minor bugfix --- src/slic3r/Utils/PrintHost.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/Utils/PrintHost.cpp b/src/slic3r/Utils/PrintHost.cpp index d50d6c6bd..b6f5b8b9c 100644 --- a/src/slic3r/Utils/PrintHost.cpp +++ b/src/slic3r/Utils/PrintHost.cpp @@ -138,7 +138,7 @@ void PrintHostJobQueue::priv::bg_thread_main() } catch (const std::exception &e) { emit_error(e.what()); } catch (...) { - wxTheApp->OnUnhandledException(); + emit_error("Unknown exception"); } // Cleanup leftover files, if any From 70bfa4202f15e40331107c884cc8ee4fa8b09d3c Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Thu, 20 Dec 2018 15:22:58 +0100 Subject: [PATCH 16/26] Fix for SPE-700 (Corrupted slice data) --- src/libslic3r/SLA/SLASupportTree.cpp | 9 +++++++++ src/libslic3r/SLA/SLASupportTree.hpp | 2 ++ src/libslic3r/SLA/SLASupportTreeIGL.cpp | 2 +- src/libslic3r/SLAPrint.cpp | 12 +++++++++--- 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/libslic3r/SLA/SLASupportTree.cpp b/src/libslic3r/SLA/SLASupportTree.cpp index 37b0c0ffc..c599cd83e 100644 --- a/src/libslic3r/SLA/SLASupportTree.cpp +++ b/src/libslic3r/SLA/SLASupportTree.cpp @@ -722,6 +722,10 @@ public: return m_pad; } + void remove_pad() { + m_pad = Pad(); + } + const Pad& pad() const { return m_pad; } // WITHOUT THE PAD!!! @@ -1729,6 +1733,11 @@ const TriangleMesh &SLASupportTree::get_pad() const return m_impl->pad().tmesh; } +void SLASupportTree::remove_pad() +{ + m_impl->remove_pad(); +} + SLASupportTree::SLASupportTree(const PointSet &points, const EigenMesh3D& emesh, const SupportConfig &cfg, diff --git a/src/libslic3r/SLA/SLASupportTree.hpp b/src/libslic3r/SLA/SLASupportTree.hpp index 62e790611..e19f263b6 100644 --- a/src/libslic3r/SLA/SLASupportTree.hpp +++ b/src/libslic3r/SLA/SLASupportTree.hpp @@ -164,6 +164,8 @@ public: /// Get the pad geometry const TriangleMesh& get_pad() const; + void remove_pad(); + }; } diff --git a/src/libslic3r/SLA/SLASupportTreeIGL.cpp b/src/libslic3r/SLA/SLASupportTreeIGL.cpp index 49290b3b8..6d4a770aa 100644 --- a/src/libslic3r/SLA/SLASupportTreeIGL.cpp +++ b/src/libslic3r/SLA/SLASupportTreeIGL.cpp @@ -198,7 +198,7 @@ PointSet normals(const PointSet& points, const EigenMesh3D& emesh, }); if(!neighnorms.empty()) { // there were neighbors to count with - // sum up the normals and than normalize the result again. + // sum up the normals and then normalize the result again. // This unification seems to be enough. Vec3d sumnorm(0, 0, 0); sumnorm = std::accumulate(neighnorms.begin(), lend, sumnorm); diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 90abe290f..15f0e410e 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -560,9 +560,13 @@ void SLAPrint::process() // and before the supports had been sliced. (or the slicing has to be // repeated) - if(po.m_config.pad_enable.getBool() && - po.m_supportdata && - po.m_supportdata->support_tree_ptr) + if(!po.m_supportdata || !po.m_supportdata->support_tree_ptr) { + BOOST_LOG_TRIVIAL(warning) << "Uninitialized support data at " + << "pad creation."; + return; + } + + if(po.m_config.pad_enable.getBool()) { double wt = po.m_config.pad_wall_thickness.getFloat(); double h = po.m_config.pad_wall_height.getFloat(); @@ -586,6 +590,8 @@ void SLAPrint::process() pcfg.throw_on_cancel = thrfn; po.m_supportdata->support_tree_ptr->add_pad(bp, pcfg); + } else { + po.m_supportdata->support_tree_ptr->remove_pad(); } po.throw_if_canceled(); From 5cd59377953d7bfaf5fbf79c351821c2c862b9df Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 20 Dec 2018 16:09:25 +0100 Subject: [PATCH 17/26] More transparent background texture for toolbars --- resources/icons/toolbar_background.png | Bin 1544 -> 1540 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/resources/icons/toolbar_background.png b/resources/icons/toolbar_background.png index 2b5ea013be7a6b804fb8390bec7d386e39e42d16..e7ce3c14615b551ea8fa873b1fe52c4215160a8f 100644 GIT binary patch delta 1256 zcmVOt{9C}mBHD29)sZ>waKge_JOYoK|c zR7aT@(H<12QGcO9eYKS;mKeCRp=GWtOP0hqb6rrvEHv08OLJhvQbA21=4&mq{O0Aa zQiA73&}4$KN%T{3uY`Y6E<|nmCkhxh0FUKu>*e{yZ9FZ5u#{;9Id65`PfzkwhtyH)bP39258ytehqA z0Rp7Tjobhmkq9`6r*F(LTDq)!igC37gyNtW&}1oq6@nsvEF|PmQPJR3HL7XStR+ee zQDcl2=N(l{ESOp}vt-#yk`$7rm@K7~Q^}kKSD5CQ&E=GHE(J~tOc%^9&?x2LLymCh z5f3}kk$;a;kv=t4t+857HP_O(NyG7Pv6*YB^3jyP|xZK{vd=!x9d)M!(i#KO|E8#Rc{K1|TOPINK@F%AUcHVGi1c{1~fLf}bmGV_^n zD3n2sbi!#giGg6~#5(9=cO&;DH>csZxbd&Zxk-ucUyySX-6r>$+Y4%~tZx)qfaWQj zG4(QVu|c7y!l}&fq(5%m-x_!udK-EhdK-EhdK-Eh`hN@!{CL1$P4^RitdWu+h246S z2m>;I6b}a*L#rkB00082NklJG9Kw`%~MxcI@jU$u3NU;s>i{x^Uc&;{Dg^(GC0emp{)9l%GR2i!Tw zo3;Qx1K$t*@V#^QBk<(8y%cibA$~tOC4fiZlXEMbCa~F$AU|-}e{xo(bq~A(FU1F8 z?}D%Aj7qN;*ZQvjx?b=l;V!QAn*bW#>LsNe*ZfZa9cPl9P7y%ycvop@0o8zycT*K7 zfL4h2hf4I>Kw$e;Pid-$-FreMrxw`0&sUl%0blr}Ecfc)TLBr9sstaCx&#Xx*JACG zrX7GsGzTUFkO9a5lvn^8mox1EGMCd+ld1%B0r8U_1u%b$=Kurek(@#C8~|Vf44p|b zhH=f`JPGUr3ujY$i@4SR6W|s2aAX_Z&N=^i|1ZCg{o|KwKo@8`$D6&{?{nmRPj=#t8bAkV z;r|d^yEQ!9hdhJgR_~bX%$-+b1WlkGj}R446Bn~$`#OKd_NCr9F8=(~9sCCDH&b3) Sn1ts50000yS&GhaJQZPIe*%=>DfHr2SYHLLQmLn z7ZQ&;&RGO2kR$~)uR8Fwc=UPMRqS=_+|_*w-qm}GoiE!ikD+irZio03qirXB9lI5w z`xVh`=7$F+*A$;(H%3ci^mBJ5L_{jOy{V6_tR5T>gi_Y9h+_CC`nF0&N!Vfqu?Ct4 zN_CWp5zRq?8h;fU)K^=nVu^t}8(QYdvTR9=GuH(r%tC`rvNQ)4EEUuQX1>-!Yu>!( ztCTQvBX}}FY!dxc+$-asluKxgnYu(iU9rNtc;+;gG0DvuUI0R4$5dB*S8;cFVBszx}#;yj~@i3L-OW|k~lNs>a+6qBWtaw?g#;0V(kv$>pd&ZS_|0_lR$1s?F zJ>p?UI)Cy}D$=Khsx?-tspeW5H)(kNTWsc9YPpq89jVkq*B-m|)N?Nbxi(~kp(73( zY2;BZYMbgKHF_fVH8tAQCb6*m>_!b{vkwWH$B9m6AjW|}+$I4eG*4zeQ3yQAO=dnb zUJ7MUBb{&>O=2JzI^1-0ap z2m>;I4hbAP>e>bE00086Nklv2ex?mCSNzY@``V1tRDl-I1nNKyr~qYj z4l7^@%z!B{21daA*bQVyey#y@;^GJAe$m!{F@gaw`QHF)Ko@8`*Q+!H`f(3&asZ!! z9&qCvui66m3j93uX6cm=Zp%k7uWi)0J@&=CE+Hn^_u`1Ug{;K9oPI%03BzNoK7A;nsD zQ+SKG)&P`t-gpIGfLmu&Xb-@zLjeFh#h*>*R7l@|AG?f3cMc~5rah8jQzXyN}5T)H*eJDWU% z{8H~D*@+vk#t51~J? Date: Thu, 20 Dec 2018 16:25:32 +0100 Subject: [PATCH 18/26] Don't set done on a canceled step. --- src/libslic3r/SLAPrint.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 15f0e410e..31ba0be3d 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -872,6 +872,7 @@ void SLAPrint::process() if(po->m_stepmask[currentstep] && po->set_started(currentstep)) { report_status(*this, int(st), OBJ_STEP_LABELS[currentstep]); pobj_program[currentstep](*po); + throw_if_canceled(); po->set_done(currentstep); } @@ -897,6 +898,7 @@ void SLAPrint::process() { report_status(*this, int(st), PRINT_STEP_LABELS[currentstep]); print_program[currentstep](); + throw_if_canceled(); set_done(currentstep); } From 4d70546a0596eb3e256a9d78bfee7c0b924383e2 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Thu, 20 Dec 2018 16:35:54 +0100 Subject: [PATCH 19/26] Fix: Schedule SLA print uploads too (the same way as FFF) --- src/slic3r/GUI/BackgroundSlicingProcess.cpp | 56 +++++++++++++-------- src/slic3r/GUI/BackgroundSlicingProcess.hpp | 1 + 2 files changed, 37 insertions(+), 20 deletions(-) diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/src/slic3r/GUI/BackgroundSlicingProcess.cpp index 66a0884a4..44ac1bc71 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.cpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp @@ -84,26 +84,7 @@ void BackgroundSlicingProcess::process_fff() run_post_process_scripts(export_path, m_fff_print->config()); m_print->set_status(100, "G-code file exported to " + export_path); } else if (! m_upload_job.empty()) { - // A print host upload job has been scheduled - - // XXX: is fs::path::string() right? - - // Generate a unique temp path to which the gcode is copied - boost::filesystem::path source_path = boost::filesystem::temp_directory_path() - / boost::filesystem::unique_path(".printhost.%%%%-%%%%-%%%%-%%%%.gcode"); - - if (copy_file(m_temp_output_path, source_path.string()) != 0) { - throw std::runtime_error("Copying of the temporary G-code to the output G-code failed"); - } - - m_print->set_status(95, "Running post-processing scripts"); - run_post_process_scripts(source_path.string(), m_fff_print->config()); - m_print->set_status(100, (boost::format("Scheduling upload to `%1%`. See Window -> Print Host Upload Queue") % m_upload_job.printhost->get_host()).str()); - - m_upload_job.upload_data.source_path = std::move(source_path); - m_upload_job.upload_data.upload_path = m_fff_print->print_statistics().finalize_output_path(m_upload_job.upload_data.upload_path.string()); - - GUI::wxGetApp().printhost_job_queue().enqueue(std::move(m_upload_job)); + prepare_upload(); } else { m_print->set_status(100, "Slicing complete"); } @@ -170,6 +151,10 @@ void BackgroundSlicingProcess::process_sla() if (! m_export_path.empty()) { m_sla_print->export_raster(m_export_path); m_print->set_status(100, "Zip file exported to " + m_export_path); + } else if (! m_upload_job.empty()) { + prepare_upload(); + } else { + m_print->set_status(100, "Slicing complete"); } this->set_step_done(bspsGCodeFinalize); } @@ -440,4 +425,35 @@ bool BackgroundSlicingProcess::invalidate_all_steps() return m_step_state.invalidate_all([this](){ this->stop_internal(); }); } +void BackgroundSlicingProcess::prepare_upload() +{ + // A print host upload job has been scheduled, enqueue it to the printhost job queue + + // XXX: is fs::path::string() right? + + // 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"); + + if (m_print == m_fff_print) { + m_print->set_status(95, "Running post-processing scripts"); + run_post_process_scripts(source_path.string(), m_fff_print->config()); + + if (copy_file(m_temp_output_path, source_path.string()) != 0) { + throw std::runtime_error("Copying of the temporary G-code to the output G-code failed"); + } + + 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_print->set_status(100, (boost::format("Scheduling upload to `%1%`. See Window -> Print Host Upload Queue") % m_upload_job.printhost->get_host()).str()); + + m_upload_job.upload_data.source_path = std::move(source_path); + + GUI::wxGetApp().printhost_job_queue().enqueue(std::move(m_upload_job)); +} + }; // namespace Slic3r diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.hpp b/src/slic3r/GUI/BackgroundSlicingProcess.hpp index 222ed147e..5911c8a02 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.hpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.hpp @@ -167,6 +167,7 @@ private: bool invalidate_all_steps(); // If the background processing stop was requested, throw CanceledException. void throw_if_canceled() const { if (m_print->canceled()) throw CanceledException(); } + void prepare_upload(); // wxWidgets command ID to be sent to the platter to inform that the slicing is finished, and the G-code export will continue. int m_event_slicing_completed_id = 0; From f3185365566d3389c017ed39903e083a8942d901 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Thu, 20 Dec 2018 16:42:46 +0100 Subject: [PATCH 20/26] Printhost: Make queue window non-modal, fix upload start progress --- src/slic3r/GUI/MainFrame.cpp | 2 +- src/slic3r/Utils/PrintHost.cpp | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 871d50a3d..5b38129de 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -376,7 +376,7 @@ void MainFrame::init_menubar() windowMenu->AppendSeparator(); append_menu_item(windowMenu, wxID_ANY, L("Print Host Upload Queue"), L("Display the Print Host Upload Queue window"), - [this](wxCommandEvent&) { m_printhost_queue_dlg->ShowModal(); }, "arrow_up.png"); + [this](wxCommandEvent&) { m_printhost_queue_dlg->Show(); }, "arrow_up.png"); } // View menu diff --git a/src/slic3r/Utils/PrintHost.cpp b/src/slic3r/Utils/PrintHost.cpp index b6f5b8b9c..84d823d89 100644 --- a/src/slic3r/Utils/PrintHost.cpp +++ b/src/slic3r/Utils/PrintHost.cpp @@ -213,6 +213,8 @@ void PrintHostJobQueue::priv::perform_job(PrintHostJob the_job) { if (bg_exit || the_job.empty()) { return; } + emit_progress(0); // Indicate the upload is starting + bool success = the_job.printhost->upload(std::move(the_job.upload_data), [this](Http::Progress progress, bool &cancel) { this->progress_fn(std::move(progress), cancel); }, [this](wxString error) { From af086263988d9ac50361bff47370e64610fecf33 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Thu, 20 Dec 2018 16:00:51 +0100 Subject: [PATCH 21/26] Duet: Implement upload() (refactoring from old code) --- src/slic3r/Utils/Duet.cpp | 133 ++++++++++----------------------- src/slic3r/Utils/Duet.hpp | 2 +- src/slic3r/Utils/OctoPrint.cpp | 15 +--- src/slic3r/Utils/OctoPrint.hpp | 1 - src/slic3r/Utils/PrintHost.cpp | 10 +++ src/slic3r/Utils/PrintHost.hpp | 3 + 6 files changed, 55 insertions(+), 109 deletions(-) diff --git a/src/slic3r/Utils/Duet.cpp b/src/slic3r/Utils/Duet.cpp index fd77fc130..3449e610e 100644 --- a/src/slic3r/Utils/Duet.cpp +++ b/src/slic3r/Utils/Duet.cpp @@ -54,91 +54,46 @@ wxString Duet::get_test_failed_msg (wxString &msg) const return wxString::Format("%s: %s", _(L("Could not connect to Duet")), msg); } -// bool Duet::send_gcode(const std::string &filename) const -// { -// enum { PROGRESS_RANGE = 1000 }; - -// const auto errortitle = _(L("Error while uploading to the Duet")); -// fs::path filepath(filename); - -// GUI::PrintHostSendDialog send_dialog(filepath.filename()); -// if (send_dialog.ShowModal() != wxID_OK) { return false; } - -// const bool print = send_dialog.start_print(); -// const auto upload_filepath = send_dialog.filename(); -// const auto upload_filename = upload_filepath.filename(); -// const auto upload_parent_path = upload_filepath.parent_path(); - -// wxProgressDialog progress_dialog( -// _(L("Duet upload")), -// _(L("Sending G-code file to Duet...")), -// PROGRESS_RANGE, nullptr, wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_CAN_ABORT); -// progress_dialog.Pulse(); - -// wxString connect_msg; -// if (!connect(connect_msg)) { -// auto errormsg = wxString::Format("%s: %s", errortitle, connect_msg); -// GUI::show_error(&progress_dialog, std::move(errormsg)); -// return false; -// } - -// bool res = true; - -// auto upload_cmd = get_upload_url(upload_filepath.string()); -// BOOST_LOG_TRIVIAL(info) << boost::format("Duet: Uploading file %1%, filename: %2%, path: %3%, print: %4%, command: %5%") -// % filepath.string() -// % upload_filename.string() -// % upload_parent_path.string() -// % print -// % upload_cmd; - -// auto http = Http::post(std::move(upload_cmd)); -// http.set_post_body(filename) -// .on_complete([&](std::string body, unsigned status) { -// BOOST_LOG_TRIVIAL(debug) << boost::format("Duet: File uploaded: HTTP %1%: %2%") % status % body; -// progress_dialog.Update(PROGRESS_RANGE); - -// int err_code = get_err_code_from_body(body); -// if (err_code != 0) { -// auto msg = format_error(body, L("Unknown error occured"), 0); -// GUI::show_error(&progress_dialog, std::move(msg)); -// res = false; -// } else if (print) { -// wxString errormsg; -// res = start_print(errormsg, upload_filepath.string()); -// if (!res) { -// GUI::show_error(&progress_dialog, std::move(errormsg)); -// } -// } -// }) -// .on_error([&](std::string body, std::string error, unsigned status) { -// BOOST_LOG_TRIVIAL(error) << boost::format("Duet: Error uploading file: %1%, HTTP %2%, body: `%3%`") % error % status % body; -// auto errormsg = wxString::Format("%s: %s", errortitle, format_error(body, error, status)); -// GUI::show_error(&progress_dialog, std::move(errormsg)); -// res = false; -// }) -// .on_progress([&](Http::Progress progress, bool &cancel) { -// if (cancel) { -// // Upload was canceled -// res = false; -// } else if (progress.ultotal > 0) { -// int value = PROGRESS_RANGE * progress.ulnow / progress.ultotal; -// cancel = !progress_dialog.Update(std::min(value, PROGRESS_RANGE - 1)); // Cap the value to prevent premature dialog closing -// } else { -// cancel = !progress_dialog.Pulse(); -// } -// }) -// .perform_sync(); - -// disconnect(); - -// return res; -// } - bool Duet::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn) const { - // XXX: TODO - throw "unimplemented"; + wxString connect_msg; + if (!connect(connect_msg)) { + error_fn(std::move(connect_msg)); + return false; + } + + bool res = true; + + auto upload_cmd = get_upload_url(upload_data.upload_path.string()); + BOOST_LOG_TRIVIAL(info) << boost::format("Duet: Uploading file %1%, filepath: %2%, print: %3%, command: %4%") + % upload_data.source_path + % upload_data.upload_path + % upload_data.start_print + % upload_cmd; + + auto http = Http::post(std::move(upload_cmd)); + http.set_post_body(upload_data.source_path) + .on_complete([&](std::string body, unsigned status) { + BOOST_LOG_TRIVIAL(debug) << boost::format("Duet: File uploaded: HTTP %1%: %2%") % status % body; + }) + .on_error([&](std::string body, std::string error, unsigned status) { + BOOST_LOG_TRIVIAL(error) << boost::format("Duet: Error uploading file: %1%, HTTP %2%, body: `%3%`") % error % status % body; + error_fn(format_error(body, error, status)); + res = false; + }) + .on_progress([&](Http::Progress progress, bool &cancel) { + prorgess_fn(std::move(progress), cancel); + if (cancel) { + // Upload was canceled + BOOST_LOG_TRIVIAL(info) << "Duet: Upload canceled"; + res = false; + } + }) + .perform_sync(); + + disconnect(); + + return res; } bool Duet::has_auto_discovery() const @@ -241,20 +196,10 @@ std::string Duet::timestamp_str() const return std::string(buffer); } -wxString Duet::format_error(const std::string &body, const std::string &error, unsigned status) -{ - if (status != 0) { - auto wxbody = wxString::FromUTF8(body.data()); - return wxString::Format("HTTP %u: %s", status, wxbody); - } else { - return wxString::FromUTF8(error.data()); - } -} - bool Duet::start_print(wxString &msg, const std::string &filename) const { bool res = false; - + auto url = (boost::format("%1%rr_gcode?gcode=M32%%20\"%2%\"") % get_base_url() % Http::url_encode(filename)).str(); diff --git a/src/slic3r/Utils/Duet.hpp b/src/slic3r/Utils/Duet.hpp index e053f91ef..e1c28d149 100644 --- a/src/slic3r/Utils/Duet.hpp +++ b/src/slic3r/Utils/Duet.hpp @@ -26,6 +26,7 @@ public: virtual bool has_auto_discovery() const; virtual bool can_test() const; virtual std::string get_host() const { return host; } + private: std::string host; std::string password; @@ -38,7 +39,6 @@ private: void disconnect() const; bool start_print(wxString &msg, const std::string &filename) const; int get_err_code_from_body(const std::string &body) const; - static wxString format_error(const std::string &body, const std::string &error, unsigned status); }; diff --git a/src/slic3r/Utils/OctoPrint.cpp b/src/slic3r/Utils/OctoPrint.cpp index af9d6e4f0..2e2e169b8 100644 --- a/src/slic3r/Utils/OctoPrint.cpp +++ b/src/slic3r/Utils/OctoPrint.cpp @@ -102,7 +102,7 @@ bool OctoPrint::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, Erro auto url = make_url("api/files/local"); BOOST_LOG_TRIVIAL(info) << boost::format("Octoprint: Uploading file %1% at %2%, filename: %3%, path: %4%, print: %5%") - % upload_data.source_path.string() + % upload_data.source_path % url % upload_filename.string() % upload_parent_path.string() @@ -118,7 +118,6 @@ bool OctoPrint::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, Erro }) .on_error([&](std::string body, std::string error, unsigned status) { BOOST_LOG_TRIVIAL(error) << boost::format("Octoprint: Error uploading file: %1%, HTTP %2%, body: `%3%`") % error % status % body; - // error_fn(std::move(body), std::move(error), status); error_fn(format_error(body, error, status)); res = false; }) @@ -126,7 +125,7 @@ bool OctoPrint::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, Erro prorgess_fn(std::move(progress), cancel); if (cancel) { // Upload was canceled - BOOST_LOG_TRIVIAL(error) << "Octoprint: Upload canceled"; + BOOST_LOG_TRIVIAL(info) << "Octoprint: Upload canceled"; res = false; } }) @@ -172,16 +171,6 @@ std::string OctoPrint::make_url(const std::string &path) const } } -wxString OctoPrint::format_error(const std::string &body, const std::string &error, unsigned status) -{ - if (status != 0) { - auto wxbody = wxString::FromUTF8(body.data()); - return wxString::Format("HTTP %u: %s", status, wxbody); - } else { - return wxString::FromUTF8(error.data()); - } -} - // SLAHost diff --git a/src/slic3r/Utils/OctoPrint.hpp b/src/slic3r/Utils/OctoPrint.hpp index 1e739c99d..8da149f53 100644 --- a/src/slic3r/Utils/OctoPrint.hpp +++ b/src/slic3r/Utils/OctoPrint.hpp @@ -38,7 +38,6 @@ private: void set_auth(Http &http) const; std::string make_url(const std::string &path) const; - static wxString format_error(const std::string &body, const std::string &error, unsigned status); }; diff --git a/src/slic3r/Utils/PrintHost.cpp b/src/slic3r/Utils/PrintHost.cpp index 84d823d89..31fe909c4 100644 --- a/src/slic3r/Utils/PrintHost.cpp +++ b/src/slic3r/Utils/PrintHost.cpp @@ -38,6 +38,16 @@ PrintHost* PrintHost::get_print_host(DynamicPrintConfig *config) } } +wxString PrintHost::format_error(const std::string &body, const std::string &error, unsigned status) const +{ + if (status != 0) { + auto wxbody = wxString::FromUTF8(body.data()); + return wxString::Format("HTTP %u: %s", status, wxbody); + } else { + return wxString::FromUTF8(error.data()); + } +} + struct PrintHostJobQueue::priv { diff --git a/src/slic3r/Utils/PrintHost.hpp b/src/slic3r/Utils/PrintHost.hpp index 39b93f5fb..d740ea99e 100644 --- a/src/slic3r/Utils/PrintHost.hpp +++ b/src/slic3r/Utils/PrintHost.hpp @@ -41,6 +41,9 @@ public: virtual std::string get_host() const = 0; static PrintHost* get_print_host(DynamicPrintConfig *config); + +protected: + virtual wxString format_error(const std::string &body, const std::string &error, unsigned status) const; }; From 42fada4576abc1c7d4a61106e499771df5b4168f Mon Sep 17 00:00:00 2001 From: bubnikv Date: Thu, 20 Dec 2018 17:44:24 +0100 Subject: [PATCH 22/26] Updated SLA profiles. Fixed the update downloader to ignore downloaded preset index if it is older than the currently active one. --- resources/profiles/PrusaResearch.idx | 15 +++ resources/profiles/PrusaResearch.ini | 158 +++++++++++++++++++++++---- src/slic3r/Utils/Http.cpp | 2 + src/slic3r/Utils/PresetUpdater.cpp | 37 +++++-- 4 files changed, 179 insertions(+), 33 deletions(-) diff --git a/resources/profiles/PrusaResearch.idx b/resources/profiles/PrusaResearch.idx index e440b35df..49d8ac1a5 100644 --- a/resources/profiles/PrusaResearch.idx +++ b/resources/profiles/PrusaResearch.idx @@ -1,6 +1,21 @@ min_slic3r_version = 1.42.0-alpha +0.4.0-alpha3 Update of SLA profiles 0.4.0-alpha2 First SLA profiles +min_slic3r_version = 1.41.1 +0.3.3 Prusament PETG released +0.3.2 New MK2.5 and MK3 FW versions +0.3.1 New MK2.5 and MK3 FW versions +0.3.0 New MK2.5 and MK3 FW version min_slic3r_version = 1.41.0-alpha +0.2.9 New MK2.5 and MK3 FW versions +0.2.8 New MK2.5 and MK3 FW version +min_slic3r_version = 1.41.1 +0.2.7 New MK2.5 and MK3 FW version +0.2.6 Added MMU2 MK2.5 settings +min_slic3r_version = 1.41.0-alpha +0.2.5 Prusament is out - added prusament settings +0.2.4 Added soluble support profiles for MMU2 +0.2.3 Added materials for MMU2 single mode, edited MK3 xy stealth feedrate limit 0.2.2 Edited MMU2 Single mode purge line 0.2.1 Added PET and BVOH settings for MMU2 0.2.0-beta5 Fixed MMU1 ramming parameters diff --git a/resources/profiles/PrusaResearch.ini b/resources/profiles/PrusaResearch.ini index d5425dc12..7bdcb6906 100644 --- a/resources/profiles/PrusaResearch.ini +++ b/resources/profiles/PrusaResearch.ini @@ -5,7 +5,7 @@ name = Prusa Research # Configuration version of this file. Config file will only be installed, if the config_version differs. # This means, the server may force the Slic3r configuration to be downgraded. -config_version = 0.4.0-alpha2 +config_version = 0.4.0-alpha3 # Where to get the updates from? config_update_url = https://raw.githubusercontent.com/prusa3d/Slic3r-settings/master/live/PrusaResearch/ @@ -41,7 +41,7 @@ variants = 0.4 [printer_model:SL1] name = Original Prusa SL1 -variants = default; dummy +variants = default # All presets starting with asterisk, for example *common*, are intermediate and they will # not make it into the user interface. @@ -1137,19 +1137,132 @@ min_fan_speed = 100 start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode" temperature = 220 -[sla_material:*common*] +[sla_print:*common*] +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_SL1.*/ layer_height = 0.05 -initial_layer_height = 0.3 +output_filename_format = [input_filename_base].dwz +pad_edge_radius = 0.5 +pad_enable = 1 +pad_max_merge_distance = 50 +pad_wall_height = 3 +pad_wall_thickness = 1 +support_base_diameter = 3 +support_base_height = 0.5 +support_critical_angle = 45 +support_density_at_45 = 250 +support_density_at_horizontal = 500 +support_head_front_diameter = 0.4 +support_head_penetration = 0.4 +support_head_width = 3 +support_max_bridge_length = 10 +support_minimal_z = 0 +support_object_elevation = 5 +support_pillar_diameter = 1 +support_pillar_widening_factor = 0 +supports_enable = 1 + +[sla_print:0.025 UltraDetail] +inherits = *common* +layer_height = 0.025 +support_head_width = 2 + +[sla_print:0.035 Detail] +inherits = *common* +layer_height = 0.035 + +[sla_print:0.05 Normal] +inherits = *common* +layer_height = 0.05 + +[sla_print:0.1 Fast] +inherits = *common* +layer_height = 0.1 + +########### Materials 0.025 + +[sla_material:*common 0.05*] +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_SL1.*/ +compatible_prints_condition = layer_height == 0.05 +exposure_time = 12 +initial_exposure_time = 45 +initial_layer_height = 0.5 +material_correction_curing = 1,1,1 +material_correction_printing = 1,1,1 +material_notes = + +[sla_material:*common 0.025*] +inherits = *common 0.05* +compatible_prints_condition = layer_height == 0.025 exposure_time = 10 -initial_exposure_time = 15 -material_correction_printing = 1, 1, 1 -material_correction_curing = 1, 1, 1 +initial_exposure_time = 35 -[sla_material:Material 1] -inherits = *common* +[sla_material:*common 0.035*] +inherits = *common 0.05* +compatible_prints_condition = layer_height == 0.035 +exposure_time = 13 +initial_exposure_time = 40 -[sla_material:Material 2] -inherits = *common* +[sla_material:*common 0.1*] +inherits = *common 0.05* +compatible_prints_condition = layer_height == 0.1 +exposure_time = 20 +initial_exposure_time = 90 + +########### Materials 0.025 + +[sla_material:Jamg He Transparent Clear 0.025] +inherits = *common 0.025* + +[sla_material:Jamg He Transparent Green 0.025] +inherits = *common 0.025* + +[sla_material:Jamg He Transparent Orange 0.025] +inherits = *common 0.025* + +[sla_material:Jamg He Transparent Red 0.025] +inherits = *common 0.025* + +########### Materials 0.05 + +[sla_material:Jamg He Transparent Clear 0.05] +inherits = *common 0.05* + +[sla_material:Jamg He Transparent Green 0.05] +inherits = *common 0.05* + +[sla_material:Jamg He Transparent Orange 0.05] +inherits = *common 0.05* + +[sla_material:Jamg He Transparent Red 0.05] +inherits = *common 0.05* + +########### Materials 0.035 + +[sla_material:Jamg He Transparent Clear 0.035] +inherits = *common 0.035* + +[sla_material:Jamg He Transparent Green 0.035] +inherits = *common 0.035* + +[sla_material:Jamg He Transparent Orange 0.035] +inherits = *common 0.035* + +[sla_material:Jamg He Transparent Red 0.035] +inherits = *common 0.035* + +########### Materials 0.1 + +[sla_material:Jamg He Transparent Clear 0.1] +inherits = *common 0.1* + +[sla_material:Jamg He Transparent Green 0.1] +inherits = *common 0.1* + +[sla_material:Jamg He Transparent Orange 0.1] +inherits = *common 0.1* + +[sla_material:Jamg He Transparent Red 0.1] +inherits = *common 0.1* [printer:*common*] printer_technology = FFF @@ -1467,21 +1580,20 @@ end_gcode = {if has_wipe_tower}\nG1 E-15.0000 F3000\n{else}\nG1 X0 Y210 F7200\nG printer_technology = SLA printer_model = SL1 printer_variant = default -default_sla_material_profile = Material 1 -bed_shape = 0x0,150x0,150x100,0x100 -max_print_height = 100 -display_width = 150 -display_height = 100 -display_pixels_x = 2000 -display_pixels_y = 1000 +default_sla_material_profile = Jamg He Transparent Green 0.05 +default_sla_print_profile = 0.05 Normal +bed_shape = 0.98x1.02,119.98x1.02,119.98x68.02,0.98x68.02 +display_height = 68.04 +display_orientation = portrait +display_pixels_x = 2560 +display_pixels_y = 1440 +display_width = 120.96 +max_print_height = 150 printer_correction = 1,1,1 - -[printer:Original Prusa SL1 dummy] -inherits = Original Prusa SL1 -printer_variant = dummy -default_sla_material_profile = Material 2 +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_SL1\n # The obsolete presets will be removed when upgrading from the legacy configuration structure (up to Slic3r 1.39.2) to 1.40.0 and newer. [obsolete_presets] print="0.05mm DETAIL 0.25 nozzle";"0.05mm DETAIL MK3";"0.05mm DETAIL";"0.20mm NORMAL MK3";"0.35mm FAST MK3";"print:0.15mm OPTIMAL MK3 MMU2";"print:0.20mm FAST MK3 MMU2" filament="ColorFabb Brass Bronze 1.75mm";"ColorFabb HT 1.75mm";"ColorFabb nGen 1.75mm";"ColorFabb Woodfil 1.75mm";"ColorFabb XT 1.75mm";"ColorFabb XT-CF20 1.75mm";"E3D PC-ABS 1.75mm";"Fillamentum ABS 1.75mm";"Fillamentum ASA 1.75mm";"Generic ABS 1.75mm";"Generic PET 1.75mm";"Generic PLA 1.75mm";"Prusa ABS 1.75mm";"Prusa HIPS 1.75mm";"Prusa PET 1.75mm";"Prusa PLA 1.75mm";"Taulman Bridge 1.75mm";"Taulman T-Glase 1.75mm" +printer="Original Prusa SL1 dummy" diff --git a/src/slic3r/Utils/Http.cpp b/src/slic3r/Utils/Http.cpp index 30478cb01..471cd8bc4 100644 --- a/src/slic3r/Utils/Http.cpp +++ b/src/slic3r/Utils/Http.cpp @@ -235,7 +235,9 @@ void Http::priv::http_perform() #if LIBCURL_VERSION_MAJOR >= 7 && LIBCURL_VERSION_MINOR >= 32 ::curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, xfercb); ::curl_easy_setopt(curl, CURLOPT_XFERINFODATA, static_cast(this)); +#ifndef _WIN32 (void)xfercb_legacy; // prevent unused function warning +#endif #else ::curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, xfercb); ::curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, static_cast(this)); diff --git a/src/slic3r/Utils/PresetUpdater.cpp b/src/slic3r/Utils/PresetUpdater.cpp index 924cf382d..be2a17d66 100644 --- a/src/slic3r/Utils/PresetUpdater.cpp +++ b/src/slic3r/Utils/PresetUpdater.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -112,7 +113,7 @@ struct PresetUpdater::priv bool get_file(const std::string &url, const fs::path &target_path) const; void prune_tmps() const; void sync_version() const; - void sync_config(const std::set vendors) const; + void sync_config(const std::set vendors); void check_install_indices() const; Updates get_config_updates() const; @@ -130,7 +131,7 @@ PresetUpdater::priv::priv() : { set_download_prefs(GUI::wxGetApp().app_config); check_install_indices(); - index_db = std::move(Index::load_db()); + index_db = Index::load_db(); } // Pull relevant preferences from AppConfig @@ -220,14 +221,14 @@ void PresetUpdater::priv::sync_version() const // Download vendor indices. Also download new bundles if an index indicates there's a new one available. // Both are saved in cache. -void PresetUpdater::priv::sync_config(const std::set vendors) const +void PresetUpdater::priv::sync_config(const std::set vendors) { BOOST_LOG_TRIVIAL(info) << "Syncing configuration cache"; if (!enabled_config_update) { return; } // Donwload vendor preset bundles - for (const auto &index : index_db) { + for (auto &index : index_db) { if (cancel) { return; } const auto vendor_it = vendors.find(VendorProfile(index.vendor())); @@ -245,17 +246,33 @@ void PresetUpdater::priv::sync_config(const std::set vendors) con // Download a fresh index BOOST_LOG_TRIVIAL(info) << "Downloading index for vendor: " << vendor.name; const auto idx_url = vendor.config_update_url + "/" + INDEX_FILENAME; - const auto idx_path = cache_path / (vendor.id + ".idx"); - if (! get_file(idx_url, idx_path)) { continue; } + const std::string idx_path = (cache_path / (vendor.id + ".idx")).string(); + const std::string idx_path_temp = idx_path + "-update"; + if (!get_file(idx_url, idx_path_temp)) { continue; } if (cancel) { return; } // Load the fresh index up - Index new_index; - new_index.load(idx_path); + { + Index new_index; + try { + new_index.load(idx_path_temp); + } catch (const std::exception &err) { + BOOST_LOG_TRIVIAL(error) << boost::format("Failed loading a downloaded index %1% for vendor %2%: invalid index?") % idx_path_temp % vendor.name; + continue; + } + if (new_index.version() < index.version()) { + BOOST_LOG_TRIVIAL(error) << boost::format("The downloaded index %1% for vendor %2% is older than the active one. Ignoring the downloaded index.") % idx_path_temp % vendor.name; + continue; + } + Slic3r::rename_file(idx_path_temp, idx_path); + index = std::move(new_index); + if (cancel) + return; + } // See if a there's a new version to download - const auto recommended_it = new_index.recommended(); - if (recommended_it == new_index.end()) { + const auto recommended_it = index.recommended(); + if (recommended_it == index.end()) { BOOST_LOG_TRIVIAL(error) << boost::format("No recommended version for vendor: %1%, invalid index?") % vendor.name; continue; } From f56bb7d085e422ac6d1e5a6ae36370c3d6f97dc0 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Thu, 20 Dec 2018 18:23:11 +0100 Subject: [PATCH 23/26] Fixed file wild cards when exporting a G-code or SLA output file. --- src/slic3r/GUI/GUI_App.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index bbba1d93b..97e78798f 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -43,7 +43,7 @@ namespace GUI { wxString file_wildcards(FileType file_type, const std::string &custom_extension) { - static const wxString defaults[FT_SIZE] = { + static const std::string defaults[FT_SIZE] = { /* FT_STL */ "STL files (*.stl)|*.stl;*.STL", /* FT_OBJ */ "OBJ files (*.obj)|*.obj;*.OBJ", /* FT_AMF */ "AMF files (*.amf)|*.zip.amf;*.amf;*.AMF;*.xml;*.XML", @@ -57,13 +57,17 @@ wxString file_wildcards(FileType file_type, const std::string &custom_extension) /* FT_PNGZIP */"Zipped PNG files (*.zip)|*.zip;*.ZIP", // This is lame, but that's what we use for SLA }; - wxString out = defaults[file_type]; + std::string out = defaults[file_type]; if (! custom_extension.empty()) { - // Append the custom extension to the wildcards, so that the file dialog would not add the default extension to it. - out += ";*"; - out += from_u8(custom_extension); + // Find the custom extension in the template. + if (out.find(std::string("*") + custom_extension + ",") == std::string::npos && out.find(std::string("*") + custom_extension + ")") == std::string::npos) { + // The custom extension was not found in the template. + // Append the custom extension to the wildcards, so that the file dialog would not add the default extension to it. + boost::replace_first(out, ")|", std::string(", *") + custom_extension + ")|"); + out += std::string(";*") + custom_extension; + } } - return out; + return wxString::FromUTF8(out.c_str()); } static std::string libslic3r_translate_callback(const char *s) { return wxGetTranslation(wxString(s, wxConvUTF8)).utf8_str().data(); } From 56f473c2dca318f73a7913f04b74e3f55c30ba88 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Thu, 20 Dec 2018 18:48:49 +0100 Subject: [PATCH 24/26] Prinhost: Add a note explaining OS certificate store --- src/slic3r/GUI/Tab.cpp | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 5a212d4ee..a4796778a 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1601,8 +1601,9 @@ void TabPrinter::build_printhost(ConfigOptionsGroup *optgroup) optgroup->append_line(host_line); optgroup->append_single_option_line("printhost_apikey"); - if (Http::ca_file_supported()) { + const auto ca_file_hint = _(L("HTTPS CA file is optional. It is only needed if you use HTTPS with a self-signed certificate.")); + if (Http::ca_file_supported()) { Line cafile_line = optgroup->create_single_option_line("printhost_cafile"); auto printhost_cafile_browse = [this, optgroup] (wxWindow* parent) { @@ -1625,19 +1626,31 @@ void TabPrinter::build_printhost(ConfigOptionsGroup *optgroup) cafile_line.append_widget(printhost_cafile_browse); optgroup->append_line(cafile_line); - auto printhost_cafile_hint = [this, optgroup] (wxWindow* parent) { - auto txt = new wxStaticText(parent, wxID_ANY, - _(L("HTTPS CA file is optional. It is only needed if you use HTTPS with a self-signed certificate."))); + Line cafile_hint { "", "" }; + cafile_hint.full_width = 1; + cafile_hint.widget = [this, ca_file_hint](wxWindow* parent) { + auto txt = new wxStaticText(parent, wxID_ANY, ca_file_hint); + auto sizer = new wxBoxSizer(wxHORIZONTAL); + sizer->Add(txt); + return sizer; + }; + optgroup->append_line(cafile_hint); + } else { + Line line { "", "" }; + line.full_width = 1; + + line.widget = [this, ca_file_hint] (wxWindow* parent) { + auto txt = new wxStaticText(parent, wxID_ANY, wxString::Format("%s\n\n\t%s", + _(L("HTTPS CA File:\n\ +\tOn this system, Slic3r uses HTTPS certificates from the system Certificate Store or Keychain.\n\ +\tTo use a custom CA file, please import your CA file into Certificate Store / Keychain.")), + ca_file_hint)); auto sizer = new wxBoxSizer(wxHORIZONTAL); sizer->Add(txt); return sizer; }; - Line cafile_hint { "", "" }; - cafile_hint.full_width = 1; - cafile_hint.widget = std::move(printhost_cafile_hint); - optgroup->append_line(cafile_hint); - + optgroup->append_line(line); } } From f799f2eb48fb43186c0d59e331225b13db309d30 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Thu, 20 Dec 2018 20:12:26 +0100 Subject: [PATCH 25/26] Delayed update of ObjectManipulation panel from the Canvas3D: Store the changes into temps and apply it to the wxWidgets on idle. --- src/slic3r/GUI/GUI_App.cpp | 3 + src/slic3r/GUI/GUI_ObjectManipulation.cpp | 209 +++++++++------------- src/slic3r/GUI/GUI_ObjectManipulation.hpp | 28 +-- 3 files changed, 106 insertions(+), 134 deletions(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 97e78798f..74ea52c64 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -181,6 +181,9 @@ bool GUI_App::OnInit() if (app_config->dirty()) app_config->save(); + + if (this->plater() != nullptr) + this->obj_manipul()->update_if_dirty(); }); // On OS X the UI tends to freeze in weird ways if modal dialogs(config wizard, update notifications, ...) diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index 8cc2362e8..7955326f5 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -47,6 +47,8 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : m_og->m_fill_empty_value = [this](const std::string& opt_key) { + this->update_if_dirty(); + std::string param; std::copy(opt_key.begin(), opt_key.end() - 2, std::back_inserter(param)); @@ -83,6 +85,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : m_og->m_set_focus = [this](const std::string& opt_key) { + this->update_if_dirty(); wxGetApp().plater()->canvas3D()->handle_sidebar_focus_event(opt_key, true); }; @@ -179,22 +182,19 @@ bool ObjectManipulation::IsShown() void ObjectManipulation::UpdateAndShow(const bool show) { - if (show) + if (show) { update_settings_value(wxGetApp().plater()->canvas3D()->get_selection()); + update_if_dirty(); + } OG_Settings::UpdateAndShow(show); } -int ObjectManipulation::ol_selection() -{ - return wxGetApp().obj_list()->get_selected_obj_idx(); -} - void ObjectManipulation::update_settings_value(const GLCanvas3D::Selection& selection) { - wxString move_label = _(L("Position:")); - wxString rotate_label = _(L("Rotation:")); - wxString scale_label = _(L("Scale factors:")); + m_new_move_label_string = L("Position:"); + m_new_rotate_label_string = L("Rotation:"); + m_new_scale_label_string = L("Scale factors:"); #if ENABLE_MODELVOLUME_TRANSFORM if (selection.is_single_full_instance()) #else @@ -205,10 +205,10 @@ void ObjectManipulation::update_settings_value(const GLCanvas3D::Selection& sele { // all volumes in the selection belongs to the same instance, any of them contains the needed data, so we take the first const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); - update_position_value(volume->get_offset()); - update_rotation_value(volume->get_rotation()); - update_scale_value(volume->get_scaling_factor()); - m_og->enable(); + m_new_position = volume->get_offset(); + m_new_rotation = volume->get_rotation(); + m_new_scale = volume->get_scaling_factor(); + m_new_enabled = true; } else reset_settings_value(); @@ -219,143 +219,104 @@ void ObjectManipulation::update_settings_value(const GLCanvas3D::Selection& sele // all volumes in the selection belongs to the same instance, any of them contains the needed data, so we take the first const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); #if ENABLE_MODELVOLUME_TRANSFORM - update_position_value(volume->get_instance_offset()); - update_rotation_value(volume->get_instance_rotation()); - update_scale_value(volume->get_instance_scaling_factor()); - update_size_value(volume->get_instance_transformation().get_matrix(true, true) * volume->bounding_box.size()); + m_new_position = volume->get_instance_offset(); + m_new_rotation = volume->get_instance_rotation(); + m_new_scale = volume->get_instance_scaling_factor(); + m_new_size = volume->get_instance_transformation().get_matrix(true, true) * volume->bounding_box.size(); #else - update_position_value(volume->get_offset()); - update_rotation_value(volume->get_rotation()); - update_scale_value(volume->get_scaling_factor()); + m_new_position = volume->get_offset(); + m_new_rotation = volume->get_rotation(); + m_new_scale = volume->get_scaling_factor(); #endif // ENABLE_MODELVOLUME_TRANSFORM - m_og->enable(); + m_new_enabled = true; } else if (selection.is_single_full_object()) { const BoundingBoxf3& box = selection.get_bounding_box(); - update_position_value(box.center()); - reset_rotation_value(); - reset_scale_value(); - update_size_value(box.size()); - rotate_label = _(L("Rotate:")); - scale_label = _(L("Scale:")); - m_og->enable(); + m_new_position = box.center(); + m_new_rotation = Vec3d::Zero(); + m_new_scale = Vec3d(1.0, 1.0, 1.0); + m_new_size = box.size(); + m_new_rotate_label_string = L("Rotate:"); + m_new_scale_label_string = L("Scale:"); + m_new_enabled = true; } else if (selection.is_single_modifier() || selection.is_single_volume()) { // the selection contains a single volume const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); #if ENABLE_MODELVOLUME_TRANSFORM - update_position_value(volume->get_volume_offset()); - update_rotation_value(volume->get_volume_rotation()); - update_scale_value(volume->get_volume_scaling_factor()); - update_size_value(volume->bounding_box.size()); + 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->bounding_box.size(); #else - update_position_value(volume->get_offset()); - update_rotation_value(volume->get_rotation()); - update_scale_value(volume->get_scaling_factor()); + m_new_position = volume->get_offset(); + m_new_rotation = volume->get_rotation(); + m_new_scale = volume->get_scaling_factor(); #endif // ENABLE_MODELVOLUME_TRANSFORM - m_og->enable(); + m_new_enabled = true; } else if (wxGetApp().obj_list()->multiple_selection()) { reset_settings_value(); - move_label = _(L("Translate:")); - rotate_label = _(L("Rotate:")); - scale_label = _(L("Scale:")); - update_size_value(selection.get_bounding_box().size()); - m_og->enable(); + m_new_move_label_string = L("Translate:"); + m_new_rotate_label_string = L("Rotate:"); + m_new_scale_label_string = L("Scale:"); + m_new_size = selection.get_bounding_box().size(); + m_new_enabled = true; } else reset_settings_value(); - m_move_Label->SetLabel(move_label); - m_rotate_Label->SetLabel(rotate_label); - m_scale_Label->SetLabel(scale_label); + m_dirty = true; +} + +void ObjectManipulation::update_if_dirty() +{ + if (! m_dirty) + return; + + m_move_Label->SetLabel(_(m_new_move_label_string)); + m_rotate_Label->SetLabel(_(m_new_rotate_label_string)); + m_scale_Label->SetLabel(_(m_new_scale_label_string)); + + m_og->set_value("position_x", double_to_string(m_new_position(0), 2)); + m_og->set_value("position_y", double_to_string(m_new_position(1), 2)); + m_og->set_value("position_z", double_to_string(m_new_position(2), 2)); + cache_position = m_new_position; + + auto scale = m_new_scale * 100.0; + m_og->set_value("scale_x", double_to_string(scale(0), 2)); + m_og->set_value("scale_y", double_to_string(scale(1), 2)); + m_og->set_value("scale_z", double_to_string(scale(2), 2)); + cache_scale = scale; + + m_og->set_value("size_x", double_to_string(m_new_size(0), 2)); + m_og->set_value("size_y", double_to_string(m_new_size(1), 2)); + m_og->set_value("size_z", double_to_string(m_new_size(2), 2)); + cache_size = m_new_size; + + m_og->set_value("rotation_x", double_to_string(round_nearest(Geometry::rad2deg(m_new_rotation(0)), 0), 2)); + m_og->set_value("rotation_y", double_to_string(round_nearest(Geometry::rad2deg(m_new_rotation(1)), 0), 2)); + m_og->set_value("rotation_z", double_to_string(round_nearest(Geometry::rad2deg(m_new_rotation(2)), 0), 2)); + cache_rotation = m_new_rotation; + + if (m_new_enabled) + m_og->enable(); + else + m_og->disable(); + + m_dirty = false; } void ObjectManipulation::reset_settings_value() { - reset_position_value(); - reset_rotation_value(); - reset_scale_value(); - m_og->disable(); -} - -wxString def_0 {"0"}; -wxString def_100 {"100"}; - -void ObjectManipulation::reset_position_value() -{ - m_og->set_value("position_x", def_0); - m_og->set_value("position_y", def_0); - m_og->set_value("position_z", def_0); - - cache_position = Vec3d::Zero(); -} - -void ObjectManipulation::reset_rotation_value() -{ - m_og->set_value("rotation_x", def_0); - m_og->set_value("rotation_y", def_0); - m_og->set_value("rotation_z", def_0); - - cache_rotation = Vec3d::Zero(); -} - -void ObjectManipulation::reset_scale_value() -{ - m_og->set_value("scale_x", def_100); - m_og->set_value("scale_y", def_100); - m_og->set_value("scale_z", def_100); - - cache_scale = Vec3d(100.0, 100.0, 100.0); -} - -void ObjectManipulation::reset_size_value() -{ - m_og->set_value("size_x", def_0); - m_og->set_value("size_y", def_0); - m_og->set_value("size_z", def_0); - - cache_size = Vec3d::Zero(); -} - -void ObjectManipulation::update_position_value(const Vec3d& position) -{ - m_og->set_value("position_x", double_to_string(position(0), 2)); - m_og->set_value("position_y", double_to_string(position(1), 2)); - m_og->set_value("position_z", double_to_string(position(2), 2)); - - cache_position = position; -} - -void ObjectManipulation::update_scale_value(const Vec3d& scaling_factor) -{ - auto scale = scaling_factor * 100.0; - m_og->set_value("scale_x", double_to_string(scale(0), 2)); - m_og->set_value("scale_y", double_to_string(scale(1), 2)); - m_og->set_value("scale_z", double_to_string(scale(2), 2)); - - cache_scale = scale; -} - -void ObjectManipulation::update_size_value(const Vec3d& size) -{ - m_og->set_value("size_x", double_to_string(size(0), 2)); - m_og->set_value("size_y", double_to_string(size(1), 2)); - m_og->set_value("size_z", double_to_string(size(2), 2)); - - cache_size = size; -} - -void ObjectManipulation::update_rotation_value(const Vec3d& rotation) -{ - m_og->set_value("rotation_x", double_to_string(round_nearest(Geometry::rad2deg(rotation(0)), 0), 2)); - m_og->set_value("rotation_y", double_to_string(round_nearest(Geometry::rad2deg(rotation(1)), 0), 2)); - m_og->set_value("rotation_z", double_to_string(round_nearest(Geometry::rad2deg(rotation(2)), 0), 2)); - - cache_rotation = rotation; + m_new_position = Vec3d::Zero(); + m_new_rotation = Vec3d::Zero(); + m_new_scale = Vec3d(1.0, 1.0, 1.0); + m_new_size = Vec3d::Zero(); + m_new_enabled = false; } void ObjectManipulation::change_position_value(const Vec3d& position) diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.hpp b/src/slic3r/GUI/GUI_ObjectManipulation.hpp index 0ada37b96..cbac94058 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.hpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.hpp @@ -23,6 +23,19 @@ class ObjectManipulation : public OG_Settings wxStaticText* m_scale_Label = nullptr; wxStaticText* m_rotate_Label = nullptr; + + // Needs to be updated from OnIdle? + bool m_dirty = false; + // Cached labels for the delayed update, not localized! + std::string m_new_move_label_string; + std::string m_new_rotate_label_string; + std::string m_new_scale_label_string; + Vec3d m_new_position; + Vec3d m_new_rotation; + Vec3d m_new_scale; + Vec3d m_new_size; + bool m_new_enabled; + public: ObjectManipulation(wxWindow* parent); ~ObjectManipulation() {} @@ -31,19 +44,14 @@ public: bool IsShown() override; void UpdateAndShow(const bool show) override; - int ol_selection(); + void update_settings_value(const GLCanvas3D::Selection& selection); - void update_settings_value(const GLCanvas3D::Selection& selection); + // Called from the App to update the UI if dirty. + void update_if_dirty(); + +private: void reset_settings_value(); - void reset_position_value(); - void reset_rotation_value(); - void reset_scale_value(); - void reset_size_value(); - // update position values displacements or "gizmos" - void update_position_value(const Vec3d& position); - // update scale values after scale unit changing or "gizmos" - void update_scale_value(const Vec3d& scaling_factor); // update size values after scale unit changing or "gizmos" void update_size_value(const Vec3d& size); // update rotation value after "gizmos" From cb0488df122938803917567df424cc844dcc1e33 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Thu, 20 Dec 2018 22:30:42 +0100 Subject: [PATCH 26/26] Tab key to switch between the 3D view / path preview. --- src/slic3r/GUI/Plater.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index db19180b4..11894adf8 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1117,6 +1117,9 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) #if ENABLE_REMOVE_TABS_FROM_PLATER view3D = new View3D(q, &model, config, &background_process); preview = new Preview(q, config, &background_process, &gcode_preview_data, [this](){ schedule_background_process(); }); + // Let the Tab key switch between the 3D view and the layer preview. + view3D->Bind(wxEVT_NAVIGATION_KEY, [this](wxNavigationKeyEvent &evt) { if (evt.IsFromTab()) this->q->select_view_3D("Preview"); }); + preview->Bind(wxEVT_NAVIGATION_KEY, [this](wxNavigationKeyEvent &evt) { if (evt.IsFromTab()) this->q->select_view_3D("3D"); }); panels.push_back(view3D); panels.push_back(preview);