mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-16 15:35:55 +08:00
Merge branch 'master' into fs_emboss
This commit is contained in:
commit
4acdd76fff
@ -363,7 +363,7 @@ namespace Slic3r {
|
|||||||
// All G1 commands should be translated and rotated. X and Y coords are
|
// All G1 commands should be translated and rotated. X and Y coords are
|
||||||
// only pushed to the output when they differ from last time.
|
// only pushed to the output when they differ from last time.
|
||||||
// WT generator can override this by appending the never_skip_tag
|
// WT generator can override this by appending the never_skip_tag
|
||||||
if (line.find("G1 ") == 0) {
|
if (boost::starts_with(line, "G1 ")) {
|
||||||
bool never_skip = false;
|
bool never_skip = false;
|
||||||
auto it = line.find(WipeTower::never_skip_tag());
|
auto it = line.find(WipeTower::never_skip_tag());
|
||||||
if (it != std::string::npos) {
|
if (it != std::string::npos) {
|
||||||
@ -375,6 +375,7 @@ namespace Slic3r {
|
|||||||
std::istringstream line_str(line);
|
std::istringstream line_str(line);
|
||||||
line_str >> std::noskipws; // don't skip whitespace
|
line_str >> std::noskipws; // don't skip whitespace
|
||||||
char ch = 0;
|
char ch = 0;
|
||||||
|
line_str >> ch >> ch; // read the "G1"
|
||||||
while (line_str >> ch) {
|
while (line_str >> ch) {
|
||||||
if (ch == 'X' || ch == 'Y')
|
if (ch == 'X' || ch == 'Y')
|
||||||
line_str >> (ch == 'X' ? pos.x() : pos.y());
|
line_str >> (ch == 'X' ? pos.x() : pos.y());
|
||||||
@ -386,14 +387,16 @@ namespace Slic3r {
|
|||||||
|
|
||||||
if (transformed_pos != old_pos || never_skip) {
|
if (transformed_pos != old_pos || never_skip) {
|
||||||
line = line_out.str();
|
line = line_out.str();
|
||||||
|
boost::trim_left(line); // Remove leading spaces
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << std::fixed << std::setprecision(3) << "G1 ";
|
oss << std::fixed << std::setprecision(3) << "G1";
|
||||||
if (transformed_pos.x() != old_pos.x() || never_skip)
|
if (transformed_pos.x() != old_pos.x() || never_skip)
|
||||||
oss << " X" << transformed_pos.x() - extruder_offset.x();
|
oss << " X" << transformed_pos.x() - extruder_offset.x();
|
||||||
if (transformed_pos.y() != old_pos.y() || never_skip)
|
if (transformed_pos.y() != old_pos.y() || never_skip)
|
||||||
oss << " Y" << transformed_pos.y() - extruder_offset.y();
|
oss << " Y" << transformed_pos.y() - extruder_offset.y();
|
||||||
oss << " ";
|
if (! line.empty())
|
||||||
line.replace(line.find("G1 "), 3, oss.str());
|
oss << " ";
|
||||||
|
line = oss.str() + line;
|
||||||
old_pos = transformed_pos;
|
old_pos = transformed_pos;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -444,7 +447,7 @@ namespace Slic3r {
|
|||||||
bool ignore_sparse = false;
|
bool ignore_sparse = false;
|
||||||
if (gcodegen.config().wipe_tower_no_sparse_layers.value) {
|
if (gcodegen.config().wipe_tower_no_sparse_layers.value) {
|
||||||
wipe_tower_z = m_last_wipe_tower_print_z;
|
wipe_tower_z = m_last_wipe_tower_print_z;
|
||||||
ignore_sparse = (m_tool_changes[m_layer_idx].size() == 1 && m_tool_changes[m_layer_idx].front().initial_tool == m_tool_changes[m_layer_idx].front().new_tool);
|
ignore_sparse = (m_tool_changes[m_layer_idx].size() == 1 && m_tool_changes[m_layer_idx].front().initial_tool == m_tool_changes[m_layer_idx].front().new_tool && m_layer_idx != 0);
|
||||||
if (m_tool_change_idx == 0 && !ignore_sparse)
|
if (m_tool_change_idx == 0 && !ignore_sparse)
|
||||||
wipe_tower_z = m_last_wipe_tower_print_z + m_tool_changes[m_layer_idx].front().layer_height;
|
wipe_tower_z = m_last_wipe_tower_print_z + m_tool_changes[m_layer_idx].front().layer_height;
|
||||||
}
|
}
|
||||||
@ -736,9 +739,13 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* resu
|
|||||||
CNumericLocalesSetter locales_setter;
|
CNumericLocalesSetter locales_setter;
|
||||||
|
|
||||||
// Does the file exist? If so, we hope that it is still valid.
|
// Does the file exist? If so, we hope that it is still valid.
|
||||||
if (print->is_step_done(psGCodeExport) && boost::filesystem::exists(boost::filesystem::path(path)))
|
{
|
||||||
return;
|
PrintStateBase::StateWithTimeStamp state = print->step_state_with_timestamp(psGCodeExport);
|
||||||
|
if (! state.enabled || (state.state == PrintStateBase::DONE && boost::filesystem::exists(boost::filesystem::path(path))))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enabled and either not done, or marked as done while the output file is missing.
|
||||||
print->set_started(psGCodeExport);
|
print->set_started(psGCodeExport);
|
||||||
|
|
||||||
// check if any custom gcode contains keywords used by the gcode processor to
|
// check if any custom gcode contains keywords used by the gcode processor to
|
||||||
|
@ -1180,7 +1180,7 @@ WipeTower::ToolChangeResult WipeTower::finish_layer()
|
|||||||
|
|
||||||
// Ask our writer about how much material was consumed.
|
// Ask our writer about how much material was consumed.
|
||||||
// Skip this in case the layer is sparse and config option to not print sparse layers is enabled.
|
// Skip this in case the layer is sparse and config option to not print sparse layers is enabled.
|
||||||
if (! m_no_sparse_layers || toolchanges_on_layer)
|
if (! m_no_sparse_layers || toolchanges_on_layer || first_layer)
|
||||||
if (m_current_tool < m_used_filament_length.size())
|
if (m_current_tool < m_used_filament_length.size())
|
||||||
m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length();
|
m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length();
|
||||||
|
|
||||||
@ -1196,7 +1196,7 @@ void WipeTower::plan_toolchange(float z_par, float layer_height_par, unsigned in
|
|||||||
if (m_plan.empty() || m_plan.back().z + WT_EPSILON < z_par) // if we moved to a new layer, we'll add it to m_plan first
|
if (m_plan.empty() || m_plan.back().z + WT_EPSILON < z_par) // if we moved to a new layer, we'll add it to m_plan first
|
||||||
m_plan.push_back(WipeTowerInfo(z_par, layer_height_par));
|
m_plan.push_back(WipeTowerInfo(z_par, layer_height_par));
|
||||||
|
|
||||||
if (m_first_layer_idx == size_t(-1) && (! m_no_sparse_layers || old_tool != new_tool))
|
if (m_first_layer_idx == size_t(-1) && (! m_no_sparse_layers || old_tool != new_tool || m_plan.size() == 1))
|
||||||
m_first_layer_idx = m_plan.size() - 1;
|
m_first_layer_idx = m_plan.size() - 1;
|
||||||
|
|
||||||
if (old_tool == new_tool) // new layer without toolchanges - we are done
|
if (old_tool == new_tool) // new layer without toolchanges - we are done
|
||||||
|
@ -45,7 +45,7 @@ namespace FillLightning {
|
|||||||
|
|
||||||
// Print step IDs for keeping track of the print state.
|
// Print step IDs for keeping track of the print state.
|
||||||
// The Print steps are applied in this order.
|
// The Print steps are applied in this order.
|
||||||
enum PrintStep {
|
enum PrintStep : unsigned int {
|
||||||
psWipeTower,
|
psWipeTower,
|
||||||
// Ordering of the tools on PrintObjects for a multi-material print.
|
// 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,
|
// psToolOrdering is a synonym to psWipeTower, as the Wipe Tower calculates and modifies the ToolOrdering,
|
||||||
@ -59,7 +59,7 @@ enum PrintStep {
|
|||||||
psCount,
|
psCount,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum PrintObjectStep {
|
enum PrintObjectStep : unsigned int {
|
||||||
posSlice, posPerimeters, posPrepareInfill,
|
posSlice, posPerimeters, posPrepareInfill,
|
||||||
posInfill, posIroning, posSupportMaterial, posCount,
|
posInfill, posIroning, posSupportMaterial, posCount,
|
||||||
};
|
};
|
||||||
@ -350,6 +350,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
// to be called from Print only.
|
// to be called from Print only.
|
||||||
friend class Print;
|
friend class Print;
|
||||||
|
friend class PrintBaseWithState<PrintStep, psCount>;
|
||||||
|
|
||||||
PrintObject(Print* print, ModelObject* model_object, const Transform3d& trafo, PrintInstances&& instances);
|
PrintObject(Print* print, ModelObject* model_object, const Transform3d& trafo, PrintInstances&& instances);
|
||||||
~PrintObject() override {
|
~PrintObject() override {
|
||||||
@ -537,8 +538,10 @@ public:
|
|||||||
std::vector<ObjectID> print_object_ids() const override;
|
std::vector<ObjectID> print_object_ids() const override;
|
||||||
|
|
||||||
ApplyStatus apply(const Model &model, DynamicPrintConfig config) override;
|
ApplyStatus apply(const Model &model, DynamicPrintConfig config) override;
|
||||||
|
void set_task(const TaskParams ¶ms) override { PrintBaseWithState<PrintStep, psCount>::set_task_impl(params, m_objects); }
|
||||||
void process() override;
|
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.
|
// 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).
|
// 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);
|
std::string export_gcode(const std::string& path_template, GCodeProcessorResult* result, ThumbnailsGeneratorCallback thumbnail_cb = nullptr);
|
||||||
|
@ -39,9 +39,9 @@ public:
|
|||||||
// A new unique timestamp is being assigned to the step every time the step changes its state.
|
// A new unique timestamp is being assigned to the step every time the step changes its state.
|
||||||
struct StateWithTimeStamp
|
struct StateWithTimeStamp
|
||||||
{
|
{
|
||||||
StateWithTimeStamp() : state(INVALID), timestamp(0) {}
|
State state { INVALID };
|
||||||
State state;
|
TimeStamp timestamp { 0 };
|
||||||
TimeStamp timestamp;
|
bool enabled { true };
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Warning
|
struct Warning
|
||||||
@ -112,10 +112,24 @@ public:
|
|||||||
return this->state_with_timestamp_unguarded(step).state == DONE;
|
return this->state_with_timestamp_unguarded(step).state == DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void enable_unguarded(StepType step, bool enable) {
|
||||||
|
m_state[step].enabled = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
void enable_all_unguarded(bool enable) {
|
||||||
|
for (size_t istep = 0; istep < COUNT; ++ istep)
|
||||||
|
m_state[istep].enabled = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_enabled_unguarded(StepType step) const {
|
||||||
|
return this->state_with_timestamp_unguarded(step).enabled;
|
||||||
|
}
|
||||||
|
|
||||||
// Set the step as started. Block on mutex while the Print / PrintObject / PrintRegion objects are being
|
// Set the step as started. Block on mutex while the Print / PrintObject / PrintRegion objects are being
|
||||||
// modified by the UI thread.
|
// modified by the UI thread.
|
||||||
// This is necessary to block until the Print::apply() updates its state, which may
|
// This is necessary to block until the Print::apply() updates its state, which may
|
||||||
// influence the processing step being entered.
|
// influence the processing step being entered.
|
||||||
|
// Returns false if the step is not enabled or if the step has already been finished (it is done).
|
||||||
template<typename ThrowIfCanceled>
|
template<typename ThrowIfCanceled>
|
||||||
bool set_started(StepType step, std::mutex &mtx, ThrowIfCanceled throw_if_canceled) {
|
bool set_started(StepType step, std::mutex &mtx, ThrowIfCanceled throw_if_canceled) {
|
||||||
std::scoped_lock<std::mutex> lock(mtx);
|
std::scoped_lock<std::mutex> lock(mtx);
|
||||||
@ -134,9 +148,9 @@ public:
|
|||||||
// for (int i = 0; i < int(COUNT); ++ i)
|
// for (int i = 0; i < int(COUNT); ++ i)
|
||||||
// assert(m_state[i].state != STARTED);
|
// assert(m_state[i].state != STARTED);
|
||||||
#endif // NDEBUG
|
#endif // NDEBUG
|
||||||
if (m_state[step].state == DONE)
|
|
||||||
return false;
|
|
||||||
PrintStateBase::StateWithWarnings &state = m_state[step];
|
PrintStateBase::StateWithWarnings &state = m_state[step];
|
||||||
|
if (! state.enabled || state.state == DONE)
|
||||||
|
return false;
|
||||||
state.state = STARTED;
|
state.state = STARTED;
|
||||||
state.timestamp = ++ g_last_timestamp;
|
state.timestamp = ++ g_last_timestamp;
|
||||||
state.mark_warnings_non_current();
|
state.mark_warnings_non_current();
|
||||||
@ -388,12 +402,12 @@ public:
|
|||||||
int to_print_step;
|
int to_print_step;
|
||||||
};
|
};
|
||||||
// After calling the apply() function, call set_task() to limit the task to be processed by process().
|
// After calling the apply() function, call set_task() to limit the task to be processed by process().
|
||||||
virtual void set_task(const TaskParams ¶ms) {}
|
virtual void set_task(const TaskParams ¶ms) = 0;
|
||||||
// Perform the calculation. This is the only method that is to be called at a worker thread.
|
// Perform the calculation. This is the only method that is to be called at a worker thread.
|
||||||
virtual void process() = 0;
|
virtual void process() = 0;
|
||||||
// Clean up after process() finished, either with success, error or if canceled.
|
// 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.
|
// 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 {
|
struct SlicingStatus {
|
||||||
SlicingStatus(int percent, const std::string &text, unsigned int flags = 0) : percent(percent), text(text), flags(flags) {}
|
SlicingStatus(int percent, const std::string &text, unsigned int flags = 0) : percent(percent), text(text), flags(flags) {}
|
||||||
@ -511,10 +525,15 @@ private:
|
|||||||
friend PrintTryCancel;
|
friend PrintTryCancel;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename PrintStepEnum, const size_t COUNT>
|
template<typename PrintStepEnumType, const size_t COUNT>
|
||||||
class PrintBaseWithState : public PrintBase
|
class PrintBaseWithState : public PrintBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
using PrintStepEnum = PrintStepEnumType;
|
||||||
|
static constexpr const size_t PrintStepEnumSize = COUNT;
|
||||||
|
|
||||||
|
PrintBaseWithState() = default;
|
||||||
|
|
||||||
bool is_step_done(PrintStepEnum step) const { return m_state.is_done(step, this->state_mutex()); }
|
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::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()); }
|
PrintStateBase::StateWithWarnings step_state_with_warnings(PrintStepEnum step) const { return m_state.state_with_warnings(step, this->state_mutex()); }
|
||||||
@ -549,14 +568,120 @@ protected:
|
|||||||
this->status_update_warnings(static_cast<int>(active_step.first), warning_level, message);
|
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 ¶ms, std::vector<PrintObject*> &print_objects)
|
||||||
|
{
|
||||||
|
static constexpr const auto PrintObjectStepEnumSize = int(PrintObject::PrintObjectStepEnumSize);
|
||||||
|
using PrintObjectStepEnum = typename PrintObject::PrintObjectStepEnum;
|
||||||
|
// 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 = 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->is_step_enabled_unguarded(PrintObjectStepEnum(istep)))
|
||||||
|
// Step was skipped, cancel.
|
||||||
|
break;
|
||||||
|
if (print_object->is_step_started_unguarded(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 < PrintObjectStepEnumSize; ++ istep)
|
||||||
|
po->enable_step_unguarded(PrintObjectStepEnum(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->enable_step_unguarded(PrintObjectStepEnum(istep), true);
|
||||||
|
for (int istep = n_object_steps; istep < PrintObjectStepEnumSize; ++ istep)
|
||||||
|
print_object->enable_step_unguarded(PrintObjectStepEnum(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->is_step_enabled_unguarded(PrintObjectStepEnum(istep))) {
|
||||||
|
// Step may have been skipped. Restart.
|
||||||
|
goto loop_end;
|
||||||
|
}
|
||||||
|
if (print_object->is_step_started_unguarded(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->enable_step_unguarded(PrintObjectStepEnum(istep), true);
|
||||||
|
for (int istep = n_object_steps; istep < PrintObjectStepEnumSize; ++ istep)
|
||||||
|
po->enable_step_unguarded(PrintObjectStepEnum(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 < PrintStepEnumSize; ++ istep)
|
||||||
|
m_state.enable_unguarded(PrintStepEnum(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)
|
||||||
|
{
|
||||||
|
// Grab the lock for the Print / PrintObject milestones.
|
||||||
|
std::scoped_lock<std::mutex> lock(this->state_mutex());
|
||||||
|
for (auto *po : print_objects)
|
||||||
|
po->enable_all_steps_unguarded(true);
|
||||||
|
m_state.enable_all_unguarded(true);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PrintState<PrintStepEnum, COUNT> m_state;
|
PrintState<PrintStepEnum, COUNT> m_state;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename PrintType, typename PrintObjectStepEnum, const size_t COUNT>
|
template<typename PrintType, typename PrintObjectStepEnumType, const size_t COUNT>
|
||||||
class PrintObjectBaseWithState : public PrintObjectBase
|
class PrintObjectBaseWithState : public PrintObjectBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
using PrintObjectStepEnum = PrintObjectStepEnumType;
|
||||||
|
static constexpr const size_t PrintObjectStepEnumSize = COUNT;
|
||||||
|
|
||||||
PrintType* print() { return m_print; }
|
PrintType* print() { return m_print; }
|
||||||
const PrintType* print() const { return m_print; }
|
const PrintType* print() const { return m_print; }
|
||||||
|
|
||||||
@ -590,6 +715,10 @@ protected:
|
|||||||
bool is_step_started_unguarded(PrintObjectStepEnum step) const { return m_state.is_started_unguarded(step); }
|
bool is_step_started_unguarded(PrintObjectStepEnum step) const { return m_state.is_started_unguarded(step); }
|
||||||
bool is_step_done_unguarded(PrintObjectStepEnum step) const { return m_state.is_done_unguarded(step); }
|
bool is_step_done_unguarded(PrintObjectStepEnum step) const { return m_state.is_done_unguarded(step); }
|
||||||
|
|
||||||
|
bool is_step_enabled_unguarded(PrintObjectStepEnum step) const { return m_state.is_enabled_unguarded(step); }
|
||||||
|
void enable_step_unguarded(PrintObjectStepEnum step, bool enable) { m_state.enable_unguarded(step, enable); }
|
||||||
|
void enable_all_steps_unguarded(bool enable) { m_state.enable_all_unguarded(enable); }
|
||||||
|
|
||||||
// Add a slicing warning to the active PrintObject step and send a status notification.
|
// Add a slicing warning to the active PrintObject step and send a status notification.
|
||||||
// This method could be called multiple times between this->set_started() and this->set_done().
|
// This method could be called multiple times between this->set_started() and this->set_done().
|
||||||
void active_step_add_warning(PrintStateBase::WarningLevel warning_level, const std::string &message, int message_id = 0) {
|
void active_step_add_warning(PrintStateBase::WarningLevel warning_level, const std::string &message, int message_id = 0) {
|
||||||
@ -604,10 +733,10 @@ protected:
|
|||||||
void throw_if_canceled() { if (m_print->canceled()) throw CanceledException(); }
|
void throw_if_canceled() { if (m_print->canceled()) throw CanceledException(); }
|
||||||
|
|
||||||
friend PrintType;
|
friend PrintType;
|
||||||
PrintType *m_print;
|
PrintType *m_print;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PrintState<PrintObjectStepEnum, COUNT> m_state;
|
PrintState<PrintObjectStepEnum, COUNT> m_state;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
@ -513,104 +513,6 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, DynamicPrintConfig con
|
|||||||
return static_cast<ApplyStatus>(apply_status);
|
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 ¶ms)
|
|
||||||
{
|
|
||||||
// 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
|
// 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.
|
// (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).
|
// 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;
|
st += incr;
|
||||||
|
|
||||||
if (po->m_stepmask[step] && po->set_started(step)) {
|
if (po->set_started(step)) {
|
||||||
m_report_status(*this, st, printsteps.label(step));
|
m_report_status(*this, st, printsteps.label(step));
|
||||||
bench.start();
|
bench.start();
|
||||||
printsteps.execute(step, *po);
|
printsteps.execute(step, *po);
|
||||||
@ -759,14 +661,11 @@ void SLAPrint::process()
|
|||||||
apply_steps_on_objects(level1_obj_steps);
|
apply_steps_on_objects(level1_obj_steps);
|
||||||
apply_steps_on_objects(level2_obj_steps);
|
apply_steps_on_objects(level2_obj_steps);
|
||||||
|
|
||||||
// this would disable the rasterization step
|
|
||||||
// std::fill(m_stepmask.begin(), m_stepmask.end(), false);
|
|
||||||
|
|
||||||
st = Steps::max_objstatus;
|
st = Steps::max_objstatus;
|
||||||
for(SLAPrintStep currentstep : print_steps) {
|
for(SLAPrintStep currentstep : print_steps) {
|
||||||
throw_if_canceled();
|
throw_if_canceled();
|
||||||
|
|
||||||
if (m_stepmask[currentstep] && set_started(currentstep)) {
|
if (set_started(currentstep)) {
|
||||||
m_report_status(*this, st, printsteps.label(currentstep));
|
m_report_status(*this, st, printsteps.label(currentstep));
|
||||||
bench.start();
|
bench.start();
|
||||||
printsteps.execute(currentstep);
|
printsteps.execute(currentstep);
|
||||||
@ -898,7 +797,6 @@ bool SLAPrint::is_step_done(SLAPrintObjectStep step) const
|
|||||||
|
|
||||||
SLAPrintObject::SLAPrintObject(SLAPrint *print, ModelObject *model_object)
|
SLAPrintObject::SLAPrintObject(SLAPrint *print, ModelObject *model_object)
|
||||||
: Inherited(print, model_object)
|
: Inherited(print, model_object)
|
||||||
, m_stepmask(slaposCount, true)
|
|
||||||
, m_transformed_rmesh([this](TriangleMesh &obj) {
|
, m_transformed_rmesh([this](TriangleMesh &obj) {
|
||||||
obj = m_model_object->raw_mesh();
|
obj = m_model_object->raw_mesh();
|
||||||
if (!obj.empty()) {
|
if (!obj.empty()) {
|
||||||
|
@ -265,6 +265,7 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
// to be called from SLAPrint only.
|
// to be called from SLAPrint only.
|
||||||
friend class SLAPrint;
|
friend class SLAPrint;
|
||||||
|
friend class PrintBaseWithState<SLAPrintStep, slapsCount>;
|
||||||
|
|
||||||
SLAPrintObject(SLAPrint* print, ModelObject* model_object);
|
SLAPrintObject(SLAPrint* print, ModelObject* model_object);
|
||||||
~SLAPrintObject();
|
~SLAPrintObject();
|
||||||
@ -285,10 +286,6 @@ protected:
|
|||||||
// Invalidate steps based on a set of parameters changed.
|
// Invalidate steps based on a set of parameters changed.
|
||||||
bool invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys);
|
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:
|
private:
|
||||||
// Object specific configuration, pulled from the configuration layer.
|
// Object specific configuration, pulled from the configuration layer.
|
||||||
SLAPrintObjectConfig m_config;
|
SLAPrintObjectConfig m_config;
|
||||||
@ -408,7 +405,7 @@ private: // Prevents erroneous use by other classes.
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
SLAPrint(): m_stepmask(slapsCount, true) {}
|
SLAPrint() = default;
|
||||||
|
|
||||||
virtual ~SLAPrint() override { this->clear(); }
|
virtual ~SLAPrint() override { this->clear(); }
|
||||||
|
|
||||||
@ -419,9 +416,9 @@ public:
|
|||||||
// List of existing PrintObject IDs, to remove notifications for non-existent IDs.
|
// List of existing PrintObject IDs, to remove notifications for non-existent IDs.
|
||||||
std::vector<ObjectID> print_object_ids() const override;
|
std::vector<ObjectID> print_object_ids() const override;
|
||||||
ApplyStatus apply(const Model &model, DynamicPrintConfig config) override;
|
ApplyStatus apply(const Model &model, DynamicPrintConfig config) override;
|
||||||
void set_task(const TaskParams ¶ms) override;
|
void set_task(const TaskParams ¶ms) override { PrintBaseWithState<SLAPrintStep, slapsCount>::set_task_impl(params, m_objects); }
|
||||||
void process() override;
|
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.
|
// 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;
|
bool is_step_done(SLAPrintObjectStep step) const;
|
||||||
// Returns true if the last step was finished with success.
|
// Returns true if the last step was finished with success.
|
||||||
@ -522,7 +519,6 @@ private:
|
|||||||
SLAPrintObjectConfig m_default_object_config;
|
SLAPrintObjectConfig m_default_object_config;
|
||||||
|
|
||||||
PrintObjects m_objects;
|
PrintObjects m_objects;
|
||||||
std::vector<bool> m_stepmask;
|
|
||||||
|
|
||||||
// Ready-made data for rasterization.
|
// Ready-made data for rasterization.
|
||||||
std::vector<PrintLayer> m_printer_input;
|
std::vector<PrintLayer> m_printer_input;
|
||||||
|
@ -2630,7 +2630,7 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool
|
|||||||
|
|
||||||
// gets the vertex index from the index buffer on gpu
|
// gets the vertex index from the index buffer on gpu
|
||||||
const IBuffer& i_buffer = buffer.indices[sub_path.first.b_id];
|
const IBuffer& i_buffer = buffer.indices[sub_path.first.b_id];
|
||||||
unsigned int index = 0;
|
IBufferType index = 0;
|
||||||
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, i_buffer.ibo));
|
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, i_buffer.ibo));
|
||||||
glsafe(::glGetBufferSubData(GL_ELEMENT_ARRAY_BUFFER, static_cast<GLintptr>(offset * sizeof(IBufferType)), static_cast<GLsizeiptr>(sizeof(IBufferType)), static_cast<void*>(&index)));
|
glsafe(::glGetBufferSubData(GL_ELEMENT_ARRAY_BUFFER, static_cast<GLintptr>(offset * sizeof(IBufferType)), static_cast<GLsizeiptr>(sizeof(IBufferType)), static_cast<void*>(&index)));
|
||||||
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
|
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
|
||||||
|
@ -3565,9 +3565,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
|||||||
else {
|
else {
|
||||||
// Generic view
|
// Generic view
|
||||||
// Get new position at the same Z of the initial click point.
|
// Get new position at the same Z of the initial click point.
|
||||||
float z0 = 0.0f;
|
cur_pos = mouse_ray(pos).intersect_plane(m_mouse.drag.start_position_3D.z());
|
||||||
float z1 = 1.0f;
|
|
||||||
cur_pos = Linef3(_mouse_to_3d(pos, &z0), _mouse_to_3d(pos, &z1)).intersect_plane(m_mouse.drag.start_position_3D.z());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3630,7 +3628,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
|||||||
if (m_mouse.is_start_position_2D_defined()) {
|
if (m_mouse.is_start_position_2D_defined()) {
|
||||||
// get point in model space at Z = 0
|
// get point in model space at Z = 0
|
||||||
float z = 0.0f;
|
float z = 0.0f;
|
||||||
const Vec3d& cur_pos = _mouse_to_3d(pos, &z);
|
const Vec3d cur_pos = _mouse_to_3d(pos, &z);
|
||||||
const Vec3d orig = _mouse_to_3d(m_mouse.drag.start_position_2D, &z);
|
const Vec3d orig = _mouse_to_3d(m_mouse.drag.start_position_2D, &z);
|
||||||
Camera& camera = wxGetApp().plater()->get_camera();
|
Camera& camera = wxGetApp().plater()->get_camera();
|
||||||
if (wxGetApp().app_config->get("use_free_camera") != "1")
|
if (wxGetApp().app_config->get("use_free_camera") != "1")
|
||||||
@ -6476,19 +6474,19 @@ Vec3d GLCanvas3D::_mouse_to_3d(const Point& mouse_pos, float* z)
|
|||||||
return Vec3d(DBL_MAX, DBL_MAX, DBL_MAX);
|
return Vec3d(DBL_MAX, DBL_MAX, DBL_MAX);
|
||||||
|
|
||||||
const Camera& camera = wxGetApp().plater()->get_camera();
|
const Camera& camera = wxGetApp().plater()->get_camera();
|
||||||
Matrix4d modelview = camera.get_view_matrix().matrix();
|
const Matrix4d modelview = camera.get_view_matrix().matrix();
|
||||||
Matrix4d projection= camera.get_projection_matrix().matrix();
|
const Matrix4d projection = camera.get_projection_matrix().matrix();
|
||||||
Vec4i viewport(camera.get_viewport().data());
|
const Vec4i viewport(camera.get_viewport().data());
|
||||||
|
|
||||||
GLint y = viewport[3] - (GLint)mouse_pos(1);
|
const int y = viewport[3] - mouse_pos.y();
|
||||||
GLfloat mouse_z;
|
float mouse_z;
|
||||||
if (z == nullptr)
|
if (z == nullptr)
|
||||||
glsafe(::glReadPixels((GLint)mouse_pos(0), y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, (void*)&mouse_z));
|
glsafe(::glReadPixels(mouse_pos.x(), y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, (void*)&mouse_z));
|
||||||
else
|
else
|
||||||
mouse_z = *z;
|
mouse_z = *z;
|
||||||
|
|
||||||
Vec3d out;
|
Vec3d out;
|
||||||
igl::unproject(Vec3d(mouse_pos(0), y, mouse_z), modelview, projection, viewport, out);
|
igl::unproject(Vec3d(mouse_pos.x(), y, mouse_z), modelview, projection, viewport, out);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6287,7 +6287,7 @@ void Plater::reslice_SLA_hollowing(const ModelObject &object, bool postpone_erro
|
|||||||
reslice_SLA_until_step(slaposDrillHoles, object, postpone_error_messages);
|
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.
|
//FIXME Don't reslice if export of G-code or sending to OctoPrint is running.
|
||||||
// bitmask of UpdateBackgroundProcessReturnState
|
// bitmask of UpdateBackgroundProcessReturnState
|
||||||
@ -6313,6 +6313,16 @@ void Plater::reslice_SLA_until_step(SLAPrintObjectStep step, const ModelObject &
|
|||||||
this->p->restart_background_process(state | priv::UPDATE_BACKGROUND_PROCESS_FORCE_RESTART);
|
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()
|
void Plater::send_gcode()
|
||||||
{
|
{
|
||||||
// if physical_printer is selected, send gcode for this printer
|
// if physical_printer is selected, send gcode for this printer
|
||||||
|
@ -32,6 +32,7 @@ using ModelObjectCutAttributes = enum_bitmask<ModelObjectCutAttribute>;
|
|||||||
class ModelInstance;
|
class ModelInstance;
|
||||||
class Print;
|
class Print;
|
||||||
class SLAPrint;
|
class SLAPrint;
|
||||||
|
enum PrintObjectStep : unsigned int;
|
||||||
enum SLAPrintObjectStep : unsigned int;
|
enum SLAPrintObjectStep : unsigned int;
|
||||||
enum class ConversionType : int;
|
enum class ConversionType : int;
|
||||||
|
|
||||||
@ -265,6 +266,7 @@ public:
|
|||||||
bool has_toolpaths_to_export() const;
|
bool has_toolpaths_to_export() const;
|
||||||
void export_toolpaths_to_obj() const;
|
void export_toolpaths_to_obj() const;
|
||||||
void reslice();
|
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_supports(const ModelObject &object, bool postpone_error_messages = false);
|
||||||
void reslice_SLA_hollowing(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);
|
void reslice_SLA_until_step(SLAPrintObjectStep step, const ModelObject &object, bool postpone_error_messages = false);
|
||||||
@ -478,6 +480,8 @@ public:
|
|||||||
static void show_illegal_characters_warning(wxWindow* parent);
|
static void show_illegal_characters_warning(wxWindow* parent);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void reslice_until_step_inner(int step, const ModelObject &object, bool postpone_error_messages);
|
||||||
|
|
||||||
struct priv;
|
struct priv;
|
||||||
std::unique_ptr<priv> p;
|
std::unique_ptr<priv> p;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user