mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-30 20:21:12 -06:00 
			
		
		
		
	Move ui jobs into separate folder
This commit is contained in:
		
							parent
							
								
									728d90cb33
								
							
						
					
					
						commit
						6eb51a1cca
					
				
					 11 changed files with 19 additions and 18 deletions
				
			
		
							
								
								
									
										223
									
								
								src/slic3r/GUI/Jobs/ArrangeJob.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										223
									
								
								src/slic3r/GUI/Jobs/ArrangeJob.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,223 @@ | |||
| #include "ArrangeJob.hpp" | ||||
| 
 | ||||
| #include "libslic3r/MTUtils.hpp" | ||||
| 
 | ||||
| #include "slic3r/GUI/Plater.hpp" | ||||
| #include "slic3r/GUI/GLCanvas3D.hpp" | ||||
| #include "slic3r/GUI/GUI.hpp" | ||||
| 
 | ||||
| namespace Slic3r { namespace GUI { | ||||
| 
 | ||||
| // Cache the wti info
 | ||||
| class WipeTower: public GLCanvas3D::WipeTowerInfo { | ||||
|     using ArrangePolygon = arrangement::ArrangePolygon; | ||||
| public: | ||||
|     explicit WipeTower(const GLCanvas3D::WipeTowerInfo &wti) | ||||
|         : GLCanvas3D::WipeTowerInfo(wti) | ||||
|     {} | ||||
|      | ||||
|     explicit WipeTower(GLCanvas3D::WipeTowerInfo &&wti) | ||||
|         : GLCanvas3D::WipeTowerInfo(std::move(wti)) | ||||
|     {} | ||||
| 
 | ||||
|     void apply_arrange_result(const Vec2d& tr, double rotation) | ||||
|     { | ||||
|         m_pos = unscaled(tr); m_rotation = rotation; | ||||
|         apply_wipe_tower(); | ||||
|     } | ||||
|      | ||||
|     ArrangePolygon get_arrange_polygon() const | ||||
|     { | ||||
|         Polygon ap({ | ||||
|             {coord_t(0), coord_t(0)}, | ||||
|             {scaled(m_bb_size(X)), coord_t(0)}, | ||||
|             {scaled(m_bb_size)}, | ||||
|             {coord_t(0), scaled(m_bb_size(Y))}, | ||||
|             {coord_t(0), coord_t(0)}, | ||||
|             }); | ||||
|          | ||||
|         ArrangePolygon ret; | ||||
|         ret.poly.contour = std::move(ap); | ||||
|         ret.translation  = scaled(m_pos); | ||||
|         ret.rotation     = m_rotation; | ||||
|         ret.priority++; | ||||
|         return ret; | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| static WipeTower get_wipe_tower(Plater &plater) | ||||
| { | ||||
|     return WipeTower{plater.canvas3D()->get_wipe_tower_info()}; | ||||
| } | ||||
| 
 | ||||
| void ArrangeJob::clear_input() | ||||
| { | ||||
|     const Model &model = m_plater->model(); | ||||
|      | ||||
|     size_t count = 0, cunprint = 0; // To know how much space to reserve
 | ||||
|     for (auto obj : model.objects) | ||||
|         for (auto mi : obj->instances) | ||||
|             mi->printable ? count++ : cunprint++; | ||||
|      | ||||
|     m_selected.clear(); | ||||
|     m_unselected.clear(); | ||||
|     m_unprintable.clear(); | ||||
|     m_selected.reserve(count + 1 /* for optional wti */); | ||||
|     m_unselected.reserve(count + 1 /* for optional wti */); | ||||
|     m_unprintable.reserve(cunprint /* for optional wti */); | ||||
| } | ||||
| 
 | ||||
| double ArrangeJob::bed_stride() const { | ||||
|     double bedwidth = m_plater->bed_shape_bb().size().x(); | ||||
|     return scaled<double>((1. + LOGICAL_BED_GAP) * bedwidth); | ||||
| } | ||||
| 
 | ||||
| void ArrangeJob::prepare_all() { | ||||
|     clear_input(); | ||||
|      | ||||
|     for (ModelObject *obj: m_plater->model().objects) | ||||
|         for (ModelInstance *mi : obj->instances) { | ||||
|             ArrangePolygons & cont = mi->printable ? m_selected : m_unprintable; | ||||
|             cont.emplace_back(get_arrange_poly(mi)); | ||||
|         } | ||||
| 
 | ||||
|     if (auto wti = get_wipe_tower(*m_plater)) | ||||
|         m_selected.emplace_back(wti.get_arrange_polygon()); | ||||
| } | ||||
| 
 | ||||
| void ArrangeJob::prepare_selected() { | ||||
|     clear_input(); | ||||
|      | ||||
|     Model &model = m_plater->model(); | ||||
|     double stride = bed_stride(); | ||||
|      | ||||
|     std::vector<const Selection::InstanceIdxsList *> | ||||
|             obj_sel(model.objects.size(), nullptr); | ||||
|      | ||||
|     for (auto &s : m_plater->get_selection().get_content()) | ||||
|         if (s.first < int(obj_sel.size())) | ||||
|             obj_sel[size_t(s.first)] = &s.second; | ||||
|      | ||||
|     // Go through the objects and check if inside the selection
 | ||||
|     for (size_t oidx = 0; oidx < model.objects.size(); ++oidx) { | ||||
|         const Selection::InstanceIdxsList * instlist = obj_sel[oidx]; | ||||
|         ModelObject *mo = model.objects[oidx]; | ||||
|          | ||||
|         std::vector<bool> inst_sel(mo->instances.size(), false); | ||||
|          | ||||
|         if (instlist) | ||||
|             for (auto inst_id : *instlist) | ||||
|                 inst_sel[size_t(inst_id)] = true; | ||||
|          | ||||
|         for (size_t i = 0; i < inst_sel.size(); ++i) { | ||||
|             ArrangePolygon &&ap = get_arrange_poly(mo->instances[i]); | ||||
|              | ||||
|             ArrangePolygons &cont = mo->instances[i]->printable ? | ||||
|                         (inst_sel[i] ? m_selected : | ||||
|                                        m_unselected) : | ||||
|                         m_unprintable; | ||||
|              | ||||
|             cont.emplace_back(std::move(ap)); | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     if (auto wti = get_wipe_tower(*m_plater)) { | ||||
|         ArrangePolygon &&ap = get_arrange_poly(&wti); | ||||
|          | ||||
|         m_plater->get_selection().is_wipe_tower() ? | ||||
|                     m_selected.emplace_back(std::move(ap)) : | ||||
|                     m_unselected.emplace_back(std::move(ap)); | ||||
|     } | ||||
|      | ||||
|     // If the selection was empty arrange everything
 | ||||
|     if (m_selected.empty()) m_selected.swap(m_unselected); | ||||
|      | ||||
|     // The strides have to be removed from the fixed items. For the
 | ||||
|     // arrangeable (selected) items bed_idx is ignored and the
 | ||||
|     // translation is irrelevant.
 | ||||
|     for (auto &p : m_unselected) p.translation(X) -= p.bed_idx * stride; | ||||
| } | ||||
| 
 | ||||
| void ArrangeJob::prepare() | ||||
| { | ||||
|     wxGetKeyState(WXK_SHIFT) ? prepare_selected() : prepare_all(); | ||||
| } | ||||
| 
 | ||||
| void ArrangeJob::process() | ||||
| { | ||||
|     static const auto arrangestr = _(L("Arranging")); | ||||
|      | ||||
|     double dist = min_object_distance(*m_plater->config()); | ||||
|      | ||||
|     arrangement::ArrangeParams params; | ||||
|     params.min_obj_distance = scaled(dist); | ||||
|      | ||||
|     auto count = unsigned(m_selected.size() + m_unprintable.size()); | ||||
|     Points bedpts = get_bed_shape(*m_plater->config()); | ||||
|      | ||||
|     params.stopcondition = [this]() { return was_canceled(); }; | ||||
|      | ||||
|     try { | ||||
|         params.progressind = [this, count](unsigned st) { | ||||
|             st += m_unprintable.size(); | ||||
|             if (st > 0) update_status(int(count - st), arrangestr); | ||||
|         }; | ||||
|          | ||||
|         arrangement::arrange(m_selected, m_unselected, bedpts, params); | ||||
|          | ||||
|         params.progressind = [this, count](unsigned st) { | ||||
|             if (st > 0) update_status(int(count - st), arrangestr); | ||||
|         }; | ||||
|          | ||||
|         arrangement::arrange(m_unprintable, {}, bedpts, params); | ||||
|     } catch (std::exception & /*e*/) { | ||||
|         GUI::show_error(m_plater, | ||||
|                         _(L("Could not arrange model objects! " | ||||
|                             "Some geometries may be invalid."))); | ||||
|     } | ||||
| 
 | ||||
|     // finalize just here.
 | ||||
|     update_status(int(count), | ||||
|                   was_canceled() ? _(L("Arranging canceled.")) | ||||
|                                    : _(L("Arranging done."))); | ||||
| } | ||||
| 
 | ||||
| void ArrangeJob::finalize() { | ||||
|     // Ignore the arrange result if aborted.
 | ||||
|     if (was_canceled()) return; | ||||
|      | ||||
|     // Unprintable items go to the last virtual bed
 | ||||
|     int beds = 0; | ||||
|      | ||||
|     // Apply the arrange result to all selected objects
 | ||||
|     for (ArrangePolygon &ap : m_selected) { | ||||
|         beds = std::max(ap.bed_idx, beds); | ||||
|         ap.apply(); | ||||
|     } | ||||
|      | ||||
|     // Get the virtual beds from the unselected items
 | ||||
|     for (ArrangePolygon &ap : m_unselected) | ||||
|         beds = std::max(ap.bed_idx, beds); | ||||
|      | ||||
|     // Move the unprintable items to the last virtual bed.
 | ||||
|     for (ArrangePolygon &ap : m_unprintable) { | ||||
|         ap.bed_idx += beds + 1; | ||||
|         ap.apply(); | ||||
|     } | ||||
|      | ||||
|     m_plater->update(); | ||||
|      | ||||
|     Job::finalize(); | ||||
| } | ||||
| 
 | ||||
| arrangement::ArrangePolygon get_wipe_tower_arrangepoly(Plater &plater) | ||||
| { | ||||
|     return WipeTower{plater.canvas3D()->get_wipe_tower_info()}.get_arrange_polygon(); | ||||
| } | ||||
| 
 | ||||
| void apply_wipe_tower_arrangepoly(Plater &plater, const arrangement::ArrangePolygon &ap) | ||||
| { | ||||
|     WipeTower{plater.canvas3D()->get_wipe_tower_info()}.apply_arrange_result(ap.translation.cast<double>(), ap.rotation); | ||||
| } | ||||
| 
 | ||||
| }} // namespace Slic3r::GUI
 | ||||
							
								
								
									
										77
									
								
								src/slic3r/GUI/Jobs/ArrangeJob.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								src/slic3r/GUI/Jobs/ArrangeJob.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,77 @@ | |||
| #ifndef ARRANGEJOB_HPP | ||||
| #define ARRANGEJOB_HPP | ||||
| 
 | ||||
| #include "Job.hpp" | ||||
| #include "libslic3r/Arrange.hpp" | ||||
| 
 | ||||
| namespace Slic3r { namespace GUI { | ||||
| 
 | ||||
| class Plater; | ||||
| 
 | ||||
| class ArrangeJob : public Job | ||||
| { | ||||
|     Plater *m_plater; | ||||
|      | ||||
|     using ArrangePolygon = arrangement::ArrangePolygon; | ||||
|     using ArrangePolygons = arrangement::ArrangePolygons; | ||||
|      | ||||
|     // The gap between logical beds in the x axis expressed in ratio of
 | ||||
|     // the current bed width.
 | ||||
|     static const constexpr double LOGICAL_BED_GAP = 1. / 5.; | ||||
|      | ||||
|     ArrangePolygons m_selected, m_unselected, m_unprintable; | ||||
|      | ||||
|     // clear m_selected and m_unselected, reserve space for next usage
 | ||||
|     void clear_input(); | ||||
|      | ||||
|     // Stride between logical beds
 | ||||
|     double bed_stride() const; | ||||
|      | ||||
|     // Set up arrange polygon for a ModelInstance and Wipe tower
 | ||||
|     template<class T> ArrangePolygon get_arrange_poly(T *obj) const | ||||
|     { | ||||
|         ArrangePolygon ap = obj->get_arrange_polygon(); | ||||
|         ap.priority       = 0; | ||||
|         ap.bed_idx        = ap.translation.x() / bed_stride(); | ||||
|         ap.setter         = [obj, this](const ArrangePolygon &p) { | ||||
|             if (p.is_arranged()) { | ||||
|                 Vec2d t = p.translation.cast<double>(); | ||||
|                 t.x() += p.bed_idx * bed_stride(); | ||||
|                 obj->apply_arrange_result(t, p.rotation); | ||||
|             } | ||||
|         }; | ||||
|         return ap; | ||||
|     } | ||||
|      | ||||
|     // Prepare all objects on the bed regardless of the selection
 | ||||
|     void prepare_all(); | ||||
|      | ||||
|     // Prepare the selected and unselected items separately. If nothing is
 | ||||
|     // selected, behaves as if everything would be selected.
 | ||||
|     void prepare_selected(); | ||||
|      | ||||
| protected: | ||||
|      | ||||
|     void prepare() override; | ||||
|      | ||||
| public: | ||||
|     ArrangeJob(std::shared_ptr<ProgressIndicator> pri, Plater *plater) | ||||
|         : Job{std::move(pri)}, m_plater{plater} | ||||
|     {} | ||||
|      | ||||
|     int status_range() const override | ||||
|     { | ||||
|         return int(m_selected.size() + m_unprintable.size()); | ||||
|     } | ||||
|      | ||||
|     void process() override; | ||||
|      | ||||
|     void finalize() override; | ||||
| }; | ||||
| 
 | ||||
| arrangement::ArrangePolygon get_wipe_tower_arrangepoly(Plater &); | ||||
| void apply_wipe_tower_arrangepoly(Plater &plater, const arrangement::ArrangePolygon &ap); | ||||
| 
 | ||||
| }} // namespace Slic3r::GUI
 | ||||
| 
 | ||||
| #endif // ARRANGEJOB_HPP
 | ||||
							
								
								
									
										121
									
								
								src/slic3r/GUI/Jobs/Job.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								src/slic3r/GUI/Jobs/Job.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,121 @@ | |||
| #include <algorithm> | ||||
| 
 | ||||
| #include "Job.hpp" | ||||
| #include <boost/log/trivial.hpp> | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| 
 | ||||
| void GUI::Job::run() | ||||
| { | ||||
|     m_running.store(true); | ||||
|     process(); | ||||
|     m_running.store(false); | ||||
|      | ||||
|     // ensure to call the last status to finalize the job
 | ||||
|     update_status(status_range(), ""); | ||||
| } | ||||
| 
 | ||||
| void GUI::Job::update_status(int st, const wxString &msg) | ||||
| { | ||||
|     auto evt = new wxThreadEvent(); | ||||
|     evt->SetInt(st); | ||||
|     evt->SetString(msg); | ||||
|     wxQueueEvent(this, evt); | ||||
| } | ||||
| 
 | ||||
| GUI::Job::Job(std::shared_ptr<ProgressIndicator> pri) | ||||
|     : m_progress(std::move(pri)) | ||||
| { | ||||
|     Bind(wxEVT_THREAD, [this](const wxThreadEvent &evt) { | ||||
|         auto msg = evt.GetString(); | ||||
|         if (!msg.empty()) | ||||
|             m_progress->set_status_text(msg.ToUTF8().data()); | ||||
|          | ||||
|         if (m_finalized) return; | ||||
|          | ||||
|         m_progress->set_progress(evt.GetInt()); | ||||
|         if (evt.GetInt() == status_range()) { | ||||
|             // set back the original range and cancel callback
 | ||||
|             m_progress->set_range(m_range); | ||||
|             m_progress->set_cancel_callback(); | ||||
|             wxEndBusyCursor(); | ||||
|              | ||||
|             finalize(); | ||||
|              | ||||
|             // dont do finalization again for the same process
 | ||||
|             m_finalized = true; | ||||
|         } | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| void GUI::Job::start() | ||||
| { // Start the job. No effect if the job is already running
 | ||||
|     if (!m_running.load()) { | ||||
|         prepare(); | ||||
|          | ||||
|         // Save the current status indicatior range and push the new one
 | ||||
|         m_range = m_progress->get_range(); | ||||
|         m_progress->set_range(status_range()); | ||||
|          | ||||
|         // init cancellation flag and set the cancel callback
 | ||||
|         m_canceled.store(false); | ||||
|         m_progress->set_cancel_callback( | ||||
|                     [this]() { m_canceled.store(true); }); | ||||
|          | ||||
|         m_finalized = false; | ||||
|          | ||||
|         // Changing cursor to busy
 | ||||
|         wxBeginBusyCursor(); | ||||
|          | ||||
|         try { // Execute the job
 | ||||
|             m_thread = create_thread([this] { this->run(); }); | ||||
|         } catch (std::exception &) { | ||||
|             update_status(status_range(), | ||||
|                           _(L("ERROR: not enough resources to " | ||||
|                               "execute a new job."))); | ||||
|         } | ||||
|          | ||||
|         // The state changes will be undone when the process hits the
 | ||||
|         // last status value, in the status update handler (see ctor)
 | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| bool GUI::Job::join(int timeout_ms) | ||||
| { | ||||
|     if (!m_thread.joinable()) return true; | ||||
|      | ||||
|     if (timeout_ms <= 0) | ||||
|         m_thread.join(); | ||||
|     else if (!m_thread.try_join_for(boost::chrono::milliseconds(timeout_ms))) | ||||
|         return false; | ||||
|      | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| void GUI::ExclusiveJobGroup::start(size_t jid) { | ||||
|     assert(jid < m_jobs.size()); | ||||
|     stop_all(); | ||||
|     m_jobs[jid]->start(); | ||||
| } | ||||
| 
 | ||||
| void GUI::ExclusiveJobGroup::join_all(int wait_ms) | ||||
| { | ||||
|     std::vector<bool> aborted(m_jobs.size(), false); | ||||
|      | ||||
|     for (size_t jid = 0; jid < m_jobs.size(); ++jid) | ||||
|         aborted[jid] = m_jobs[jid]->join(wait_ms); | ||||
|      | ||||
|     if (!std::all_of(aborted.begin(), aborted.end(), [](bool t) { return t; })) | ||||
|         BOOST_LOG_TRIVIAL(error) << "Could not abort a job!"; | ||||
| } | ||||
| 
 | ||||
| bool GUI::ExclusiveJobGroup::is_any_running() const | ||||
| { | ||||
|     return std::any_of(m_jobs.begin(), m_jobs.end(), | ||||
|                        [](const std::unique_ptr<GUI::Job> &j) { | ||||
|         return j->is_running(); | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
							
								
								
									
										110
									
								
								src/slic3r/GUI/Jobs/Job.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								src/slic3r/GUI/Jobs/Job.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,110 @@ | |||
| #ifndef JOB_HPP | ||||
| #define JOB_HPP | ||||
| 
 | ||||
| #include <atomic> | ||||
| 
 | ||||
| #include <slic3r/Utils/Thread.hpp> | ||||
| #include <slic3r/GUI/I18N.hpp> | ||||
| 
 | ||||
| #include "ProgressIndicator.hpp" | ||||
| 
 | ||||
| #include <wx/event.h> | ||||
| 
 | ||||
| #include <boost/thread.hpp> | ||||
| 
 | ||||
| namespace Slic3r { namespace GUI { | ||||
| 
 | ||||
| // A class to handle UI jobs like arranging and optimizing rotation.
 | ||||
| // These are not instant jobs, the user has to be informed about their
 | ||||
| // state in the status progress indicator. On the other hand they are
 | ||||
| // separated from the background slicing process. Ideally, these jobs should
 | ||||
| // run when the background process is not running.
 | ||||
| //
 | ||||
| // TODO: A mechanism would be useful for blocking the plater interactions:
 | ||||
| // objects would be frozen for the user. In case of arrange, an animation
 | ||||
| // could be shown, or with the optimize orientations, partial results
 | ||||
| // could be displayed.
 | ||||
| class Job : public wxEvtHandler | ||||
| { | ||||
|     int               m_range = 100; | ||||
|     boost::thread     m_thread; | ||||
|     std::atomic<bool> m_running{false}, m_canceled{false}; | ||||
|     bool              m_finalized = false; | ||||
|     std::shared_ptr<ProgressIndicator> m_progress; | ||||
|      | ||||
|     void run(); | ||||
|      | ||||
| protected: | ||||
|     // status range for a particular job
 | ||||
|     virtual int status_range() const { return 100; } | ||||
|      | ||||
|     // status update, to be used from the work thread (process() method)
 | ||||
|     void update_status(int st, const wxString &msg = ""); | ||||
| 
 | ||||
|     bool was_canceled() const { return m_canceled.load(); } | ||||
| 
 | ||||
|     // Launched just before start(), a job can use it to prepare internals
 | ||||
|     virtual void prepare() {} | ||||
|      | ||||
|     // Launched when the job is finished. It refreshes the 3Dscene by def.
 | ||||
|     virtual void finalize() { m_finalized = true; } | ||||
|     | ||||
| public: | ||||
|     Job(std::shared_ptr<ProgressIndicator> pri); | ||||
|      | ||||
|     bool is_finalized() const { return m_finalized; } | ||||
|      | ||||
|     Job(const Job &) = delete; | ||||
|     Job(Job &&)      = delete; | ||||
|     Job &operator=(const Job &) = delete; | ||||
|     Job &operator=(Job &&) = delete; | ||||
|      | ||||
|     virtual void process() = 0; | ||||
|      | ||||
|     void start(); | ||||
|      | ||||
|     // To wait for the running job and join the threads. False is
 | ||||
|     // returned if the timeout has been reached and the job is still
 | ||||
|     // running. Call cancel() before this fn if you want to explicitly
 | ||||
|     // end the job.
 | ||||
|     bool join(int timeout_ms = 0); | ||||
|      | ||||
|     bool is_running() const { return m_running.load(); } | ||||
|     void cancel() { m_canceled.store(true); } | ||||
| }; | ||||
| 
 | ||||
| // Jobs defined inside the group class will be managed so that only one can
 | ||||
| // run at a time. Also, the background process will be stopped if a job is
 | ||||
| // started.
 | ||||
| class ExclusiveJobGroup | ||||
| { | ||||
|     static const int ABORT_WAIT_MAX_MS = 10000; | ||||
|      | ||||
|     std::vector<std::unique_ptr<GUI::Job>> m_jobs; | ||||
|      | ||||
| protected: | ||||
|     virtual void before_start() {} | ||||
|      | ||||
| public: | ||||
|     virtual ~ExclusiveJobGroup() = default; | ||||
|      | ||||
|     size_t add_job(std::unique_ptr<GUI::Job> &&job) | ||||
|     { | ||||
|         m_jobs.emplace_back(std::move(job)); | ||||
|         return m_jobs.size() - 1; | ||||
|     } | ||||
|      | ||||
|     void start(size_t jid); | ||||
|      | ||||
|     void cancel_all() { for (auto& j : m_jobs) j->cancel(); } | ||||
|      | ||||
|     void join_all(int wait_ms = 0); | ||||
|      | ||||
|     void stop_all() { cancel_all(); join_all(ABORT_WAIT_MAX_MS); } | ||||
|      | ||||
|     bool is_any_running() const; | ||||
| }; | ||||
| 
 | ||||
| }} // namespace Slic3r::GUI
 | ||||
| 
 | ||||
| #endif // JOB_HPP
 | ||||
							
								
								
									
										29
									
								
								src/slic3r/GUI/Jobs/ProgressIndicator.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/slic3r/GUI/Jobs/ProgressIndicator.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,29 @@ | |||
| #ifndef IPROGRESSINDICATOR_HPP | ||||
| #define IPROGRESSINDICATOR_HPP | ||||
| 
 | ||||
| #include <string> | ||||
| #include <functional> | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Generic progress indication interface. | ||||
|  */ | ||||
| class ProgressIndicator { | ||||
| public: | ||||
|      | ||||
|     /// Cancel callback function type
 | ||||
|     using CancelFn = std::function<void()>; | ||||
|      | ||||
|     virtual ~ProgressIndicator() = default; | ||||
|      | ||||
|     virtual void set_range(int range) = 0; | ||||
|     virtual void set_cancel_callback(CancelFn = CancelFn()) = 0; | ||||
|     virtual void set_progress(int pr) = 0; | ||||
|     virtual void set_status_text(const char *) = 0; // utf8 char array
 | ||||
|     virtual int  get_range() const = 0; | ||||
| }; | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #endif // IPROGRESSINDICATOR_HPP
 | ||||
							
								
								
									
										68
									
								
								src/slic3r/GUI/Jobs/RotoptimizeJob.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								src/slic3r/GUI/Jobs/RotoptimizeJob.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,68 @@ | |||
| #include "RotoptimizeJob.hpp" | ||||
| 
 | ||||
| #include "libslic3r/MTUtils.hpp" | ||||
| #include "libslic3r/SLA/Rotfinder.hpp" | ||||
| #include "libslic3r/MinAreaBoundingBox.hpp" | ||||
| 
 | ||||
| #include "slic3r/GUI/Plater.hpp" | ||||
| 
 | ||||
| namespace Slic3r { namespace GUI { | ||||
| 
 | ||||
| void RotoptimizeJob::process() | ||||
| { | ||||
|     int obj_idx = m_plater->get_selected_object_idx(); | ||||
|     if (obj_idx < 0) { return; } | ||||
|      | ||||
|     ModelObject *o = m_plater->model().objects[size_t(obj_idx)]; | ||||
| 
 | ||||
|     auto r = sla::find_best_rotation( | ||||
|         *o, | ||||
|         .005f, | ||||
|         [this](unsigned s) { | ||||
|             if (s < 100) | ||||
|                 update_status(int(s), | ||||
|                               _(L("Searching for optimal orientation"))); | ||||
|         }, | ||||
|         [this]() { return was_canceled(); }); | ||||
| 
 | ||||
| 
 | ||||
|     double mindist = 6.0; // FIXME
 | ||||
| 
 | ||||
|     if (!was_canceled()) { | ||||
|         for(ModelInstance * oi : o->instances) { | ||||
|             oi->set_rotation({r[X], r[Y], r[Z]}); | ||||
| 
 | ||||
|             auto    trmatrix = oi->get_transformation().get_matrix(); | ||||
|             Polygon trchull  = o->convex_hull_2d(trmatrix); | ||||
| 
 | ||||
|             MinAreaBoundigBox rotbb(trchull, MinAreaBoundigBox::pcConvex); | ||||
|             double            phi = rotbb.angle_to_X(); | ||||
| 
 | ||||
|             // The box should be landscape
 | ||||
|             if(rotbb.width() < rotbb.height()) phi += PI / 2; | ||||
| 
 | ||||
|             Vec3d rt = oi->get_rotation(); rt(Z) += phi; | ||||
| 
 | ||||
|             oi->set_rotation(rt); | ||||
|         } | ||||
| 
 | ||||
|         m_plater->find_new_position(o->instances, scaled(mindist)); | ||||
| 
 | ||||
|         // Correct the z offset of the object which was corrupted be
 | ||||
|         // the rotation
 | ||||
|         o->ensure_on_bed(); | ||||
|     } | ||||
| 
 | ||||
|     update_status(100, was_canceled() ? _(L("Orientation search canceled.")) : | ||||
|                                         _(L("Orientation found."))); | ||||
| } | ||||
| 
 | ||||
| void RotoptimizeJob::finalize() | ||||
| { | ||||
|     if (!was_canceled()) | ||||
|         m_plater->update(); | ||||
|      | ||||
|     Job::finalize(); | ||||
| } | ||||
| 
 | ||||
| }} | ||||
							
								
								
									
										24
									
								
								src/slic3r/GUI/Jobs/RotoptimizeJob.hpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/slic3r/GUI/Jobs/RotoptimizeJob.hpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,24 @@ | |||
| #ifndef ROTOPTIMIZEJOB_HPP | ||||
| #define ROTOPTIMIZEJOB_HPP | ||||
| 
 | ||||
| #include "Job.hpp" | ||||
| 
 | ||||
| namespace Slic3r { namespace GUI { | ||||
| 
 | ||||
| class Plater; | ||||
| 
 | ||||
| class RotoptimizeJob : public Job | ||||
| { | ||||
|     Plater *m_plater; | ||||
| public: | ||||
|     RotoptimizeJob(std::shared_ptr<ProgressIndicator> pri, Plater *plater) | ||||
|         : Job{std::move(pri)}, m_plater{plater} | ||||
|     {} | ||||
|      | ||||
|     void process() override; | ||||
|     void finalize() override; | ||||
| }; | ||||
| 
 | ||||
| }} // namespace Slic3r::GUI
 | ||||
| 
 | ||||
| #endif // ROTOPTIMIZEJOB_HPP
 | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 tamasmeszaros
						tamasmeszaros