Implemented naming of the SLA export file based on the output file name

template.

Reworked naming of the plater exports to not use the output file name
template, but to derive the file name from the first printable object's name.

Fixed error handling: Reimpemented the Perl's "eval" blocks
as try / catch blocks.
This commit is contained in:
bubnikv 2018-12-03 13:14:28 +01:00
parent 041fae8148
commit d46d0dc365
25 changed files with 474 additions and 344 deletions

View file

@ -540,6 +540,15 @@ void Model::reset_auto_extruder_id()
s_auto_extruder_id = 1;
}
std::string Model::propose_export_file_name() const
{
for (const ModelObject *model_object : this->objects)
for (ModelInstance *model_instance : model_object->instances)
if (model_instance->is_printable())
return model_object->input_file;
return std::string();
}
ModelObject::~ModelObject()
{
this->clear_volumes();

View file

@ -653,6 +653,9 @@ public:
static std::string get_auto_extruder_id_as_string(unsigned int max_extruders);
static void reset_auto_extruder_id();
// Propose an output file name based on the first printable object's name.
std::string propose_export_file_name() const;
private:
MODELBASE_DERIVED_PRIVATE_COPY_MOVE(Model)
};

View file

@ -94,6 +94,36 @@ void PlaceholderParser::update_timestamp(DynamicConfig &config)
config.set_key_value("second", new ConfigOptionInt(timeinfo->tm_sec));
}
// Ignore this key by the placeholder parser.
static inline bool placeholder_parser_ignore(const ConfigDef *def, const std::string &opt_key)
{
const ConfigOptionDef *opt_def = def->get(opt_key);
assert(opt_def != nullptr);
return (opt_def->multiline && boost::ends_with(opt_key, "_gcode")) || opt_key == "post_process";
}
static inline bool opts_equal(const DynamicConfig &config_old, const DynamicConfig &config_new, const std::string &opt_key)
{
const ConfigOption *opt_old = config_old.option(opt_key);
const ConfigOption *opt_new = config_new.option(opt_key);
assert(opt_new != nullptr);
if (opt_old == nullptr)
return false;
return (opt_new->type() == coFloatOrPercent) ?
dynamic_cast<const ConfigOptionFloat*>(opt_old)->value == config_new.get_abs_value(opt_key) :
*opt_new == *opt_old;
}
std::vector<std::string> PlaceholderParser::config_diff(const DynamicPrintConfig &rhs)
{
const ConfigDef *def = rhs.def();
std::vector<std::string> diff_keys;
for (const t_config_option_key &opt_key : rhs.keys())
if (! placeholder_parser_ignore(def, opt_key) && ! opts_equal(m_config, rhs, opt_key))
diff_keys.emplace_back(opt_key);
return diff_keys;
}
// Scalar configuration values are stored into m_single,
// vector configuration values are stored into m_multiple.
// All vector configuration values stored into the PlaceholderParser
@ -105,28 +135,39 @@ bool PlaceholderParser::apply_config(const DynamicPrintConfig &rhs)
const ConfigDef *def = rhs.def();
bool modified = false;
for (const t_config_option_key &opt_key : rhs.keys()) {
const ConfigOptionDef *opt_def = def->get(opt_key);
if ((opt_def->multiline && boost::ends_with(opt_key, "_gcode")) || opt_key == "post_process")
if (placeholder_parser_ignore(def, opt_key))
continue;
const ConfigOption *opt_rhs = rhs.option(opt_key);
const ConfigOption *opt_old = m_config.option(opt_key, false);
if (opt_old != nullptr) {
if (opt_rhs->type() == coFloatOrPercent ?
dynamic_cast<const ConfigOptionFloat*>(opt_old)->value == rhs.get_abs_value(opt_key)
: *opt_rhs == *opt_old)
// no need to update
continue;
if (! opts_equal(m_config, rhs, opt_key)) {
// Store a copy of the config option.
// Convert FloatOrPercent values to floats first.
//FIXME there are some ratio_over chains, which end with empty ratio_with.
// For example, XXX_extrusion_width parameters are not handled by get_abs_value correctly.
const ConfigOption *opt_rhs = rhs.option(opt_key);
this->set(opt_key, (opt_rhs->type() == coFloatOrPercent) ?
new ConfigOptionFloat(rhs.get_abs_value(opt_key)) :
opt_rhs->clone());
modified = true;
}
}
return modified;
}
void PlaceholderParser::apply_only(const DynamicPrintConfig &rhs, const std::vector<std::string> &keys)
{
#ifdef _DEBUG
const ConfigDef *def = rhs.def();
#endif /* _DEBUG */
for (const t_config_option_key &opt_key : keys) {
assert(! placeholder_parser_ignore(def, opt_key));
// Store a copy of the config option.
// Convert FloatOrPercent values to floats first.
//FIXME there are some ratio_over chains, which end with empty ratio_with.
// For example, XXX_extrusion_width parameters are not handled by get_abs_value correctly.
const ConfigOption *opt_rhs = rhs.option(opt_key);
this->set(opt_key, (opt_rhs->type() == coFloatOrPercent) ?
new ConfigOptionFloat(rhs.get_abs_value(opt_key)) :
opt_rhs->clone());
modified = true;
}
return modified;
}
void PlaceholderParser::apply_env_variables()

