From 3b373a55e6612436907885b50dd4bbb46998ac37 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Thu, 8 Nov 2018 16:01:21 +0100 Subject: [PATCH] slaprint with dummy backround processing in plater. --- src/slic3r/GUI/GLGizmo.cpp | 27 +---------------- src/slic3r/GUI/GLGizmo.hpp | 10 ++++--- src/slic3r/GUI/Plater.cpp | 53 +++++++++++++++++++++++++++++++-- src/slic3r/GUI/Plater.hpp | 2 ++ src/slic3r/GUI/SLAPrint.cpp | 57 ++++++++++++++++++++++++++++++----- src/slic3r/GUI/SLAPrint.hpp | 59 +++++++++++++++++++++---------------- 6 files changed, 143 insertions(+), 65 deletions(-) diff --git a/src/slic3r/GUI/GLGizmo.cpp b/src/slic3r/GUI/GLGizmo.cpp index 67c504411..56189da9d 100644 --- a/src/slic3r/GUI/GLGizmo.cpp +++ b/src/slic3r/GUI/GLGizmo.cpp @@ -137,6 +137,7 @@ GLGizmoBase::GLGizmoBase(GLCanvas3D& parent) : m_parent(parent) , m_group_id(-1) , m_state(Off) + , m_prev_state(Off) , m_hover_id(-1) , m_dragging(false) { @@ -1621,32 +1622,6 @@ void GLGizmoSlaSupports::update_mesh() } } -void GLGizmoSlaSupports::on_deactivate() { - if(!m_model_object) return; - -// sla::Controller supportctl; -// std::cout << "Generating supports:" << std::endl; - -// // TODO: somehow get the global status indicator -// supportctl.statuscb = [] (unsigned st, const std::string& msg) { -// std::cout << st << "% " << msg << std::endl; -// }; - -// TriangleMesh&& m = m_model_object->raw_mesh(); -// m.transform(m_model_object_matrix); -// auto emesh = sla::to_eigenmesh(m); - -// sla::SupportConfig cfg; -// sla::PointSet input = sla::support_points(*m_model_object, 0 /*instance*/); - -// sla::SLASupportTree stree(input, emesh, cfg, supportctl); - -// TriangleMesh output; -// stree.merged_mesh(output); - -// _3DScene::reload_scene(m_parent.get_wxglcanvas(), false); -} - Vec3f GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos) { // if the gizmo doesn't have the V, F structures for igl, calculate them first: diff --git a/src/slic3r/GUI/GLGizmo.hpp b/src/slic3r/GUI/GLGizmo.hpp index 727ef0868..498990057 100644 --- a/src/slic3r/GUI/GLGizmo.hpp +++ b/src/slic3r/GUI/GLGizmo.hpp @@ -56,7 +56,7 @@ protected: GLCanvas3D& m_parent; int m_group_id; - EState m_state; + EState m_state, m_prev_state; // textures are assumed to be square and all with the same size in pixels, no internal check is done GLTexture m_textures[Num_States]; int m_hover_id; @@ -79,12 +79,14 @@ public: EState get_state() const { return m_state; } void set_state(EState state) { - // FIXME: this is my workaround to react on the disabling event (Tamas) - bool call_deactivate = ((m_state == On || m_state == Hover) && - state == Off); + bool call_deactivate = + m_prev_state == On && state == Off && m_state == Hover; + + if(state == On || state == Off) m_prev_state = state; m_state = state; on_set_state(); + // FIXME: this is my workaround to react on the disabling event (Tamas) if(call_deactivate) { on_deactivate(); } diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 8cc120e1e..f215c7224 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -842,6 +842,42 @@ bool PlaterDropTarget::OnDropFiles(wxCoord x, wxCoord y, const wxArrayString &fi // Plater / private + +// For the SLAPrint: No multi-threading here +class DummyBackgroundProcess: public BackgroundProcess { +public: + + /// schedule a task on the background + virtual void schedule(std::function fn) override { + /*std::asynch*/ fn(); + } + + /// Report status change, used inside the worker thread + virtual void status(unsigned st, const std::string& msg) { + // TODO would use the statusbar gauge + std::cout << "Processing " << st << "% " << msg << std::endl; + } + + /// Check whether the calculation was canceled from the UI. Called by the + /// worker thread + virtual bool is_canceled() { + // this would be connected to the statusbar's cancel button + // and return true if that was pushed during the processing + return false; + } + + /// Determine the state of the background process. If something is running + /// returns true. If no job is running, returns false. + virtual bool is_running() { return false; } + + virtual void input_changed() override { + /*lock();*/ + BackgroundProcess::input_changed(); + /*unlock();*/ + } +}; + + struct Plater::priv { // PIMPL back pointer ("Q-Pointer") @@ -854,16 +890,19 @@ struct Plater::priv // Data Slic3r::DynamicPrintConfig *config; Slic3r::Print print; - Slic3r::SLAPrint slaprint; Slic3r::Model model; Slic3r::GCodePreviewData gcode_preview_data; + // Will live only in this branch: + Slic3r::SLAPrint slaprint; + // GUI elements wxNotebook *notebook; Sidebar *sidebar; wxGLCanvas *canvas3D; // TODO: Use GLCanvas3D when we can Preview *preview; BackgroundSlicingProcess background_process; + wxTimer background_process_timer; static const std::regex pattern_bundle; @@ -943,7 +982,6 @@ private: const std::regex Plater::priv::pattern_bundle(".*[.](amf|amf[.]xml|zip[.]amf|3mf|prusa)", std::regex::icase); const std::regex Plater::priv::pattern_3mf(".*3mf", std::regex::icase); const std::regex Plater::priv::pattern_zip_amf(".*[.]zip[.]amf", std::regex::icase); - Plater::priv::priv(Plater *q, MainFrame *main_frame) : q(q), main_frame(main_frame), @@ -959,6 +997,8 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) : canvas3D(GLCanvas3DManager::create_wxglcanvas(notebook)), slaprint(&model) { + slaprint.set_scheduler(std::make_shared()); + // TODO: background_process.set_print(&slaprint); background_process.set_print(&print); background_process.set_gcode_preview_data(&gcode_preview_data); background_process.set_sliced_event(EVT_SLICING_COMPLETED); @@ -1526,6 +1566,10 @@ void Plater::priv::async_apply_config() // Apply new config to the possibly running background task. Print::ApplyStatus invalidated = this->background_process.apply(this->q->model(), std::move(config)); + + // Thread safe invalidation of the SLAPrint data cache + this->slaprint.synch(); + // Just redraw the 3D canvas without reloading the scene to consume the update of the layer height profile. if (Slic3r::_3DScene::is_layers_editing_enabled(this->canvas3D)) this->canvas3D->Refresh(); @@ -1936,6 +1980,11 @@ Sidebar& Plater::sidebar() { return *p->sidebar; } Model& Plater::model() { return p->model; } Print& Plater::print() { return p->print; } +SLAPrint &Plater::sla_print() +{ + return p->slaprint; +} + void Plater::add() { wxArrayString input_files; diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 30c14621d..1fb22cf31 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -18,6 +18,7 @@ namespace Slic3r { class Model; class Print; +class SLAPrint; namespace GUI { @@ -104,6 +105,7 @@ public: Sidebar& sidebar(); Model& model(); Print& print(); + SLAPrint& sla_print(); void add(); diff --git a/src/slic3r/GUI/SLAPrint.cpp b/src/slic3r/GUI/SLAPrint.cpp index c6a7a8940..f50c53618 100644 --- a/src/slic3r/GUI/SLAPrint.cpp +++ b/src/slic3r/GUI/SLAPrint.cpp @@ -1,5 +1,9 @@ #include "SLAPrint.hpp" #include "GUI.hpp" +#include "GLGizmo.hpp" +#include "Plater.hpp" + +#include "GUI_App.hpp" namespace Slic3r { @@ -16,20 +20,57 @@ const std::string SLAPrint::m_stage_labels[] = { L("SLA print preparation aborted") // ABORT, }; -void SLAPrint::synch() { - m_gcfg = m_config_reader(); - // TODO: check model objects and instances +void SLAPrint::_start() +{ } -bool SLAPrint::start(std::shared_ptr scheduler) { - if(!m_process || !m_process->is_running()) set_scheduler(scheduler); +void SLAPrint::_synch() { + m_gcfg = m_config_reader(); + // TODO: fill PrintObject cache + m_dirty.store(false); +} + +bool SLAPrint::start() { if(!m_process) return false; - m_process->schedule([this, scheduler](){ - - }); + m_process->schedule([this](){ _start(); }); return true; } +namespace GUI { + +void GLGizmoSlaSupports::on_deactivate() { + std::cout << "gizmo deactivated " << std::endl; + if(!m_model_object) return; + + SLAPrint& print = wxGetApp().plater()->sla_print(); + print.synch(); + + print.start(); + +// sla::Controller supportctl; +// std::cout << "Generating supports:" << std::endl; + +// // TODO: somehow get the global status indicator +// supportctl.statuscb = [] (unsigned st, const std::string& msg) { +// std::cout << st << "% " << msg << std::endl; +// }; + +// TriangleMesh&& m = m_model_object->raw_mesh(); +// m.transform(m_model_object_matrix); +// auto emesh = sla::to_eigenmesh(m); + +// sla::SupportConfig cfg; +// sla::PointSet input = sla::support_points(*m_model_object, 0 /*instance*/); + +// sla::SLASupportTree stree(input, emesh, cfg, supportctl); + +// TriangleMesh output; +// stree.merged_mesh(output); + +// _3DScene::reload_scene(m_parent.get_wxglcanvas(), false); +} +} + } diff --git a/src/slic3r/GUI/SLAPrint.hpp b/src/slic3r/GUI/SLAPrint.hpp index 7878e25ba..4d7236279 100644 --- a/src/slic3r/GUI/SLAPrint.hpp +++ b/src/slic3r/GUI/SLAPrint.hpp @@ -19,6 +19,7 @@ class DynamicPrintConfig; // implemented using a BackgroundSlicingProcess or something derived from that // The methods should be thread safe, obviously... class BackgroundProcess { + std::function m_synchfn; public: virtual ~BackgroundProcess() {} @@ -33,14 +34,21 @@ public: /// worker thread virtual bool is_canceled() = 0; - /// Setting up a callback that transfers the input parameters to the worker - /// thread. Appropriate synchronization has to be implemented here. A simple - /// condition variable and mutex pair should do the job. - virtual void on_input_changed(std::function synchfn) = 0; - /// Determine the state of the background process. If something is running /// returns true. If no job is running, returns false. virtual bool is_running() = 0; + + /// Trigger the synchronization of frontend/backend data + virtual void input_changed() { + m_synchfn(); // will just call the provided synch function itself. + } + + /// Setting up a callback that transfers the input parameters to the worker + /// thread. Appropriate synchronization has to be implemented here. A simple + /// condition variable and mutex pair should do the job. + void on_input_changed(std::function synchfn) { + m_synchfn = synchfn; + } }; /** @@ -78,21 +86,20 @@ public: private: - // There will be a support tree for every instance of every ModelObject - // because if the object is rotated differently, the support should also be - // very different + // Caching instance transformations and slices struct PrintObjectInstance { Transform3f tr; - std::unique_ptr support_tree_ptr; SlicedSupports slice_cache; }; using InstanceMap = std::unordered_map; // Every ModelObject will have its PrintObject here. It will contain the - // cached index-triangle structure (emesh) and the map of the instance cache + // support tree geometry, the cached index-triangle structure (emesh) and + // the map of the instance cache struct PrintObject { sla::EigenMesh3D emesh; + std::unique_ptr support_tree_ptr; InstanceMap instances; }; @@ -113,19 +120,8 @@ private: std::shared_ptr m_process; // The scheduler // For now it will just stop the whole process and invalidate everything - void synch(); std::atomic m_dirty; - void set_scheduler(std::shared_ptr scheduler) { - if(scheduler && !scheduler->is_running()) { - m_process = scheduler; - m_process->on_input_changed([this] { - /*synch(); */ - m_dirty.store(true); - }); - } - } - enum Stages { IDLE, FIND_ROTATION, @@ -142,22 +138,35 @@ private: static const std::string m_stage_labels[NUM_STAGES]; - bool run(); + void _start(); + void _synch(); + public: + void set_scheduler(std::shared_ptr scheduler) { + if(scheduler && !scheduler->is_running()) { + m_process = scheduler; + m_process->on_input_changed([this] { + _synch(); + }); + } + } + SLAPrint(const Model * model, std::function cfgreader = [](){ return SLAPrint::GlobalConfig(); }, std::shared_ptr scheduler = {}): m_model(model), m_config_reader(cfgreader) { - synch(); - m_dirty.store(false); set_scheduler(scheduler); } + void synch() { + if(m_process) m_process->input_changed(); + } + // This will start the calculation using the - bool start(std::shared_ptr scheduler); + bool start(); // Get the full support structure (including the base pool) // This should block until the supports are not ready?