WIP FFF background slicing for a single object only.

This commit is contained in:
Vojtech Bubnik 2022-03-29 09:38:30 +02:00
parent 888f45c0d3
commit db5f70aa98
6 changed files with 147 additions and 123 deletions

View File

@ -45,7 +45,7 @@ namespace FillLightning {
// Print step IDs for keeping track of the print state.
// The Print steps are applied in this order.
enum PrintStep {
enum PrintStep : unsigned int {
psWipeTower,
// Ordering of the tools on PrintObjects for a multi-material print.
// psToolOrdering is a synonym to psWipeTower, as the Wipe Tower calculates and modifies the ToolOrdering,
@ -59,7 +59,7 @@ enum PrintStep {
psCount,
};
enum PrintObjectStep {
enum PrintObjectStep : unsigned int {
posSlice, posPerimeters, posPrepareInfill,
posInfill, posIroning, posSupportMaterial, posCount,
};
@ -350,6 +350,7 @@ public:
private:
// to be called from Print only.
friend class Print;
friend class PrintBaseWithState<PrintStep, psCount>;
PrintObject(Print* print, ModelObject* model_object, const Transform3d& trafo, PrintInstances&& instances);
~PrintObject() override {
@ -537,8 +538,10 @@ public:
std::vector<ObjectID> print_object_ids() const override;
ApplyStatus apply(const Model &model, DynamicPrintConfig config) override;
void set_task(const TaskParams &params) override { PrintBaseWithState<PrintStep, psCount>::set_task_impl(params, m_objects); }
void process() override;
void finalize() override { PrintBaseWithState<PrintStep, psCount>::finalize_impl(m_objects); }
// Exports G-code into a file name based on the path_template, returns the file path of the generated G-code file.
// If preview_data is not null, the preview_data is filled in for the G-code visualization (not used by the command line Slic3r).
std::string export_gcode(const std::string& path_template, GCodeProcessorResult* result, ThumbnailsGeneratorCallback thumbnail_cb = nullptr);

View File

@ -388,12 +388,12 @@ public:
int to_print_step;
};
// After calling the apply() function, call set_task() to limit the task to be processed by process().
virtual void set_task(const TaskParams &params) {}
virtual void set_task(const TaskParams &params) = 0;
// Perform the calculation. This is the only method that is to be called at a worker thread.
virtual void process() = 0;
// Clean up after process() finished, either with success, error or if canceled.
// The adjustments on the Print / PrintObject data due to set_task() are to be reverted here.
virtual void finalize() {}
virtual void finalize() = 0;
struct SlicingStatus {
SlicingStatus(int percent, const std::string &text, unsigned int flags = 0) : percent(percent), text(text), flags(flags) {}
@ -511,16 +511,21 @@ private:
friend PrintTryCancel;
};
template<typename PrintStepEnum, const size_t COUNT>
template<typename PrintStepEnumType, const size_t COUNT>
class PrintBaseWithState : public PrintBase
{
public:
using PrintStepEnum = PrintStepEnumType;
static constexpr const size_t PrintStepEnumSize = COUNT;
PrintBaseWithState() { m_stepmask.fill(true); }
bool is_step_done(PrintStepEnum step) const { return m_state.is_done(step, this->state_mutex()); }
PrintStateBase::StateWithTimeStamp step_state_with_timestamp(PrintStepEnum step) const { return m_state.state_with_timestamp(step, this->state_mutex()); }
PrintStateBase::StateWithWarnings step_state_with_warnings(PrintStepEnum step) const { return m_state.state_with_warnings(step, this->state_mutex()); }
protected:
bool set_started(PrintStepEnum step) { return m_state.set_started(step, this->state_mutex(), [this](){ this->throw_if_canceled(); }); }
bool set_started(PrintStepEnum step) { return m_stepmask[step] && m_state.set_started(step, this->state_mutex(), [this](){ this->throw_if_canceled(); }); }
PrintStateBase::TimeStamp set_done(PrintStepEnum step) {
std::pair<PrintStateBase::TimeStamp, bool> status = m_state.set_done(step, this->state_mutex(), [this](){ this->throw_if_canceled(); });
if (status.second)
@ -549,14 +554,118 @@ protected:
this->status_update_warnings(static_cast<int>(active_step.first), warning_level, message);
}
// After calling the apply() function, set_task() may be called to limit the task to be processed by process().
template<typename PrintObject>
void set_task_impl(const TaskParams &params, std::vector<PrintObject*> &print_objects)
{
// Grab the lock for the Print / PrintObject milestones.
std::scoped_lock<std::mutex> lock(this->state_mutex());
int n_object_steps = int(params.to_object_step) + 1;
if (n_object_steps == 0)
n_object_steps = int(PrintObject::PrintObjectStepEnumSize);
if (params.single_model_object.valid()) {
// Find the print object to be processed with priority.
PrintObject *print_object = nullptr;
size_t idx_print_object = 0;
for (; idx_print_object < print_objects.size(); ++ idx_print_object)
if (print_objects[idx_print_object]->model_object()->id() == params.single_model_object) {
print_object = print_objects[idx_print_object];
break;
}
assert(print_object != nullptr);
// Find out whether the priority print object is being currently processed.
bool running = false;
for (int istep = 0; istep < n_object_steps; ++ istep) {
if (! print_object->m_stepmask[size_t(istep)])
// Step was skipped, cancel.
break;
if (print_object->is_step_started_unguarded(
PrintObject::PrintObjectStepEnum(istep))) {
// No step was skipped, and a wanted step is being processed. Don't cancel.
running = true;
break;
}
}
if (! running)
this->call_cancel_callback();
// Now the background process is either stopped, or it is inside one of the print object steps to be calculated anyway.
if (params.single_model_instance_only) {
// Suppress all the steps of other instances.
for (PrintObject *po : print_objects)
for (size_t istep = 0; istep < PrintObject::PrintObjectStepEnumSize; ++ istep)
po->m_stepmask[istep] = false;
} else if (! running) {
// Swap the print objects, so that the selected print_object is first in the row.
// At this point the background processing must be stopped, so it is safe to shuffle print objects.
if (idx_print_object != 0)
std::swap(print_objects.front(), print_objects[idx_print_object]);
}
// and set the steps for the current object.
for (int istep = 0; istep < n_object_steps; ++ istep)
print_object->m_stepmask[size_t(istep)] = true;
for (int istep = n_object_steps; istep < int(PrintObject::PrintObjectStepEnumSize); ++ istep)
print_object->m_stepmask[size_t(istep)] = false;
} else {
// Slicing all objects.
bool running = false;
for (PrintObject *print_object : print_objects)
for (int istep = 0; istep < n_object_steps; ++ istep) {
if (! print_object->m_stepmask[size_t(istep)]) {
// Step may have been skipped. Restart.
goto loop_end;
}
if (print_object->is_step_started_unguarded(PrintObject::PrintObjectStepEnum(istep))) {
// This step is running, and the state cannot be changed due to the this->state_mutex() being locked.
// It is safe to manipulate m_stepmask of other PrintObjects and Print now.
running = true;
goto loop_end;
}
}
loop_end:
if (! running)
this->call_cancel_callback();
for (PrintObject *po : print_objects) {
for (int istep = 0; istep < n_object_steps; ++ istep)
po->m_stepmask[size_t(istep)] = true;
for (auto istep = size_t(n_object_steps); istep < PrintObject::PrintObjectStepEnumSize; ++ istep)
po->m_stepmask[istep] = false;
}
}
if (params.to_object_step != -1 || params.to_print_step != -1) {
// Limit the print steps.
size_t istep = (params.to_object_step != -1) ? 0 : size_t(params.to_print_step) + 1;
for (; istep < m_stepmask.size(); ++ istep)
m_stepmask[istep] = false;
}
}
// Clean up after process() finished, either with success, error or if canceled.
// The adjustments on the Print / PrintObject m_stepmask data due to set_task() are to be reverted here.
template<typename PrintObject>
void finalize_impl(std::vector<PrintObject*> &print_objects)
{
for (auto *po : print_objects)
po->m_stepmask.fill(true);
m_stepmask.fill(true);
}
private:
PrintState<PrintStepEnum, COUNT> m_state;
PrintState<PrintStepEnum, COUNT> m_state;
std::array<bool, PrintStepEnumSize> m_stepmask;
};
template<typename PrintType, typename PrintObjectStepEnum, const size_t COUNT>
template<typename PrintType, typename PrintObjectStepEnumType, const size_t COUNT>
class PrintObjectBaseWithState : public PrintObjectBase
{
public:
using PrintObjectStepEnum = PrintObjectStepEnumType;
static constexpr const size_t PrintObjectStepEnumSize = COUNT;
PrintType* print() { return m_print; }
const PrintType* print() const { return m_print; }
@ -566,10 +675,10 @@ public:
PrintStateBase::StateWithWarnings step_state_with_warnings(PrintObjectStepEnum step) const { return m_state.state_with_warnings(step, PrintObjectBase::state_mutex(m_print)); }
protected:
PrintObjectBaseWithState(PrintType *print, ModelObject *model_object) : PrintObjectBase(model_object), m_print(print) {}
PrintObjectBaseWithState(PrintType *print, ModelObject *model_object) : PrintObjectBase(model_object), m_print(print) { m_stepmask.fill(true); }
bool set_started(PrintObjectStepEnum step)
{ return m_state.set_started(step, PrintObjectBase::state_mutex(m_print), [this](){ this->throw_if_canceled(); }); }
{ return m_stepmask[step] && m_state.set_started(step, PrintObjectBase::state_mutex(m_print), [this](){ this->throw_if_canceled(); }); }
PrintStateBase::TimeStamp set_done(PrintObjectStepEnum step) {
std::pair<PrintStateBase::TimeStamp, bool> status = m_state.set_done(step, PrintObjectBase::state_mutex(m_print), [this](){ this->throw_if_canceled(); });
if (status.second)
@ -604,10 +713,11 @@ protected:
void throw_if_canceled() { if (m_print->canceled()) throw CanceledException(); }
friend PrintType;
PrintType *m_print;
PrintType *m_print;
std::array<bool, PrintObjectStepEnumSize> m_stepmask;
private:
PrintState<PrintObjectStepEnum, COUNT> m_state;
PrintState<PrintObjectStepEnum, COUNT> m_state;
};
} // namespace Slic3r

View File

@ -513,104 +513,6 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, DynamicPrintConfig con
return static_cast<ApplyStatus>(apply_status);
}
// After calling the apply() function, set_task() may be called to limit the task to be processed by process().
void SLAPrint::set_task(const TaskParams &params)
{
// Grab the lock for the Print / PrintObject milestones.
std::scoped_lock<std::mutex> lock(this->state_mutex());
int n_object_steps = int(params.to_object_step) + 1;
if (n_object_steps == 0)
n_object_steps = int(slaposCount);
if (params.single_model_object.valid()) {
// Find the print object to be processed with priority.
SLAPrintObject *print_object = nullptr;
size_t idx_print_object = 0;
for (; idx_print_object < m_objects.size(); ++ idx_print_object)
if (m_objects[idx_print_object]->model_object()->id() == params.single_model_object) {
print_object = m_objects[idx_print_object];
break;
}
assert(print_object != nullptr);
// Find out whether the priority print object is being currently processed.
bool running = false;
for (int istep = 0; istep < n_object_steps; ++ istep) {
if (! print_object->m_stepmask[size_t(istep)])
// Step was skipped, cancel.
break;
if (print_object->is_step_started_unguarded(SLAPrintObjectStep(istep))) {
// No step was skipped, and a wanted step is being processed. Don't cancel.
running = true;
break;
}
}
if (! running)
this->call_cancel_callback();
// Now the background process is either stopped, or it is inside one of the print object steps to be calculated anyway.
if (params.single_model_instance_only) {
// Suppress all the steps of other instances.
for (SLAPrintObject *po : m_objects)
for (size_t istep = 0; istep < slaposCount; ++ istep)
po->m_stepmask[istep] = false;
} else if (! running) {
// Swap the print objects, so that the selected print_object is first in the row.
// At this point the background processing must be stopped, so it is safe to shuffle print objects.
if (idx_print_object != 0)
std::swap(m_objects.front(), m_objects[idx_print_object]);
}
// and set the steps for the current object.
for (int istep = 0; istep < n_object_steps; ++ istep)
print_object->m_stepmask[size_t(istep)] = true;
for (int istep = n_object_steps; istep < int(slaposCount); ++ istep)
print_object->m_stepmask[size_t(istep)] = false;
} else {
// Slicing all objects.
bool running = false;
for (SLAPrintObject *print_object : m_objects)
for (int istep = 0; istep < n_object_steps; ++ istep) {
if (! print_object->m_stepmask[size_t(istep)]) {
// Step may have been skipped. Restart.
goto loop_end;
}
if (print_object->is_step_started_unguarded(SLAPrintObjectStep(istep))) {
// This step is running, and the state cannot be changed due to the this->state_mutex() being locked.
// It is safe to manipulate m_stepmask of other SLAPrintObjects and SLAPrint now.
running = true;
goto loop_end;
}
}
loop_end:
if (! running)
this->call_cancel_callback();
for (SLAPrintObject *po : m_objects) {
for (int istep = 0; istep < n_object_steps; ++ istep)
po->m_stepmask[size_t(istep)] = true;
for (auto istep = size_t(n_object_steps); istep < slaposCount; ++ istep)
po->m_stepmask[istep] = false;
}
}
if (params.to_object_step != -1 || params.to_print_step != -1) {
// Limit the print steps.
size_t istep = (params.to_object_step != -1) ? 0 : size_t(params.to_print_step) + 1;
for (; istep < m_stepmask.size(); ++ istep)
m_stepmask[istep] = false;
}
}
// Clean up after process() finished, either with success, error or if canceled.
// The adjustments on the SLAPrint / SLAPrintObject data due to set_task() are to be reverted here.
void SLAPrint::finalize()
{
for (SLAPrintObject *po : m_objects)
for (size_t istep = 0; istep < slaposCount; ++ istep)
po->m_stepmask[istep] = true;
for (size_t istep = 0; istep < slapsCount; ++ istep)
m_stepmask[istep] = true;
}
// Generate a recommended output file name based on the format template, default extension, and template parameters
// (timestamps, object placeholders derived from the model, current placeholder prameters and print statistics.
// Use the final print statistics if available, or just keep the print statistics placeholders if not available yet (before the output is finalized).
@ -741,7 +643,7 @@ void SLAPrint::process()
st += incr;
if (po->m_stepmask[step] && po->set_started(step)) {
if (po->set_started(step)) {
m_report_status(*this, st, printsteps.label(step));
bench.start();
printsteps.execute(step, *po);
@ -766,7 +668,7 @@ void SLAPrint::process()
for(SLAPrintStep currentstep : print_steps) {
throw_if_canceled();
if (m_stepmask[currentstep] && set_started(currentstep)) {
if (set_started(currentstep)) {
m_report_status(*this, st, printsteps.label(currentstep));
bench.start();
printsteps.execute(currentstep);
@ -898,7 +800,6 @@ bool SLAPrint::is_step_done(SLAPrintObjectStep step) const
SLAPrintObject::SLAPrintObject(SLAPrint *print, ModelObject *model_object)
: Inherited(print, model_object)
, m_stepmask(slaposCount, true)
, m_transformed_rmesh([this](TriangleMesh &obj) {
obj = m_model_object->raw_mesh();
if (!obj.empty()) {

View File

@ -265,6 +265,7 @@ public:
protected:
// to be called from SLAPrint only.
friend class SLAPrint;
friend class PrintBaseWithState<SLAPrintStep, slapsCount>;
SLAPrintObject(SLAPrint* print, ModelObject* model_object);
~SLAPrintObject();
@ -285,10 +286,6 @@ protected:
// Invalidate steps based on a set of parameters changed.
bool invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys);
// Which steps have to be performed. Implicitly: all
// to be accessible from SLAPrint
std::vector<bool> m_stepmask;
private:
// Object specific configuration, pulled from the configuration layer.
SLAPrintObjectConfig m_config;
@ -408,7 +405,7 @@ private: // Prevents erroneous use by other classes.
public:
SLAPrint(): m_stepmask(slapsCount, true) {}
SLAPrint() = default;
virtual ~SLAPrint() override { this->clear(); }
@ -419,9 +416,9 @@ public:
// List of existing PrintObject IDs, to remove notifications for non-existent IDs.
std::vector<ObjectID> print_object_ids() const override;
ApplyStatus apply(const Model &model, DynamicPrintConfig config) override;
void set_task(const TaskParams &params) override;
void set_task(const TaskParams &params) override { PrintBaseWithState<SLAPrintStep, slapsCount>::set_task_impl(params, m_objects); }
void process() override;
void finalize() override;
void finalize() override { PrintBaseWithState<SLAPrintStep, slapsCount>::finalize_impl(m_objects); }
// Returns true if an object step is done on all objects and there's at least one object.
bool is_step_done(SLAPrintObjectStep step) const;
// Returns true if the last step was finished with success.
@ -522,7 +519,6 @@ private:
SLAPrintObjectConfig m_default_object_config;
PrintObjects m_objects;
std::vector<bool> m_stepmask;
// Ready-made data for rasterization.
std::vector<PrintLayer> m_printer_input;

View File

@ -6269,7 +6269,7 @@ void Plater::reslice_SLA_hollowing(const ModelObject &object, bool postpone_erro
reslice_SLA_until_step(slaposDrillHoles, object, postpone_error_messages);
}
void Plater::reslice_SLA_until_step(SLAPrintObjectStep step, const ModelObject &object, bool postpone_error_messages)
void Plater::reslice_until_step_inner(int step, const ModelObject &object, bool postpone_error_messages)
{
//FIXME Don't reslice if export of G-code or sending to OctoPrint is running.
// bitmask of UpdateBackgroundProcessReturnState
@ -6295,6 +6295,16 @@ void Plater::reslice_SLA_until_step(SLAPrintObjectStep step, const ModelObject &
this->p->restart_background_process(state | priv::UPDATE_BACKGROUND_PROCESS_FORCE_RESTART);
}
void Plater::reslice_FFF_until_step(PrintObjectStep step, const ModelObject &object, bool postpone_error_messages)
{
this->reslice_until_step_inner(PrintObjectStep(step), object, postpone_error_messages);
}
void Plater::reslice_SLA_until_step(SLAPrintObjectStep step, const ModelObject &object, bool postpone_error_messages)
{
this->reslice_until_step_inner(SLAPrintObjectStep(step), object, postpone_error_messages);
}
void Plater::send_gcode()
{
// if physical_printer is selected, send gcode for this printer

View File

@ -32,6 +32,7 @@ using ModelObjectCutAttributes = enum_bitmask<ModelObjectCutAttribute>;
class ModelInstance;
class Print;
class SLAPrint;
enum PrintObjectStep : unsigned int;
enum SLAPrintObjectStep : unsigned int;
enum class ConversionType : int;
@ -265,6 +266,7 @@ public:
bool has_toolpaths_to_export() const;
void export_toolpaths_to_obj() const;
void reslice();
void reslice_FFF_until_step(PrintObjectStep step, const ModelObject &object, bool postpone_error_messages = false);
void reslice_SLA_supports(const ModelObject &object, bool postpone_error_messages = false);
void reslice_SLA_hollowing(const ModelObject &object, bool postpone_error_messages = false);
void reslice_SLA_until_step(SLAPrintObjectStep step, const ModelObject &object, bool postpone_error_messages = false);
@ -477,6 +479,8 @@ public:
static void show_illegal_characters_warning(wxWindow* parent);
private:
void reslice_until_step_inner(int step, const ModelObject &object, bool postpone_error_messages);
struct priv;
std::unique_ptr<priv> p;