View file

@ -14,8 +14,14 @@ class PlaceholderParser
public:
PlaceholderParser();
// Return a list of keys, which should be changed in m_config from rhs.
// This contains keys, which are found in rhs, but not in m_config.
std::vector<std::string> config_diff(const DynamicPrintConfig &rhs);
// Return true if modified.
bool apply_config(const DynamicPrintConfig &config);
// To be called on the values returned by PlaceholderParser::config_diff().
// The keys should already be valid.
void apply_only(const DynamicPrintConfig &config, const std::vector<std::string> &keys);
void apply_env_variables();
// Add new ConfigOption values to m_config.

View file

@ -442,7 +442,7 @@ bool Print::apply_config(DynamicPrintConfig config)
config.normalize();
// apply variables to placeholder parser
m_placeholder_parser.apply_config(config);
this->placeholder_parser().apply_config(config);
// handle changes to print config
t_config_option_keys print_diff = m_config.diff(config);
@ -683,6 +683,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
t_config_option_keys print_diff = m_config.diff(config);
t_config_option_keys object_diff = m_default_object_config.diff(config);
t_config_option_keys region_diff = m_default_region_config.diff(config);
t_config_option_keys placeholder_parser_diff = this->placeholder_parser().config_diff(config);
// Do not use the ApplyStatus as we will use the max function when updating apply_status.
unsigned int apply_status = APPLY_STATUS_UNCHANGED;
@ -699,8 +700,15 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
update_apply_status(this->invalidate_state_by_config_options(print_diff));
// Apply variables to placeholder parser. The placeholder parser is used by G-code export,
// which should be stopped if print_diff is not empty.
if (m_placeholder_parser.apply_config(config))
if (! placeholder_parser_diff.empty()) {
update_apply_status(this->invalidate_step(psGCodeExport));
PlaceholderParser &pp = this->placeholder_parser();
pp.apply_only(config, placeholder_parser_diff);
// Set the profile aliases for the PrintBase::output_filename()
pp.set("print_preset", config_in.option("print_settings_id" )->clone());
pp.set("filament_preset", config_in.option("filament_settings_id")->clone());
pp.set("printer_preset", config_in.option("printer_settings_id" )->clone());
}
// It is also safe to change m_config now after this->invalidate_state_by_config_options() call.
m_config.apply_only(config, print_diff, true);
@ -1113,6 +1121,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
if (! object->layer_height_profile_valid)
object->update_layer_height_profile();
//FIXME there may be a race condition with the G-code export running at the background thread.
this->update_object_placeholders();
#ifdef _DEBUG
@ -1122,33 +1131,6 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
return static_cast<ApplyStatus>(apply_status);
}
// Update "scale", "input_filename", "input_filename_base" placeholders from the current m_objects.
void Print::update_object_placeholders()
{
// get the first input file name
std::string input_file;
std::vector<std::string> v_scale;
for (const PrintObject *object : m_objects) {
const ModelObject &mobj = *object->model_object();
// CHECK_ME -> Is the following correct ?
v_scale.push_back("x:" + boost::lexical_cast<std::string>(mobj.instances[0]->get_scaling_factor(X) * 100) +
"% y:" + boost::lexical_cast<std::string>(mobj.instances[0]->get_scaling_factor(Y) * 100) +
"% z:" + boost::lexical_cast<std::string>(mobj.instances[0]->get_scaling_factor(Z) * 100) + "%");
if (input_file.empty())
input_file = mobj.input_file;
}
PlaceholderParser &pp = m_placeholder_parser;
pp.set("scale", v_scale);
if (! input_file.empty()) {
// get basename with and without suffix
const std::string input_basename = boost::filesystem::path(input_file).filename().string();
pp.set("input_filename", input_basename);
const std::string input_basename_base = input_basename.substr(0, input_basename.find_last_of("."));
pp.set("input_filename_base", input_basename_base);
}
}
bool Print::has_infinite_skirt() const
{
return (m_config.skirt_height == -1 && m_config.skirts > 0)
@ -1851,60 +1833,6 @@ void Print::_make_wipe_tower()
m_wipe_tower_data.number_of_toolchanges = wipe_tower.get_number_of_toolchanges();
}
std::string Print::output_filename() const
{
DynamicConfig cfg_timestamp;
PlaceholderParser::update_timestamp(cfg_timestamp);
try {
return this->placeholder_parser().process(m_config.output_filename_format.value, 0, &cfg_timestamp);
} catch (std::runtime_error &err) {
throw std::runtime_error(L("Failed processing of the output_filename_format template.") + "\n" + err.what());
}
}
std::string Print::output_filepath(const std::string &path) const
{
// if we were supplied no path, generate an automatic one based on our first object's input file
if (path.empty()) {
// get the first input file name
std::string input_file;
for (const PrintObject *object : m_objects) {
input_file = object->model_object()->input_file;
if (! input_file.empty())
break;
}
return (boost::filesystem::path(input_file).parent_path() / this->output_filename()).make_preferred().string();
}
// if we were supplied a directory, use it and append our automatically generated filename
boost::filesystem::path p(path);
if (boost::filesystem::is_directory(p))
return (p / this->output_filename()).make_preferred().string();
// if we were supplied a file which is not a directory, use it
return path;
}
void Print::export_png(const std::string &dirpath)
{
// size_t idx = 0;
// for (PrintObject *obj : m_objects) {
// obj->slice();
// this->set_status(int(floor(idx * 100. / m_objects.size() + 0.5)), "Slicing...");
// ++ idx;
// }
// this->set_status(90, "Exporting zipped archive...");
// print_to<FilePrinterFormat::PNG>(*this,
// dirpath,
// float(m_config.bed_size_x.value),
// float(m_config.bed_size_y.value),
// int(m_config.pixel_width.value),
// int(m_config.pixel_height.value),
// float(m_config.exp_time.value),
// float(m_config.exp_time_first.value));
// this->set_status(100, "Done.");
}
// Returns extruder this eec should be printed with, according to PrintRegion config
int Print::get_extruder(const ExtrusionEntityCollection& fill, const PrintRegion &region)
{

View file

@ -8,7 +8,6 @@
#include "Point.hpp"
#include "Layer.hpp"
#include "Model.hpp"
#include "PlaceholderParser.hpp"
#include "Slicing.hpp"
#include "GCode/ToolOrdering.hpp"
#include "GCode/WipeTower.hpp"
@ -296,8 +295,6 @@ public:
void process() override;
void export_gcode(const std::string &path_template, GCodePreviewData *preview_data);
// SLA export, temporary.
void export_png(const std::string &dirpath);
// methods for handling state
bool is_step_done(PrintStep step) const { return Inherited::is_step_done(step); }
@ -330,8 +327,6 @@ public:
PrintObject* get_object(size_t idx) { return m_objects[idx]; }
const PrintObject* get_object(size_t idx) const { return m_objects[idx]; }
const PrintRegionPtrs& regions() const { return m_regions; }
const PlaceholderParser& placeholder_parser() const { return m_placeholder_parser; }
PlaceholderParser& placeholder_parser() { return m_placeholder_parser; }
// How many of PrintObject::copies() over all print objects are there?
// If zero, then the print is empty and the print shall not be executed.
unsigned int num_object_instances() const;
@ -348,8 +343,8 @@ public:
bool has_wipe_tower() const;
const WipeTowerData& wipe_tower_data() const { return m_wipe_tower_data; }
std::string output_filename() const;
std::string output_filepath(const std::string &path) const;
std::string output_filename() const override
{ return this->PrintBase::output_filename(m_config.output_filename_format.value, "gcode"); }
// Accessed by SupportMaterial
const PrintRegion* get_region(size_t idx) const { return m_regions[idx]; }
@ -364,9 +359,6 @@ protected:
bool invalidate_step(PrintStep step);
private:
// Update "scale", "input_filename", "input_filename_base" placeholders from the current m_objects.
void update_object_placeholders();
bool invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys);
void _make_skirt();
@ -382,7 +374,6 @@ private:
PrintRegionConfig m_default_region_config;
PrintObjectPtrs m_objects;
PrintRegionPtrs m_regions;
PlaceholderParser m_placeholder_parser;
// Ordered collections of extrusion paths to build skirt loops and brim.
ExtrusionEntityCollection m_skirt;

