Using of Re run Job

This commit is contained in:
Filip Sykala 2021-11-23 22:21:14 +01:00
parent 2e41c8aafe
commit 43d200a7fb
5 changed files with 160 additions and 153 deletions

View File

@ -1743,7 +1743,7 @@ void ObjectList::load_shape_object_from_gallery(const wxArrayString& input_files
wxGetApp().mainframe->update_title(); wxGetApp().mainframe->update_title();
} }
void ObjectList::load_mesh_object(const TriangleMesh &mesh, const wxString &name, bool center, TextConfiguration* text_config/* = nullptr*/) void ObjectList::load_mesh_object(const TriangleMesh &mesh, const wxString &name, bool center, const TextConfiguration* text_config/* = nullptr*/)
{ {
// Add mesh to model as a new object // Add mesh to model as a new object
Model& model = wxGetApp().plater()->model(); Model& model = wxGetApp().plater()->model();

View File

@ -257,7 +257,7 @@ public:
void load_shape_object(const std::string &type_name); void load_shape_object(const std::string &type_name);
void load_shape_object_from_gallery(); void load_shape_object_from_gallery();
void load_shape_object_from_gallery(const wxArrayString& input_files); void load_shape_object_from_gallery(const wxArrayString& input_files);
void load_mesh_object(const TriangleMesh &mesh, const wxString &name, bool center = true, TextConfiguration* text_config = nullptr); void load_mesh_object(const TriangleMesh &mesh, const wxString &name, bool center = true, const TextConfiguration* text_config = nullptr);
void del_object(const int obj_idx); void del_object(const int obj_idx);
void del_subobject_item(wxDataViewItem& item); void del_subobject_item(wxDataViewItem& item);
void del_settings_from_config(const wxDataViewItem& parent_item); void del_settings_from_config(const wxDataViewItem& parent_item);

View File

@ -472,14 +472,13 @@ bool GLGizmoEmboss::process()
// exist loaded font? // exist loaded font?
if (m_font == nullptr) return false; if (m_font == nullptr) return false;
auto data = std::make_unique<EmbossData>();
EmbossJob::Data data; data->font = m_font;
data.font = m_font; data->text_configuration = create_configuration();
data.text_configuration = create_configuration(); data->volume_name = create_volume_name();
data.volume_name = create_volume_name(); data->volume_ptr = m_volume;
data.volume_ptr = m_volume; data->object_idx = m_parent.get_selection().get_object_idx();
data.object_idx = m_parent.get_selection().get_object_idx(); m_job->re_run(std::move(data));
m_job->restart(data);
// notification is removed befor object is changed by job // notification is removed befor object is changed by job
remove_notification_not_valid_font(); remove_notification_not_valid_font();

View File

@ -13,108 +13,92 @@
using namespace Slic3r; using namespace Slic3r;
using namespace GUI; using namespace GUI;
//EmbossJob::EmbossJob(): Job(std::make_shared<NotificationProgressIndicator>(wxGetApp().plater()->get_notification_manager())){} namespace Priv {
EmbossJob::EmbossJob() : Job(std::make_shared<EmbossJob::Progress>()) {}
EmbossJob::~EmbossJob() { static void process(std::unique_ptr<EmbossData> input);
Job::cancel(); static void finalize(const EmbossData &input, const indexed_triangle_set &result);
Job::join();
}
void EmbossJob::restart(const Data &data) // TODO: move to objec list utils
static void select_volume(ModelVolume *volume);
} // namespace Priv
EmbossJob::EmbossJob() : ReRunJob<EmbossData>(Priv::process) {}
void Priv::process(std::unique_ptr<EmbossData> input)
{ {
if (Job::is_running()) { // only for sure
Job::cancel(); assert(input != nullptr);
std::lock_guard lk(m_mutex);
bool create_restart = !m_data_next.has_value();
m_data_next = data; // copy
if (create_restart) {
wxGetApp().plater()->CallAfter([this]() {
const Plater *plater = wxGetApp().plater();
if (plater == nullptr) return;
const GLCanvas3D *canvas = plater->canvas3D();
if (canvas == nullptr) return;
const GLGizmosManager &mng = canvas->get_gizmos_manager();
// check if simplify is still activ gizmo
if (mng.get_current_type() != GLGizmosManager::Emboss) return;
// when emboss is current, this object exist
Job::join();
{
// Not neccessary to lock mutex because job is stoped,
// but for sure that no other thread try to restart job.
// Is not critical and could be there.
std::lock_guard lk(m_mutex);
assert(m_data_next.has_value());
m_data = std::move(m_data_next);
// after move optional, data is UNDEFINED
m_data_next = {};
}
Job::start();
});
}
} else {
m_data = data; // copy
Job::start();
}
}
void EmbossJob::prepare() {}
void EmbossJob::process() {
// check if data was set
if (!m_data.has_value()) return;
// check if exist valid font // check if exist valid font
if (m_data->font == nullptr) return; if (input->font == nullptr) return;
// Do NOT process empty string // Do NOT process empty string
const TextConfiguration &cfg = m_data->text_configuration; const TextConfiguration &cfg = input->text_configuration;
const std::string &text = cfg.text; const std::string & text = cfg.text;
if (text.empty()) return; if (text.empty()) return;
const FontProp &prop = cfg.font_prop; const FontProp &prop = cfg.font_prop;
ExPolygons shapes = Emboss::text2shapes(*m_data->font, text.c_str(), prop); ExPolygons shapes = Emboss::text2shapes(*input->font, text.c_str(), prop);
// 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;
float scale = prop.size_in_mm / m_data->font->ascent; float scale = prop.size_in_mm / input->font->ascent;
auto project = std::make_unique<Emboss::ProjectScale>( auto projectZ = std::make_unique<Emboss::ProjectZ>(prop.emboss / scale);
std::make_unique<Emboss::ProjectZ>(prop.emboss / scale), scale); Emboss::ProjectScale project(std::move(projectZ), scale);
auto its = std::make_unique<indexed_triangle_set>(Emboss::polygons2model(shapes, project));
indexed_triangle_set its = Emboss::polygons2model(shapes, *project);
// 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;
m_result = its;
// Call setting model in UI thread
// Not work !!! CallAfter use only reference to lambda not lambda itself
// wxGetApp().plater()->CallAfter(
// [its2 = std::move(its), input2 = std::move(input)]() {
// Priv::finalize(*input2, *its2);
// });
struct Data
{
std::unique_ptr<EmbossData> input;
std::unique_ptr<indexed_triangle_set> result;
Data(std::unique_ptr<EmbossData> input,
std::unique_ptr<indexed_triangle_set> result)
: input(std::move(input)), result(std::move(result))
{}
};
Data *data = new Data(std::move(input), std::move(its));
wxGetApp().plater()->CallAfter([data]() {
Priv::finalize(*data->input, *data->result);
delete data;
});
} }
void EmbossJob::finalize() { void Priv::finalize(const EmbossData &input, const indexed_triangle_set &result)
// check result was created {
if (!m_result.has_value()) return; // it is sad, but there is no move constructor --> copy
if (m_result->indices.empty()) return; TriangleMesh tm(std::move(result));
// move object data
TriangleMesh tm(std::move(*m_result));
m_result = {};
// center triangle mesh // center triangle mesh
Vec3d shift = tm.bounding_box().center(); Vec3d shift = tm.bounding_box().center();
tm.translate(-shift.cast<float>()); tm.translate(-shift.cast<float>());
GUI_App & app = wxGetApp(); GUI_App & app = wxGetApp();
Plater * plater = app.plater(); Plater * plater = app.plater();
GLCanvas3D *canvas = plater->canvas3D(); GLCanvas3D * canvas = plater->canvas3D();
const std::string &name = m_data->volume_name; const std::string &name = input.volume_name;
plater->take_snapshot(_L("Emboss text") + ": " + name); plater->take_snapshot(_L("Emboss text") + ": " + name);
ModelVolume *volume = m_data->volume_ptr; ModelVolume *volume = input.volume_ptr;
if (volume == nullptr) { if (volume == nullptr) {
// decide to add as volume or new object // decide to add as volume or new object
if (m_data->object_idx < 0) { if (input.object_idx < 0) {
// create new object // create new object
app.obj_list()->load_mesh_object(tm, name, true, &m_data->text_configuration); app.obj_list()->load_mesh_object(tm, name, true, &input.text_configuration);
app.mainframe->update_title(); app.mainframe->update_title();
// TODO: find Why ??? // TODO: find Why ???
@ -127,9 +111,9 @@ void EmbossJob::finalize() {
} else { } else {
// create new volume inside of object // create new volume inside of object
Model &model = plater->model(); Model &model = plater->model();
if (model.objects.size() <= m_data->object_idx) return; if (model.objects.size() <= input.object_idx) return;
ModelObject *obj = model.objects[m_data->object_idx]; ModelObject *obj = model.objects[input.object_idx];
volume = obj->add_volume(std::move(tm)); volume = obj->add_volume(std::move(tm));
// set a default extruder value, since user can't add it manually // set a default extruder value, since user can't add it manually
volume->config.set_key_value("extruder", new ConfigOptionInt(0)); volume->config.set_key_value("extruder", new ConfigOptionInt(0));
} }
@ -141,8 +125,8 @@ void EmbossJob::finalize() {
volume->get_object()->invalidate_bounding_box(); volume->get_object()->invalidate_bounding_box();
} }
volume->name = name; volume->name = name;
volume->text_configuration = m_data->text_configuration; volume->text_configuration = input.text_configuration;
// update volume name in object list // update volume name in object list
// updata selection after new volume added // updata selection after new volume added
@ -153,18 +137,19 @@ void EmbossJob::finalize() {
canvas->reload_scene(true); canvas->reload_scene(true);
} }
void EmbossJob::select_volume(ModelVolume *volume) void Priv::select_volume(ModelVolume *volume)
{ {
if (volume == nullptr) return; if (volume == nullptr) return;
ObjectList * obj_list = wxGetApp().obj_list(); ObjectList *obj_list = wxGetApp().obj_list();
// select only actual volume // select only actual volume
// when new volume is created change selection to this volume // when new volume is created change selection to this volume
auto add_to_selection = [volume](const ModelVolume *vol) { auto add_to_selection = [volume](const ModelVolume *vol) {
return vol == volume; return vol == volume;
}; };
const Selection &selection = wxGetApp().plater()->canvas3D()->get_selection(); const Selection &selection =
wxGetApp().plater()->canvas3D()->get_selection();
wxDataViewItemArray sel = wxDataViewItemArray sel =
obj_list->reorder_volumes_and_get_selection(selection.get_object_idx(), obj_list->reorder_volumes_and_get_selection(selection.get_object_idx(),
add_to_selection); add_to_selection);

View File

@ -10,70 +10,93 @@
namespace Slic3r { namespace Slic3r {
class ModelVolume; class ModelVolume;
class ModelObject;
} }
namespace Slic3r::GUI { namespace Slic3r::GUI {
// thread process of conversion from text to model // inspired by Job.hpp
// [optionaly] union with model // All public function can be call only from UI thread
class EmbossJob : protected Job // Mechanism to stack processing and do only last one
template<typename TIn> class ReRunJob
{
std::mutex m_next_mutex;
std::unique_ptr<TIn> m_input_next = nullptr;
std::thread m_thread;
// indicate checking of new input.
std::atomic<bool> m_running{false};
using Func = std::function<void(std::unique_ptr<TIn>)>;
Func m_func;
public:
ReRunJob(Func func) : m_func(func) {}
virtual ~ReRunJob() { join(); }
void re_run(std::unique_ptr<TIn> input)
{
if (input == nullptr) return;
{
// keep access to next input
std::lock_guard lg(m_next_mutex);
if (is_running()) {
// when runnig
m_input_next = std::move(input);
return; // on end of run will be used new input
}
m_running.store(true);
}
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));
std::lock_guard lg(m_next_mutex);
// it is not in while condition because of lock guard
if (m_input_next == nullptr) {
m_running.store(false);
return;
}
input = std::move(m_input_next);
m_input_next = nullptr;
} while (true);
},
std::move(input));
} catch (std::exception &) {}
}
bool is_running() const { return m_running.load(); }
void join()
{
if (m_thread.joinable()) m_thread.join();
assert(!is_running());
}
};
struct EmbossData
{
// Pointer on Data of font (glyph shapes)
std::shared_ptr<Emboss::Font> font;
// font item is not used for create object
TextConfiguration text_configuration;
// new volume name created from text
std::string volume_name;
// when volume_ptr == nullptr than new volume will be created
ModelVolume *volume_ptr;
// when volume_ptr == nullptr && object_idx < 0 than new object will be created
int object_idx;
};
class EmbossJob : public ReRunJob<EmbossData>
{ {
public: public:
struct Data EmbossJob();
{
// Pointer on Data of font (glyph shapes)
std::shared_ptr<Emboss::Font> font;
// font item is not used for create object
TextConfiguration text_configuration;
// new volume name created from text
std::string volume_name;
// when volume_ptr == nullptr than new volume will be created
ModelVolume *volume_ptr;
// when volume_ptr == nullptr && object_idx < 0 than new object will be created
int object_idx;
};
EmbossJob();
~EmbossJob();// cancel work and join
void restart(const Data &data);
// do not allow Job::start
bool join(int timeout_ms = 0) { return Job::join(timeout_ms); };
bool is_running() const { return Job::is_running(); }
void cancel() { Job::cancel(); }
protected:
// Launched just before start(), a job can use it to prepare internals
virtual void prepare() override;
// The method where the actual work of the job should be defined.
virtual void process() override;
// Launched when the job is finished. It refreshes the 3Dscene by def.
virtual void finalize() override;
private:
std::optional<Data> m_data;
std::optional<indexed_triangle_set> m_result;
std::mutex m_mutex; // protect next data
std::optional<Data> m_data_next;
// TODO: move to objec list utils
void select_volume(ModelVolume * volume);
class Progress : public ProgressIndicator
{
// Inherited via ProgressIndicator
virtual void set_range(int range) override {}
virtual void set_cancel_callback(CancelFn = CancelFn()) override {}
virtual void set_progress(int pr) override {}
virtual void set_status_text(const char *) override {}
virtual int get_range() const override { return 100; }
};
}; };
} // namespace Slic3r::GUI } // namespace Slic3r::GUI
#endif // slic3r_EmbossJob_hpp_ #endif // slic3r_EmbossJob_hpp_