create stopable job which could be repeatedly run

This commit is contained in:
Filip Sykala 2021-11-24 09:41:34 +01:00
parent 43d200a7fb
commit 205f8cf86d
2 changed files with 102 additions and 10 deletions

View File

@ -13,9 +13,10 @@
using namespace Slic3r; using namespace Slic3r;
using namespace GUI; using namespace GUI;
namespace Priv { namespace Priv {
static void process(std::unique_ptr<EmbossData> input); static void process(std::unique_ptr<EmbossData> input, StopCondition is_stop);
static void finalize(const EmbossData &input, const indexed_triangle_set &result); static void finalize(const EmbossData &input, const indexed_triangle_set &result);
// TODO: move to objec list utils // TODO: move to objec list utils
@ -23,10 +24,9 @@ static void select_volume(ModelVolume *volume);
} // namespace Priv } // namespace Priv
EmbossJob::EmbossJob() : ReRunJob<EmbossData>(Priv::process) {} EmbossJob::EmbossJob() : StopableJob<EmbossData>(Priv::process) {}
void Priv::process(std::unique_ptr<EmbossData> input, StopCondition is_stop)
void Priv::process(std::unique_ptr<EmbossData> input)
{ {
// only for sure // only for sure
assert(input != nullptr); assert(input != nullptr);
@ -34,14 +34,16 @@ void Priv::process(std::unique_ptr<EmbossData> input)
// check if exist valid font // check if exist valid font
if (input->font == nullptr) return; if (input->font == nullptr) return;
// Do NOT process empty string
const TextConfiguration &cfg = input->text_configuration; const TextConfiguration &cfg = input->text_configuration;
const std::string & text = cfg.text; const std::string & text = cfg.text;
// Do NOT process empty string
if (text.empty()) return; if (text.empty()) return;
const FontProp &prop = cfg.font_prop; const FontProp &prop = cfg.font_prop;
ExPolygons shapes = Emboss::text2shapes(*input->font, text.c_str(), prop); ExPolygons shapes = Emboss::text2shapes(*input->font, text.c_str(), prop);
if (is_stop()) return;
// exist 2d shape made by text ? // exist 2d shape made by text ?
// (no shape means that font hasn't any of text symbols) // (no shape means that font hasn't any of text symbols)
if (shapes.empty()) return; if (shapes.empty()) return;
@ -49,7 +51,9 @@ void Priv::process(std::unique_ptr<EmbossData> input)
float scale = prop.size_in_mm / input->font->ascent; float scale = prop.size_in_mm / input->font->ascent;
auto projectZ = std::make_unique<Emboss::ProjectZ>(prop.emboss / scale); auto projectZ = std::make_unique<Emboss::ProjectZ>(prop.emboss / scale);
Emboss::ProjectScale project(std::move(projectZ), scale); Emboss::ProjectScale project(std::move(projectZ), scale);
auto its = std::make_unique<indexed_triangle_set>(Emboss::polygons2model(shapes, project)); auto its = std::make_unique<indexed_triangle_set>(Emboss::polygons2model(shapes, project));
if (is_stop()) return;
// for sure that some object is created from shape // for sure that some object is created from shape
if (its->indices.empty()) return; if (its->indices.empty()) return;
@ -72,9 +76,11 @@ void Priv::process(std::unique_ptr<EmbossData> input)
{} {}
}; };
Data *data = new Data(std::move(input), std::move(its)); Data *data = new Data(std::move(input), std::move(its));
// How to proof that call, will be done on exit?
wxGetApp().plater()->CallAfter([data]() { wxGetApp().plater()->CallAfter([data]() {
Priv::finalize(*data->input, *data->result); // because of finalize exception delete must be in ScopeGuard
delete data; ScopeGuard sg([data]() { delete data; });
Priv::finalize(*data->input, *data->result);
}); });
} }

View File

@ -17,7 +17,8 @@ namespace Slic3r::GUI {
// inspired by Job.hpp // inspired by Job.hpp
// All public function can be call only from UI thread // All public function can be call only from UI thread
// Mechanism to stack processing and do only last one // Mechanism to stack processing and do only last one
template<typename TIn> class ReRunJob template<typename TIn>
class ReRunJob
{ {
std::mutex m_next_mutex; std::mutex m_next_mutex;
std::unique_ptr<TIn> m_input_next = nullptr; std::unique_ptr<TIn> m_input_next = nullptr;
@ -77,6 +78,91 @@ public:
} }
}; };
using StopCondition = std::function<bool(void)>;
// add stop ability
template<typename TIn> class StopableJob
{
std::mutex m_mutex;
std::unique_ptr<TIn> m_input_next = nullptr;
std::thread m_thread;
// indicate checking of new input.
bool m_running = false;
bool m_stop = false;
using Func = std::function<void(std::unique_ptr<TIn>, StopCondition)>;
Func m_func;
public:
StopableJob(Func func) : m_func(func) {}
virtual ~StopableJob() {
stop();
join();
}
void re_run(std::unique_ptr<TIn> input)
{
if (input == nullptr) return;
{
// keep access to next input
std::lock_guard lg(m_mutex);
if (m_running) {
// when runnig
m_stop = true;
m_input_next = std::move(input);
return; // on end of run will be used new input
}
m_running = true;
m_stop = false;
}
if (m_thread.joinable()) m_thread.join();
// at this moment is not running --> stoped
assert(m_input_next == nullptr);
try { // Execute the job
m_thread = std::thread(
[this](std::unique_ptr<TIn> input) {
do {
m_func(std::move(input), [this]() { return is_stoping(); });
std::lock_guard lg(m_mutex);
m_stop = false;
// this is not while (end)condition because of lock guard
if (m_input_next == nullptr) {
m_running = false;
return;
}
input = std::move(m_input_next);
m_input_next = nullptr;
} while (true);
},
std::move(input));
} catch (std::exception &) {}
}
bool is_running()
{
std::lock_guard lg(m_mutex);
return m_running;
}
bool is_stoping()
{
std::lock_guard lg(m_mutex);
return m_stop;
}
void stop() {
std::lock_guard lg(m_mutex);
m_input_next = nullptr;
m_stop = true;
}
// blocking until stop,
void join(int timeout_ms = 0)
{
if (m_thread.joinable()) m_thread.join();
assert(!m_running);
}
};
struct EmbossData struct EmbossData
{ {
// Pointer on Data of font (glyph shapes) // Pointer on Data of font (glyph shapes)
@ -91,7 +177,7 @@ struct EmbossData
int object_idx; int object_idx;
}; };
class EmbossJob : public ReRunJob<EmbossData> class EmbossJob : public StopableJob<EmbossData>
{ {
public: public:
EmbossJob(); EmbossJob();