View file

@ -1,10 +1,91 @@
#include "PrintBase.hpp"
#include "I18N.hpp"
//! macro used to mark string used at localization,
//! return same string
#define L(s) Slic3r::I18N::translate(s)
namespace Slic3r
{
size_t PrintStateBase::g_last_timestamp = 0;
// Update "scale", "input_filename", "input_filename_base" placeholders from the current m_objects.
void PrintBase::update_object_placeholders()
{
// get the first input file name
std::string input_file;
std::vector<std::string> v_scale;
for (const ModelObject *model_object : m_model.objects) {
ModelInstance *printable = nullptr;
for (ModelInstance *model_instance : model_object->instances)
if (model_instance->is_printable()) {
printable = model_instance;
break;
}
if (printable) {
// CHECK_ME -> Is the following correct ?
v_scale.push_back("x:" + boost::lexical_cast<std::string>(printable->get_scaling_factor(X) * 100) +
"% y:" + boost::lexical_cast<std::string>(printable->get_scaling_factor(Y) * 100) +
"% z:" + boost::lexical_cast<std::string>(printable->get_scaling_factor(Z) * 100) + "%");
if (input_file.empty())
input_file = model_object->input_file;
}
}
PlaceholderParser &pp = m_placeholder_parser;
pp.set("scale", v_scale);
if (! input_file.empty()) {
// get basename with and without suffix
const std::string input_basename = boost::filesystem::path(input_file).filename().string();
pp.set("input_filename", input_basename);
const std::string input_basename_base = input_basename.substr(0, input_basename.find_last_of("."));
pp.set("input_filename_base", input_basename_base);
}
}
std::string PrintBase::output_filename(const std::string &format, const std::string &default_ext) const
{
DynamicConfig cfg_timestamp;
PlaceholderParser::update_timestamp(cfg_timestamp);
try {
boost::filesystem::path filename = this->placeholder_parser().process(format, 0, &cfg_timestamp);
if (filename.extension().empty())
filename = boost::filesystem::change_extension(filename, default_ext);
return filename.string();
} catch (std::runtime_error &err) {
throw std::runtime_error(L("Failed processing of the output_filename_format template.") + "\n" + err.what());
}
}
std::string PrintBase::output_filepath(const std::string &path) const
{
// if we were supplied no path, generate an automatic one based on our first object's input file
if (path.empty()) {
// get the first input file name
std::string input_file;
for (const ModelObject *model_object : m_model.objects) {
for (ModelInstance *model_instance : model_object->instances)
if (model_instance->is_printable()) {
input_file = model_object->input_file;
break;
}
if (! input_file.empty())
break;
}
return (boost::filesystem::path(input_file).parent_path() / this->output_filename()).make_preferred().string();
}
// if we were supplied a directory, use it and append our automatically generated filename
boost::filesystem::path p(path);
if (boost::filesystem::is_directory(p))
return (p / this->output_filename()).make_preferred().string();
// if we were supplied a file which is not a directory, use it
return path;
}
tbb::mutex& PrintObjectBase::state_mutex(PrintBase *print)
{
return print->state_mutex();

View file

@ -14,6 +14,7 @@
#include "tbb/mutex.h"
#include "Model.hpp"
#include "PlaceholderParser.hpp"
#include "PrintConfig.hpp"
namespace Slic3r {
@ -266,7 +267,7 @@ public:
// Various methods will call this callback to stop the background processing (the Print::process() call)
// in case a successive change of the Print / PrintObject / PrintRegion instances changed
// the state of the finished or running calculations.
void set_cancel_callback(cancel_callback_type cancel_callback) { m_cancel_callback = cancel_callback; }
void set_cancel_callback(cancel_callback_type cancel_callback) { m_cancel_callback = cancel_callback; }
// Has the calculation been canceled?
enum CancelStatus {
// No cancelation, background processing should run.
@ -276,14 +277,20 @@ public:
// Canceled internally from Print::apply() through the Print/PrintObject::invalidate_step() or ::invalidate_all_steps().
CANCELED_INTERNAL = 2
};
CancelStatus cancel_status() const { return m_cancel_status; }
CancelStatus cancel_status() const { return m_cancel_status; }
// Has the calculation been canceled?
bool canceled() const { return m_cancel_status != NOT_CANCELED; }
bool canceled() const { return m_cancel_status != NOT_CANCELED; }
// Cancel the running computation. Stop execution of all the background threads.
void cancel() { m_cancel_status = CANCELED_BY_USER; }
void cancel_internal() { m_cancel_status = CANCELED_INTERNAL; }
void cancel() { m_cancel_status = CANCELED_BY_USER; }
void cancel_internal() { m_cancel_status = CANCELED_INTERNAL; }
// Cancel the running computation. Stop execution of all the background threads.
void restart() { m_cancel_status = NOT_CANCELED; }
void restart() { m_cancel_status = NOT_CANCELED; }
const PlaceholderParser& placeholder_parser() const { return m_placeholder_parser; }
PlaceholderParser& placeholder_parser() { return m_placeholder_parser; }
virtual std::string output_filename() const = 0;
std::string output_filepath(const std::string &path) const;
protected:
friend class PrintObjectBase;
@ -297,6 +304,11 @@ protected:
// To be called by the worker thread and its sub-threads (mostly launched on the TBB thread pool) regularly.
void throw_if_canceled() const { if (m_cancel_status) throw CanceledException(); }
// To be called by this->output_filename() with the format string pulled from the configuration layer.
std::string output_filename(const std::string &format, const std::string &default_ext) const;
// Update "scale", "input_filename", "input_filename_base" placeholders from the current printable ModelObjects.
void update_object_placeholders();
Model m_model;
private:
@ -311,6 +323,8 @@ private:
// The mutex will be used to guard the worker thread against entering a stage
// while the data influencing the stage is modified.
mutable tbb::mutex m_state_mutex;
PlaceholderParser m_placeholder_parser;
};
template<typename PrintStepEnum, const size_t COUNT>

View file

@ -1322,7 +1322,7 @@ void PrintConfigDef::init_fff_params()
def->cli = "output-filename-format=s";
def->full_width = true;
def->mode = comExpert;
def->default_value = new ConfigOptionString("[input_filename_base].gcode");
def->default_value = new ConfigOptionString("[input_filename_base]");
def = this->add("overhangs", coBool);
def->label = L("Detect bridging perimeters");
@ -2925,6 +2925,7 @@ StaticPrintConfig::StaticCache<class Slic3r::HostConfig> HostConfig::s_ca
StaticPrintConfig::StaticCache<class Slic3r::FullPrintConfig> FullPrintConfig::s_cache_FullPrintConfig;
StaticPrintConfig::StaticCache<class Slic3r::SLAMaterialConfig> SLAMaterialConfig::s_cache_SLAMaterialConfig;
StaticPrintConfig::StaticCache<class Slic3r::SLAPrintConfig> SLAPrintConfig::s_cache_SLAPrintConfig;
StaticPrintConfig::StaticCache<class Slic3r::SLAPrintObjectConfig> SLAPrintObjectConfig::s_cache_SLAPrintObjectConfig;
StaticPrintConfig::StaticCache<class Slic3r::SLAPrinterConfig> SLAPrinterConfig::s_cache_SLAPrinterConfig;
StaticPrintConfig::StaticCache<class Slic3r::SLAFullPrintConfig> SLAFullPrintConfig::s_cache_SLAFullPrintConfig;

View file

@ -898,6 +898,20 @@ protected:
}
};
// This object is mapped to Perl as Slic3r::Config::PrintRegion.
class SLAPrintConfig : public StaticPrintConfig
{
STATIC_PRINT_CONFIG_CACHE(SLAPrintConfig)
public:
ConfigOptionString output_filename_format;
protected:
void initialize(StaticCacheBase &cache, const char *base_ptr)
{
OPT_PTR(output_filename_format);
}
};
class SLAPrintObjectConfig : public StaticPrintConfig
{
STATIC_PRINT_CONFIG_CACHE(SLAPrintObjectConfig)
@ -1028,10 +1042,10 @@ protected:
}
};
class SLAFullPrintConfig : public SLAPrinterConfig, public SLAPrintObjectConfig, public SLAMaterialConfig
class SLAFullPrintConfig : public SLAPrinterConfig, public SLAPrintConfig, public SLAPrintObjectConfig, public SLAMaterialConfig
{
STATIC_PRINT_CONFIG_CACHE_DERIVED(SLAFullPrintConfig)
SLAFullPrintConfig() : SLAPrinterConfig(0), SLAPrintObjectConfig(0), SLAMaterialConfig(0) { initialize_cache(); *this = s_cache_SLAFullPrintConfig.defaults(); }
SLAFullPrintConfig() : SLAPrinterConfig(0), SLAPrintConfig(0), SLAPrintObjectConfig(0), SLAMaterialConfig(0) { initialize_cache(); *this = s_cache_SLAFullPrintConfig.defaults(); }
public:
// Validate the SLAFullPrintConfig. Returns an empty string on success, otherwise an error message is returned.
@ -1039,10 +1053,11 @@ public:
protected:
// Protected constructor to be called to initialize ConfigCache::m_default.
SLAFullPrintConfig(int) : SLAPrinterConfig(0), SLAPrintObjectConfig(0), SLAMaterialConfig(0) {}
SLAFullPrintConfig(int) : SLAPrinterConfig(0), SLAPrintConfig(0), SLAPrintObjectConfig(0), SLAMaterialConfig(0) {}
void initialize(StaticCacheBase &cache, const char *base_ptr)
{
this->SLAPrinterConfig ::initialize(cache, base_ptr);
this->SLAPrintConfig ::initialize(cache, base_ptr);
this->SLAPrintObjectConfig::initialize(cache, base_ptr);
this->SLAMaterialConfig ::initialize(cache, base_ptr);
}

View file

@ -107,8 +107,7 @@ static std::vector<SLAPrintObject::Instance> sla_instances(const ModelObject &mo
return instances;
}
SLAPrint::ApplyStatus SLAPrint::apply(const Model &model,
const DynamicPrintConfig &config_in)
SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConfig &config_in)
{
#ifdef _DEBUG
check_model_ids_validity(model);
@ -118,27 +117,44 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model,
DynamicPrintConfig config(config_in);
config.normalize();
// Collect changes to print config.
t_config_option_keys print_diff = m_print_config.diff(config);
t_config_option_keys printer_diff = m_printer_config.diff(config);
t_config_option_keys material_diff = m_material_config.diff(config);
t_config_option_keys object_diff = m_default_object_config.diff(config);
t_config_option_keys placeholder_parser_diff = this->placeholder_parser().config_diff(config);
// Do not use the ApplyStatus as we will use the max function when updating apply_status.
unsigned int apply_status = APPLY_STATUS_UNCHANGED;
auto update_apply_status = [&apply_status](bool invalidated)
{ apply_status = std::max<unsigned int>(apply_status, invalidated ? APPLY_STATUS_INVALIDATED : APPLY_STATUS_CHANGED); };
if (! (printer_diff.empty() && material_diff.empty() && object_diff.empty()))
if (! (print_diff.empty() && printer_diff.empty() && material_diff.empty() && object_diff.empty()))
update_apply_status(false);
// Grab the lock for the Print / PrintObject milestones.
tbb::mutex::scoped_lock lock(this->state_mutex());
// The following call may stop the background processing.
if (! print_diff.empty())
update_apply_status(this->invalidate_state_by_config_options(print_diff));
if (! printer_diff.empty())
update_apply_status(this->invalidate_state_by_config_options(printer_diff));
if (! material_diff.empty())
update_apply_status(this->invalidate_state_by_config_options(material_diff));
// Apply variables to placeholder parser. The placeholder parser is currently used
// only to generate the output file name.
if (! placeholder_parser_diff.empty()) {
// update_apply_status(this->invalidate_step(slapsRasterize));
PlaceholderParser &pp = this->placeholder_parser();
pp.apply_config(config);
// Set the profile aliases for the PrintBase::output_filename()
pp.set("print_preset", config_in.option("sla_print_settings_id")->clone());
pp.set("material_preset", config_in.option("sla_material_settings_id")->clone());
pp.set("printer_preset", config_in.option("printer_settings_id")->clone());
}
// It is also safe to change m_config now after this->invalidate_state_by_config_options() call.
m_print_config.apply_only(config, print_diff, true);
m_printer_config.apply_only(config, printer_diff, true);
// Handle changes to material config.
m_material_config.apply_only(config, material_diff, true);
@ -368,6 +384,8 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model,
update_apply_status(new_objects);
}
this->update_object_placeholders();
#ifdef _DEBUG
check_model_ids_equal(m_model, model);
#endif /* _DEBUG */
@ -874,6 +892,7 @@ bool SLAPrint::invalidate_state_by_config_options(const std::vector<t_config_opt
"bed_shape",
"max_print_height",
"printer_technology",
"output_filename_format"
};
std::vector<SLAPrintStep> steps;
@ -927,7 +946,9 @@ bool SLAPrintObject::invalidate_state_by_config_options(const std::vector<t_conf
std::vector<SLAPrintObjectStep> steps;
bool invalidated = false;
for (const t_config_option_key &opt_key : opt_keys) {
if ( opt_key == "supports_enable"
if (opt_key == "layer_height") {
steps.emplace_back(slaposObjectSlice);
} else if (opt_key == "supports_enable"
|| opt_key == "support_head_front_diameter"
|| opt_key == "support_head_penetration"
|| opt_key == "support_head_width"

View file

@ -191,6 +191,9 @@ public:
}
const PrintObjects& objects() const { return m_objects; }
std::string output_filename() const override
{ return this->PrintBase::output_filename(m_print_config.output_filename_format.value, "zip"); }
private:
using SLAPrinter = FilePrinter<FilePrinterFormat::SLA_PNGZIP>;
using SLAPrinterPtr = std::unique_ptr<SLAPrinter>;
@ -198,6 +201,7 @@ private:
// Invalidate steps based on a set of parameters changed.
bool invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys);
SLAPrintConfig m_print_config;
SLAPrinterConfig m_printer_config;
SLAMaterialConfig m_material_config;
SLAPrintObjectConfig m_default_object_config;