mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-16 08:35:58 +08:00
Using of Re run Job
This commit is contained in:
parent
2e41c8aafe
commit
43d200a7fb
@ -1743,7 +1743,7 @@ void ObjectList::load_shape_object_from_gallery(const wxArrayString& input_files
|
||||
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
|
||||
Model& model = wxGetApp().plater()->model();
|
||||
|
@ -257,7 +257,7 @@ public:
|
||||
void load_shape_object(const std::string &type_name);
|
||||
void load_shape_object_from_gallery();
|
||||
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_subobject_item(wxDataViewItem& item);
|
||||
void del_settings_from_config(const wxDataViewItem& parent_item);
|
||||
|
@ -472,14 +472,13 @@ bool GLGizmoEmboss::process()
|
||||
// exist loaded font?
|
||||
if (m_font == nullptr) return false;
|
||||
|
||||
|
||||
EmbossJob::Data data;
|
||||
data.font = m_font;
|
||||
data.text_configuration = create_configuration();
|
||||
data.volume_name = create_volume_name();
|
||||
data.volume_ptr = m_volume;
|
||||
data.object_idx = m_parent.get_selection().get_object_idx();
|
||||
m_job->restart(data);
|
||||
auto data = std::make_unique<EmbossData>();
|
||||
data->font = m_font;
|
||||
data->text_configuration = create_configuration();
|
||||
data->volume_name = create_volume_name();
|
||||
data->volume_ptr = m_volume;
|
||||
data->object_idx = m_parent.get_selection().get_object_idx();
|
||||
m_job->re_run(std::move(data));
|
||||
|
||||
// notification is removed befor object is changed by job
|
||||
remove_notification_not_valid_font();
|
||||
|
@ -13,108 +13,92 @@
|
||||
using namespace Slic3r;
|
||||
using namespace GUI;
|
||||
|
||||
//EmbossJob::EmbossJob(): Job(std::make_shared<NotificationProgressIndicator>(wxGetApp().plater()->get_notification_manager())){}
|
||||
EmbossJob::EmbossJob() : Job(std::make_shared<EmbossJob::Progress>()) {}
|
||||
namespace Priv {
|
||||
|
||||
EmbossJob::~EmbossJob() {
|
||||
Job::cancel();
|
||||
Job::join();
|
||||
}
|
||||
static void process(std::unique_ptr<EmbossData> input);
|
||||
static void finalize(const EmbossData &input, const indexed_triangle_set &result);
|
||||
|
||||
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()) {
|
||||
Job::cancel();
|
||||
std::lock_guard lk(m_mutex);
|
||||
bool create_restart = !m_data_next.has_value();
|
||||
m_data_next = data; // copy
|
||||
// only for sure
|
||||
assert(input != nullptr);
|
||||
|
||||
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
|
||||
if (m_data->font == nullptr) return;
|
||||
if (input->font == nullptr) return;
|
||||
|
||||
// Do NOT process empty string
|
||||
const TextConfiguration &cfg = m_data->text_configuration;
|
||||
const std::string &text = cfg.text;
|
||||
const TextConfiguration &cfg = input->text_configuration;
|
||||
const std::string & text = cfg.text;
|
||||
if (text.empty()) return;
|
||||
|
||||
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 ?
|
||||
// (no shape means that font hasn't any of text symbols)
|
||||
if (shapes.empty()) return;
|
||||
|
||||
float scale = prop.size_in_mm / m_data->font->ascent;
|
||||
auto project = std::make_unique<Emboss::ProjectScale>(
|
||||
std::make_unique<Emboss::ProjectZ>(prop.emboss / scale), scale);
|
||||
|
||||
indexed_triangle_set its = Emboss::polygons2model(shapes, *project);
|
||||
float scale = prop.size_in_mm / input->font->ascent;
|
||||
auto projectZ = std::make_unique<Emboss::ProjectZ>(prop.emboss / scale);
|
||||
Emboss::ProjectScale project(std::move(projectZ), scale);
|
||||
auto its = std::make_unique<indexed_triangle_set>(Emboss::polygons2model(shapes, project));
|
||||
|
||||
// for sure that some object is created from shape
|
||||
if (its.indices.empty()) return;
|
||||
m_result = its;
|
||||
if (its->indices.empty()) return;
|
||||
|
||||
// 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() {
|
||||
// check result was created
|
||||
if (!m_result.has_value()) return;
|
||||
if (m_result->indices.empty()) return;
|
||||
// move object data
|
||||
TriangleMesh tm(std::move(*m_result));
|
||||
m_result = {};
|
||||
|
||||
void Priv::finalize(const EmbossData &input, const indexed_triangle_set &result)
|
||||
{
|
||||
// it is sad, but there is no move constructor --> copy
|
||||
TriangleMesh tm(std::move(result));
|
||||
|
||||
// center triangle mesh
|
||||
Vec3d shift = tm.bounding_box().center();
|
||||
tm.translate(-shift.cast<float>());
|
||||
|
||||
GUI_App & app = wxGetApp();
|
||||
Plater * plater = app.plater();
|
||||
GLCanvas3D *canvas = plater->canvas3D();
|
||||
const std::string &name = m_data->volume_name;
|
||||
GUI_App & app = wxGetApp();
|
||||
Plater * plater = app.plater();
|
||||
GLCanvas3D * canvas = plater->canvas3D();
|
||||
const std::string &name = input.volume_name;
|
||||
|
||||
plater->take_snapshot(_L("Emboss text") + ": " + name);
|
||||
ModelVolume *volume = m_data->volume_ptr;
|
||||
ModelVolume *volume = input.volume_ptr;
|
||||
if (volume == nullptr) {
|
||||
// decide to add as volume or new object
|
||||
if (m_data->object_idx < 0) {
|
||||
// decide to add as volume or new object
|
||||
if (input.object_idx < 0) {
|
||||
// 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();
|
||||
|
||||
// TODO: find Why ???
|
||||
@ -127,9 +111,9 @@ void EmbossJob::finalize() {
|
||||
} else {
|
||||
// create new volume inside of object
|
||||
Model &model = plater->model();
|
||||
if (model.objects.size() <= m_data->object_idx) return;
|
||||
ModelObject *obj = model.objects[m_data->object_idx];
|
||||
volume = obj->add_volume(std::move(tm));
|
||||
if (model.objects.size() <= input.object_idx) return;
|
||||
ModelObject *obj = model.objects[input.object_idx];
|
||||
volume = obj->add_volume(std::move(tm));
|
||||
// set a default extruder value, since user can't add it manually
|
||||
volume->config.set_key_value("extruder", new ConfigOptionInt(0));
|
||||
}
|
||||
@ -141,8 +125,8 @@ void EmbossJob::finalize() {
|
||||
volume->get_object()->invalidate_bounding_box();
|
||||
}
|
||||
|
||||
volume->name = name;
|
||||
volume->text_configuration = m_data->text_configuration;
|
||||
volume->name = name;
|
||||
volume->text_configuration = input.text_configuration;
|
||||
|
||||
// update volume name in object list
|
||||
// updata selection after new volume added
|
||||
@ -153,18 +137,19 @@ void EmbossJob::finalize() {
|
||||
canvas->reload_scene(true);
|
||||
}
|
||||
|
||||
void EmbossJob::select_volume(ModelVolume *volume)
|
||||
{
|
||||
void Priv::select_volume(ModelVolume *volume)
|
||||
{
|
||||
if (volume == nullptr) return;
|
||||
|
||||
ObjectList * obj_list = wxGetApp().obj_list();
|
||||
|
||||
ObjectList *obj_list = wxGetApp().obj_list();
|
||||
|
||||
// select only actual volume
|
||||
// when new volume is created change selection to this volume
|
||||
auto add_to_selection = [volume](const ModelVolume *vol) {
|
||||
return vol == volume;
|
||||
};
|
||||
const Selection &selection = wxGetApp().plater()->canvas3D()->get_selection();
|
||||
const Selection &selection =
|
||||
wxGetApp().plater()->canvas3D()->get_selection();
|
||||
wxDataViewItemArray sel =
|
||||
obj_list->reorder_volumes_and_get_selection(selection.get_object_idx(),
|
||||
add_to_selection);
|
||||
|
@ -10,70 +10,93 @@
|
||||
|
||||
namespace Slic3r {
|
||||
class ModelVolume;
|
||||
class ModelObject;
|
||||
}
|
||||
|
||||
namespace Slic3r::GUI {
|
||||
|
||||
// thread process of conversion from text to model
|
||||
// [optionaly] union with model
|
||||
class EmbossJob : protected Job
|
||||
// inspired by Job.hpp
|
||||
// All public function can be call only from UI thread
|
||||
// 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:
|
||||
struct Data
|
||||
{
|
||||
// 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; }
|
||||
};
|
||||
EmbossJob();
|
||||
};
|
||||
|
||||
} // namespace Slic3r::GUI
|
||||
|
||||
#endif // slic3r_EmbossJob_hpp_
|
||||
|
Loading…
x
Reference in New Issue
Block a user