Add some spacing settings at the side of width

- now a setting can be "phony"
 - a phony setting isn't saved in a config file
 - a phony setting should be computed from other settings
 - change/add colors, icons, and callbacks (in PrintConfig.cpp) to make phony settings works
This commit is contained in:
remi durand 2021-04-25 01:55:30 +02:00
parent 1d405304b9
commit 715d58da88
18 changed files with 673 additions and 79 deletions

View File

@ -258,15 +258,40 @@ group:Autospeed (advanced)
page:Width & Flow:width
group:Extrusion width
setting:extrusion_width
setting:first_layer_extrusion_width
setting:perimeter_extrusion_width
setting:external_perimeter_extrusion_width
setting:infill_extrusion_width
setting:solid_infill_extrusion_width
setting:top_infill_extrusion_width
setting:support_material_extrusion_width
setting:skirt_extrusion_width
line:default
setting:sidetext_width$10:label$width:extrusion_width
setting:sidetext_width$10:label_width$15:label$spacing:extrusion_spacing
end_line
line:first layer
setting:sidetext_width$10:label$width:first_layer_extrusion_width
setting:sidetext_width$10:label_width$15:label$spacing:first_layer_extrusion_spacing
end_line
line:perimeter
setting:sidetext_width$10:label$width:perimeter_extrusion_width
setting:sidetext_width$10:label_width$15:label$spacing:perimeter_extrusion_spacing
end_line
line:external perimeter
setting:sidetext_width$10:label$width:external_perimeter_extrusion_width
setting:sidetext_width$10:label_width$15:label$width&spacing combo:external_perimeter_extrusion_spacing
end_line
line:infill
setting:sidetext_width$10:label$width:infill_extrusion_width
setting:sidetext_width$10:label_width$15:label$spacing:infill_extrusion_spacing
end_line
line:solid infill
setting:sidetext_width$10:label$width:solid_infill_extrusion_width
setting:sidetext_width$10:label_width$15:label$spacing:solid_infill_extrusion_spacing
end_line
line:top infill
setting:sidetext_width$10:label$width:top_infill_extrusion_width
setting:sidetext_width$10:label_width$15:label$spacing:top_infill_extrusion_spacing
end_line
line:support material
setting:sidetext_width$10:label$width:support_material_extrusion_width
end_line
line:skirt
setting:sidetext_width$10:label$width:skirt_extrusion_width
end_line
recommended_extrusion_width_description
group:Overlap
line:Perimeter overlap

View File

@ -473,7 +473,9 @@ t_config_option_keys ConfigBase::diff(const ConfigBase &other) const
for (const t_config_option_key &opt_key : this->keys()) {
const ConfigOption *this_opt = this->option(opt_key);
const ConfigOption *other_opt = other.option(opt_key);
if (this_opt != nullptr && other_opt != nullptr && *this_opt != *other_opt)
//dirty if both exist, they aren't both phony and value is different
if (this_opt != nullptr && other_opt != nullptr && !(this_opt->phony && other_opt->phony)
&& ((*this_opt != *other_opt) || (this_opt->phony != other_opt->phony)))
diff.emplace_back(opt_key);
}
return diff;
@ -495,6 +497,8 @@ std::string ConfigBase::opt_serialize(const t_config_option_key &opt_key) const
{
const ConfigOption* opt = this->option(opt_key);
assert(opt != nullptr);
if (opt->phony)
return "";
return opt->serialize();
}
@ -584,7 +588,19 @@ bool ConfigBase::set_deserialize_raw(const t_config_option_key &opt_key_src, con
ConfigOption *opt = this->option(opt_key, true);
if (opt == nullptr)
throw new UnknownOptionException(opt_key);
bool ok= opt->deserialize(value, append);
bool ok = true;
if (!optdef->can_phony || value != "")
ok = opt->deserialize(value, append);
//set phony status
if (optdef->can_phony)
if(value == "")
opt->phony = true;
else
opt->phony = false;
else
opt->phony = false;
return ok;
}

View File

@ -214,6 +214,12 @@ inline OutputFormat operator&=(OutputFormat& a, OutputFormat b) {
// A generic value of a configuration option.
class ConfigOption {
public:
// if true, this option doesn't need to be saved, it's a computed value from an other configOption.
bool phony;
ConfigOption() : phony(false) {}
ConfigOption(bool phony) : phony(phony) {}
virtual ~ConfigOption() {}
virtual ConfigOptionType type() const = 0;
@ -258,6 +264,7 @@ class ConfigOptionSingle : public ConfigOption {
public:
T value;
explicit ConfigOptionSingle(T value) : value(value) {}
explicit ConfigOptionSingle(T value, bool phony) : ConfigOption(phony), value(value) {}
operator T() const { return this->value; }
void set(const ConfigOption *rhs) override
@ -266,6 +273,7 @@ public:
throw Slic3r::RuntimeError("ConfigOptionSingle: Assigning an incompatible type");
assert(dynamic_cast<const ConfigOptionSingle<T>*>(rhs));
this->value = static_cast<const ConfigOptionSingle<T>*>(rhs)->value;
this->phony = rhs->phony;
}
bool operator==(const ConfigOption &rhs) const override
@ -340,6 +348,7 @@ public:
throw Slic3r::RuntimeError("ConfigOptionVector: Assigning an incompatible type");
assert(dynamic_cast<const ConfigOptionVector<T>*>(rhs));
this->values = static_cast<const ConfigOptionVector<T>*>(rhs)->values;
this->phony = rhs->phony;
}
// Set from a vector of ConfigOptions.
@ -504,6 +513,7 @@ class ConfigOptionFloat : public ConfigOptionSingle<double>
public:
ConfigOptionFloat() : ConfigOptionSingle<double>(0) {}
explicit ConfigOptionFloat(double _value) : ConfigOptionSingle<double>(_value) {}
explicit ConfigOptionFloat(double _value, bool _phony) : ConfigOptionSingle<double>(_value, _phony) {}
static ConfigOptionType static_type() { return coFloat; }
ConfigOptionType type() const override { return static_type(); }
@ -850,6 +860,7 @@ class ConfigOptionPercent : public ConfigOptionFloat
public:
ConfigOptionPercent() : ConfigOptionFloat(0) {}
explicit ConfigOptionPercent(double _value) : ConfigOptionFloat(_value) {}
explicit ConfigOptionPercent(double _value, bool _phony) : ConfigOptionFloat(_value, _phony) {}
static ConfigOptionType static_type() { return coPercent; }
ConfigOptionType type() const override { return static_type(); }
@ -943,6 +954,7 @@ public:
bool percent;
ConfigOptionFloatOrPercent() : ConfigOptionPercent(0), percent(false) {}
explicit ConfigOptionFloatOrPercent(double _value, bool _percent) : ConfigOptionPercent(_value), percent(_percent) {}
explicit ConfigOptionFloatOrPercent(double _value, bool _percent, bool _phony) : ConfigOptionPercent(_value, _phony), percent(_percent) {}
static ConfigOptionType static_type() { return coFloatOrPercent; }
ConfigOptionType type() const override { return static_type(); }
@ -1427,6 +1439,7 @@ public:
throw Slic3r::RuntimeError("ConfigOptionEnum<T>: Assigning an incompatible type");
// rhs could be of the following type: ConfigOptionEnumGeneric or ConfigOptionEnum<T>
this->value = (T)rhs->getInt();
this->phony = rhs->phony;
}
std::string serialize() const override
@ -1511,6 +1524,7 @@ public:
throw Slic3r::RuntimeError("ConfigOptionEnumGeneric: Assigning an incompatible type");
// rhs could be of the following type: ConfigOptionEnumGeneric or ConfigOptionEnum<T>
this->value = rhs->getInt();
this->phony = rhs->phony;
}
std::string serialize() const override
@ -1658,7 +1672,9 @@ public:
// For text input: If true, the GUI formats text as code (fixed-width)
bool is_code = false;
// Not editable. Currently only used for the display of the number of threads.
bool readonly = false;
bool readonly = false;
// Can be phony. if not present at laoding, mark it as phony. Also adapt the gui to look for phony status.
bool can_phony = false;
// Height of a multiline GUI text box.
int height = -1;
// Optional width of an input field.

View File

@ -299,8 +299,8 @@ std::pair<double, double> adaptive_fill_line_spacing(const PrintObject &print_ob
for (const PrintRegion *region : print_object.print()->regions()) {
const PrintRegionConfig &config = region->config();
bool nonempty = config.fill_density > 0;
bool has_adaptive_infill = nonempty && config.fill_pattern == ipAdaptiveCubic;
bool has_support_infill = nonempty && config.fill_pattern == ipSupportCubic;
bool has_adaptive_infill = nonempty && config.fill_pattern.value == ipAdaptiveCubic;
bool has_support_infill = nonempty && config.fill_pattern.value == ipSupportCubic;
double infill_extrusion_width = config.infill_extrusion_width.get_abs_value(max_nozzle_diameter);
region_fill_data.push_back(RegionFillData({
has_adaptive_infill ? Tristate::Maybe : Tristate::No,

View File

@ -743,7 +743,7 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessor::Result* re
namespace DoExport {
static void init_gcode_processor(const PrintConfig& config, GCodeProcessor& processor, bool& silent_time_estimator_enabled)
{
silent_time_estimator_enabled = (config.gcode_flavor == gcfMarlin) && config.silent_mode;
silent_time_estimator_enabled = (config.gcode_flavor.value == gcfMarlin) && config.silent_mode;
processor.reset();
processor.apply_config(config);
processor.enable_stealth_time_estimator(silent_time_estimator_enabled);
@ -1490,7 +1490,7 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
bbox_prime.offset(0.5f);
bool overlap = bbox_prime.overlap(bbox_print);
if (print.config().gcode_flavor == gcfMarlin) {
if (print.config().gcode_flavor.value == gcfMarlin) {
_write(file, this->retract());
_write(file, "M300 S800 P500\n"); // Beep for 500ms, tone 800Hz.
if (overlap) {
@ -1727,14 +1727,14 @@ void GCode::print_machine_envelope(FILE *file, Print &print)
int(print.config().machine_max_acceleration_travel.values.front() + 0.5),
int(print.config().machine_max_acceleration_travel.values.front() + 0.5));
if (std::set<uint8_t>{gcfMarlin, gcfLerdge, gcfRepetier, gcfSmoothie, gcfSprinter}.count(print.config().gcode_flavor.value) > 0)
fprintf(file, (print.config().gcode_flavor == gcfMarlin || print.config().gcode_flavor == gcfSmoothie)
fprintf(file, (print.config().gcode_flavor.value == gcfMarlin || print.config().gcode_flavor.value == gcfSmoothie)
? "M203 X%d Y%d Z%d E%d ; sets maximum feedrates, mm/sec\n"
: "M203 X%d Y%d Z%d E%d ; sets maximum feedrates, mm/min\n",
int(print.config().machine_max_feedrate_x.values.front() + 0.5),
int(print.config().machine_max_feedrate_y.values.front() + 0.5),
int(print.config().machine_max_feedrate_z.values.front() + 0.5),
int(print.config().machine_max_feedrate_e.values.front() + 0.5));
if (print.config().gcode_flavor == gcfRepRap) {
if (print.config().gcode_flavor.value == gcfRepRap) {
fprintf(file, "M203 X%d Y%d Z%d E%d I%d; sets maximum feedrates, mm/min\n",
int(print.config().machine_max_feedrate_x.values.front() + 0.5),
int(print.config().machine_max_feedrate_y.values.front() + 0.5),
@ -1806,7 +1806,7 @@ void GCode::_print_first_layer_extruder_temperatures(FILE *file, Print &print, c
{
// Is the bed temperature set by the provided custom G-code?
int temp_by_gcode = -1;
bool include_g10 = print.config().gcode_flavor == gcfRepRap;
bool include_g10 = print.config().gcode_flavor.value == gcfRepRap;
if (custom_gcode_sets_temperature(gcode, 104, 109, include_g10, temp_by_gcode)) {
// Set the extruder temperature at m_writer, but throw away the generated G-code as it will be written with the custom G-code.
int temp = print.config().first_layer_temperature.get_at(first_printing_extruder_id);

View File

@ -6,9 +6,9 @@
#include <map>
#include <assert.h>
#define FLAVOR_IS(val) this->config.gcode_flavor == val
#define FLAVOR_IS_NOT(val) this->config.gcode_flavor != val
#define COMMENT(comment) if (this->config.gcode_comments && !comment.empty()) gcode << " ; " << comment;
#define FLAVOR_IS(val) this->config.gcode_flavor.value == val
#define FLAVOR_IS_NOT(val) this->config.gcode_flavor.value != val
#define COMMENT(comment) if (this->config.gcode_comments.value && !comment.empty()) gcode << " ; " << comment;
#define PRECISION(val, precision) std::fixed << std::setprecision(precision) << (val)
#define XYZF_NUM(val) PRECISION(val, this->config.gcode_precision_xyz.value)
#define E_NUM(val) PRECISION(val, this->config.gcode_precision_e.get_at(m_tool->id()))

View File

@ -156,7 +156,7 @@ void PerimeterGenerator::process()
ExPolygons bridgeable = union_ex(detector.coverage(-1, true));
if (!bridgeable.empty()) {
//check if we get everything or just the bridgeable area
if (this->config->no_perimeter_unsupported_algo == npuaNoPeri || this->config->no_perimeter_unsupported_algo == npuaFilled) {
if (this->config->no_perimeter_unsupported_algo.value == npuaNoPeri || this->config->no_perimeter_unsupported_algo.value == npuaFilled) {
//we bridge everything, even the not-bridgeable bits
for (size_t i = 0; i < unsupported_filtered.size();) {
ExPolygon &poly_unsupp = *(unsupported_filtered.begin() + i);
@ -177,7 +177,7 @@ void PerimeterGenerator::process()
}
unsupported_filtered = intersection_ex(last,
offset2_ex(unsupported_filtered, double(-perimeter_spacing / 2), double(perimeter_spacing * 3 / 2)));
if (this->config->no_perimeter_unsupported_algo == npuaFilled) {
if (this->config->no_perimeter_unsupported_algo.value == npuaFilled) {
for (ExPolygon &expol : unsupported_filtered) {
//check if the holes won't be covered by the upper layer
//TODO: if we want to do that, we must modify the geometry before making perimeters.
@ -227,7 +227,7 @@ void PerimeterGenerator::process()
}
//TODO: add other polys as holes inside this one (-margin)
} else if (this->config->no_perimeter_unsupported_algo == npuaBridgesOverhangs || this->config->no_perimeter_unsupported_algo == npuaBridges){
} else if (this->config->no_perimeter_unsupported_algo.value == npuaBridgesOverhangs || this->config->no_perimeter_unsupported_algo.value == npuaBridges){
//simplify to avoid most of artefacts from printing lines.
ExPolygons bridgeable_simplified;
for (ExPolygon &poly : bridgeable) {
@ -246,7 +246,7 @@ void PerimeterGenerator::process()
//unbridgeable = offset2_ex(unbridgeable, -ext_perimeter_width, ext_perimeter_width);
if (this->config->no_perimeter_unsupported_algo == npuaBridges) {
if (this->config->no_perimeter_unsupported_algo.value == npuaBridges) {
ExPolygons unbridgeable = unsupported_filtered;
for (ExPolygon &expol : unbridgeable)
expol.holes.clear();

View File

@ -535,9 +535,23 @@ const std::vector<std::string>& Preset::print_options()
"extruder_clearance_radius",
"extruder_clearance_height", "gcode_comments", "gcode_label_objects", "output_filename_format", "post_process", "perimeter_extruder",
"infill_extruder", "solid_infill_extruder", "support_material_extruder", "support_material_interface_extruder",
"ooze_prevention", "standby_temperature_delta", "interface_shells", "extrusion_width", "first_layer_extrusion_width",
"perimeter_extrusion_width", "external_perimeter_extrusion_width", "infill_extrusion_width", "solid_infill_extrusion_width",
"top_infill_extrusion_width", "support_material_extrusion_width", "infill_overlap", "bridge_flow_ratio",
"ooze_prevention", "standby_temperature_delta", "interface_shells",
"extrusion_spacing",
"extrusion_width",
"first_layer_extrusion_spacing",
"first_layer_extrusion_width",
"perimeter_extrusion_spacing",
"perimeter_extrusion_width",
"external_perimeter_extrusion_spacing",
"external_perimeter_extrusion_width",
"infill_extrusion_spacing",
"infill_extrusion_width",
"solid_infill_extrusion_spacing",
"solid_infill_extrusion_width",
"top_infill_extrusion_spacing",
"top_infill_extrusion_width",
"support_material_extrusion_width",
"infill_overlap", "bridge_flow_ratio",
"infill_anchor",
"infill_anchor_max",
"clip_multipart_objects",
@ -1373,7 +1387,9 @@ inline t_config_option_keys deep_diff(const ConfigBase &config_this, const Confi
for (const t_config_option_key &opt_key : config_this.keys()) {
const ConfigOption *this_opt = config_this.option(opt_key);
const ConfigOption *other_opt = config_other.option(opt_key);
if (this_opt != nullptr && other_opt != nullptr && *this_opt != *other_opt)
//dirty if both exist, they aren't both phony and value is different
if (this_opt != nullptr && other_opt != nullptr && !(this_opt->phony && other_opt->phony)
&& ((*this_opt != *other_opt) || (this_opt->phony != other_opt->phony)))
{
if (opt_key == "bed_shape" || opt_key == "thumbnails" || opt_key == "compatible_prints" || opt_key == "compatible_printers") {
// Scalar variable, or a vector variable, which is independent from number of extruders,

View File

@ -1535,7 +1535,7 @@ std::pair<PrintBase::PrintValidationError, std::string> Print::validate() const
"all nozzles have to be of the same diameter.") };
}
if (this->has_wipe_tower()) {
if (object->config().support_material_contact_distance_type == zdNone) {
if (object->config().support_material_contact_distance_type.value == zdNone) {
// Soluble interface
if (! object->config().support_material_synchronize_layers)
return { PrintBase::PrintValidationError::pveWrongSettings,L("For the Wipe Tower to work with the soluble supports, the support layers need to be synchronized with the object layers.") };

View File

@ -830,9 +830,23 @@ void PrintConfigDef::init_fff_params()
def->sidetext = L("mm or %");
def->ratio_over = "nozzle_diameter";
def->min = 0;
def->can_phony = true;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloatOrPercent(0, false));
def = this->add("external_perimeter_extrusion_spacing", coFloatOrPercent);
def->label = L("External perimeters");
def->full_label = L("External perimeters spacing");
def->category = OptionCategory::width;
def->tooltip = L("Like the External perimeters width, but this value is the distance between the edge and the 'frontier' to the next perimeter."
"\nSetting the spacing will deactivate the width setting, and vice versa.");
def->sidetext = L("mm or %");
def->ratio_over = "nozzle_diameter";
def->min = 0;
def->can_phony = true;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloatOrPercent(0, false, true));
def = this->add("external_perimeter_cut_corners", coPercent);
def->label = L("Cutting corners");
def->full_label = L("Ext. peri. cut corners");
@ -1140,16 +1154,30 @@ void PrintConfigDef::init_fff_params()
def->label = L("Default extrusion width");
def->category = OptionCategory::width;
def->tooltip = L("Set this to a non-zero value to allow a manual extrusion width. "
"If left to zero, Slic3r derives extrusion widths from the nozzle diameter "
"(see the tooltips for perimeter extrusion width, infill extrusion width etc). "
"If expressed as percentage (for example: 105%), it will be computed over nozzle diameter.");
"If left to zero, Slic3r derives extrusion widths from the nozzle diameter "
"(see the tooltips for perimeter extrusion width, infill extrusion width etc). "
"If expressed as percentage (for example: 105%), it will be computed over nozzle diameter.");
def->sidetext = L("mm or %");
def->ratio_over = "nozzle_diameter";
def->min = 0;
def->max = 1000;
def->can_phony = true;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloatOrPercent(0, false));
def = this->add("extrusion_spacing", coFloatOrPercent);
def->label = L("Default extrusion spacing");
def->category = OptionCategory::width;
def->tooltip = L("Like Default extrusion width but spacing is the distance between two lines (as they overlap a bit, it's not the same)."
"\nSetting the spacing will deactivate the width setting, and vice versa.");
def->sidetext = L("mm or %");
def->ratio_over = "nozzle_diameter";
def->min = 0;
def->max = 1000;
def->can_phony = true;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloatOrPercent(0, false, true));
def = this->add("fan_always_on", coBools);
def->label = L("Keep fan always on");
def->category = OptionCategory::cooling;
@ -1709,16 +1737,32 @@ void PrintConfigDef::init_fff_params()
def->full_label = L("First layer width");
def->category = OptionCategory::width;
def->tooltip = L("Set this to a non-zero value to set a manual extrusion width for first layer. "
"You can use this to force fatter extrudates for better adhesion. If expressed "
"as percentage (for example 140%) it will be computed over the nozzle diameter "
"of the nozzle used for the type of extrusion. "
"If set to zero, it will use the default extrusion width.");
"You can use this to force fatter extrudates for better adhesion. If expressed "
"as percentage (for example 140%) it will be computed over the nozzle diameter "
"of the nozzle used for the type of extrusion. "
"If set to zero, it will use the default extrusion width.");
def->sidetext = L("mm or %");
def->ratio_over = "nozzle_diameter";
def->min = 0;
def->max = 1000;
def->can_phony = true;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloatOrPercent(140, true));
def = this->add("first_layer_extrusion_spacing", coFloatOrPercent);
def->label = L("First layer");
def->full_label = L("First layer spacing");
def->category = OptionCategory::width;
def->tooltip = L("Like First layer width but spacing is the distance between two lines (as they overlap a bit, it's not the same)."
"\nSetting the spacing will deactivate the width setting, and vice versa.");
def->sidetext = L("mm or %");
def->ratio_over = "nozzle_diameter";
def->min = 0;
def->max = 1000;
def->can_phony = true;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloatOrPercent(0, false, true));
def = this->add("first_layer_height", coFloatOrPercent);
def->label = L("First layer height");
def->category = OptionCategory::perimeter;
@ -2086,17 +2130,34 @@ void PrintConfigDef::init_fff_params()
def = this->add("infill_extrusion_width", coFloatOrPercent);
def->label = L("Infill");
def->full_label = L("Infill width");
def->category = OptionCategory::width;
def->tooltip = L("Set this to a non-zero value to set a manual extrusion width for infill. "
"If left zero, default extrusion width will be used if set, otherwise 1.125 x nozzle diameter will be used. "
"You may want to use fatter extrudates to speed up the infill and make your parts stronger. "
"If expressed as percentage (for example 110%) it will be computed over nozzle diameter.");
"If left zero, default extrusion width will be used if set, otherwise 1.125 x nozzle diameter will be used. "
"You may want to use fatter extrudates to speed up the infill and make your parts stronger. "
"If expressed as percentage (for example 110%) it will be computed over nozzle diameter.");
def->sidetext = L("mm or %");
def->ratio_over = "nozzle_diameter";
def->min = 0;
def->max = 1000;
def->can_phony = true;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloatOrPercent(0, false));
def = this->add("infill_extrusion_spacing", coFloatOrPercent);
def->label = L("Infill");
def->full_label = L("Infill spacing");
def->category = OptionCategory::width;
def->tooltip = L("Like First layer width but spacing is the distance between two lines (as they overlap a bit, it's not the same)."
"\nSetting the spacing will deactivate the width setting, and vice versa.");
def->sidetext = L("mm or %");
def->ratio_over = "nozzle_diameter";
def->min = 0;
def->max = 1000;
def->can_phony = true;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloatOrPercent(0, false, true));
def = this->add("infill_first", coBool);
def->label = L("Infill before perimeters");
def->category = OptionCategory::infill;
@ -2799,15 +2860,31 @@ void PrintConfigDef::init_fff_params()
def->full_label = ("Perimeter width");
def->category = OptionCategory::width;
def->tooltip = L("Set this to a non-zero value to set a manual extrusion width for perimeters. "
"You may want to use thinner extrudates to get more accurate surfaces. "
"If left zero, default extrusion width will be used if set, otherwise 1.125 x nozzle diameter will be used. "
"If expressed as percentage (for example 105%) it will be computed over nozzle diameter.");
"You may want to use thinner extrudates to get more accurate surfaces. "
"If left zero, default extrusion width will be used if set, otherwise 1.125 x nozzle diameter will be used. "
"If expressed as percentage (for example 105%) it will be computed over nozzle diameter.");
def->sidetext = L("mm or %");
def->aliases = { "perimeters_extrusion_width" };
def->min = 0;
def->max = 1000;
def->can_phony = true;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloatOrPercent(0, false));
def = this->add("perimeter_extrusion_spacing", coFloatOrPercent);
def->label = L("Perimeters");
def->full_label = ("Perimeter spacing");
def->category = OptionCategory::width;
def->tooltip = L("Like Perimeter width but spacing is the distance between two perimeter lines (as they overlap a bit, it's not the same)."
"\nSetting the spacing will deactivate the width setting, and vice versa.");
def->sidetext = L("mm or %");
def->aliases = { "perimeters_extrusion_width" };
def->min = 0;
def->max = 1000;
def->can_phony = true;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloatOrPercent(0, false, true));
def = this->add("perimeter_speed", coFloat);
def->label = L("Default");
def->full_label = ("Default speed");
@ -3141,10 +3218,12 @@ void PrintConfigDef::init_fff_params()
def = this->add("skirt_extrusion_width", coFloatOrPercent);
def->label = L("Skirt");
def->full_label = L("Skirt width");
def->category = OptionCategory::width;
def->tooltip = L("Horizontal width of the skirt that will be printed around each object.");
def->sidetext = L("mm");
def->min = 0;
def->max = 1000;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloatOrPercent(0, false));
@ -3306,14 +3385,30 @@ void PrintConfigDef::init_fff_params()
def->full_label = ("Solid infill width");
def->category = OptionCategory::width;
def->tooltip = L("Set this to a non-zero value to set a manual extrusion width for infill for solid surfaces. "
"If left zero, default extrusion width will be used if set, otherwise 1.125 x nozzle diameter will be used. "
"If expressed as percentage (for example 110%) it will be computed over nozzle diameter.");
"If left zero, default extrusion width will be used if set, otherwise 1.125 x nozzle diameter will be used. "
"If expressed as percentage (for example 110%) it will be computed over nozzle diameter.");
def->sidetext = L("mm or %");
def->ratio_over = "nozzle_diameter";
def->min = 0;
def->max = 1000;
def->can_phony = true;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloatOrPercent(0, false));
def = this->add("solid_infill_extrusion_spacing", coFloatOrPercent);
def->label = L("Solid spacing");
def->full_label = ("Solid infill spacing");
def->category = OptionCategory::width;
def->tooltip = L("Like Solid infill width but spacing is the distance between two lines (as they overlap a bit, it's not the same)."
"\nSetting the spacing will deactivate the width setting, and vice versa.");
def->sidetext = L("mm or %");
def->ratio_over = "nozzle_diameter";
def->min = 0;
def->max = 1000;
def->can_phony = true;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloatOrPercent(0, false, true));
def = this->add("solid_infill_speed", coFloatOrPercent);
def->label = L("Solid");
def->full_label = ("Solid infill speed");
@ -3577,11 +3672,12 @@ void PrintConfigDef::init_fff_params()
def->full_label = L("Support material width");
def->category = OptionCategory::width;
def->tooltip = L("Set this to a non-zero value to set a manual extrusion width for support material. "
"If left zero, default extrusion width will be used if set, otherwise nozzle diameter will be used. "
"If expressed as percentage (for example 110%) it will be computed over nozzle diameter.");
"If left zero, default extrusion width will be used if set, otherwise nozzle diameter will be used. "
"If expressed as percentage (for example 110%) it will be computed over nozzle diameter.");
def->sidetext = L("mm or %");
def->ratio_over = "nozzle_diameter";
def->min = 0;
def->max = 1000;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloatOrPercent(0, false));
@ -3857,15 +3953,30 @@ void PrintConfigDef::init_fff_params()
def->label = L("Top solid infill");
def->category = OptionCategory::width;
def->tooltip = L("Set this to a non-zero value to set a manual extrusion width for infill for top surfaces. "
"You may want to use thinner extrudates to fill all narrow regions and get a smoother finish. "
"If left zero, default extrusion width will be used if set, otherwise nozzle diameter will be used. "
"If expressed as percentage (for example 110%) it will be computed over nozzle diameter.");
"You may want to use thinner extrudates to fill all narrow regions and get a smoother finish. "
"If left zero, default extrusion width will be used if set, otherwise nozzle diameter will be used. "
"If expressed as percentage (for example 110%) it will be computed over nozzle diameter.");
def->sidetext = L("mm or %");
def->ratio_over = "nozzle_diameter";
def->min = 0;
def->max = 1000;
def->can_phony = true;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloatOrPercent(0, false));
def = this->add("top_infill_extrusion_spacing", coFloatOrPercent);
def->label = L("Top solid spacing");
def->category = OptionCategory::width;
def->tooltip = L("Like Top solid infill width but spacing is the distance between two lines (as they overlap a bit, it's not the same)."
"\nSetting the spacing will deactivate the width setting, and vice versa.");
def->sidetext = L("mm or %");
def->ratio_over = "nozzle_diameter";
def->min = 0;
def->max = 1000;
def->can_phony = true;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloatOrPercent(0, false, true));
def = this->add("top_solid_infill_speed", coFloatOrPercent);
def->label = L("Top solid");
def->full_label = L("Top solid speed");
@ -5141,6 +5252,12 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va
// In PrusaSlicer 2.3.0-alpha0 the "monotonic" infill was introduced, which was later renamed to "monotonous".
if (value == "monotonous" && (opt_key == "top_fill_pattern" || opt_key == "bottom_fill_pattern" || opt_key == "fill_pattern" || opt_key == "solid_fill_pattern" || opt_key == "support_material_interface_pattern"))
value = "monotonic";
// some changes has occurs between rectilineargapfill and monotonicgapfill. Set them at the right value for each type
if (value == "rectilineargapfill" && (opt_key == "top_fill_pattern" || opt_key == "bottom_fill_pattern" || opt_key == "fill_pattern" || opt_key == "support_material_interface_pattern"))
value = "monotonicgapfill";
if (value == "monotonicgapfill" && (opt_key == "solid_fill_pattern"))
value = "rectilineargapfill";
if (ignore.find(opt_key) != ignore.end()) {
opt_key = "";
@ -5292,7 +5409,14 @@ void PrintConfigDef::to_prusa(t_config_option_key& opt_key, std::string& value,
"milling_post_process",
"milling_extra_size",
"milling_after_z",
"milling_speed"
"milling_speed",
"extrusion_spacing",
"first_layer_extrusion_spacing",
"perimeter_extrusion_spacing",
"external_perimeter_extrusion_spacing",
"infill_extrusion_spacing",
"solid_infill_extrusion_spacing",
"top_infill_extrusion_spacing"
};
//looks if it's to be removed, or have to be transformed
@ -5360,6 +5484,15 @@ void PrintConfigDef::to_prusa(t_config_option_key& opt_key, std::string& value,
value = "marlin";
else if ("klipper" == value)
value = "reprap";
} else if (opt_key.find("extrusion_width") != std::string::npos) {
if (std::set<std::string>{"extrusion_width", "first_layer_extrusion_width", "perimeter_extrusion_width", "external_perimeter_extrusion_width",
"infill_extrusion_width", "solid_infill_extrusion_width", "top_infill_extrusion_width"}.count(opt_key) > 0) {
const ConfigOptionFloatOrPercent* opt = all_conf.option<ConfigOptionFloatOrPercent>(opt_key);
if (opt->phony) {
//bypass the phony kill switch from Config::opt_serialize
value = opt->serialize();
}
}
}
}
@ -5592,6 +5725,7 @@ std::string DynamicPrintConfig::validate()
{
FullPrintConfig fpc;
fpc.apply(*this, true);
// Verify this print options through the FullPrintConfig.
return fpc.validate();
}
@ -5601,6 +5735,261 @@ std::string DynamicPrintConfig::validate()
}
}
template<typename TYPE>
const TYPE* find_option(const t_config_option_key &opt_key, DynamicPrintConfig* default_config, const std::vector<const DynamicPrintConfig*> &other_config) {
const TYPE* option = default_config->option<TYPE>(opt_key);
if (option)
return option;
for (const DynamicPrintConfig* conf : other_config) {
option = conf->option<TYPE>(opt_key);
if (option)
return option;
}
return nullptr;
}
bool DynamicPrintConfig::update_phony(const std::vector<const DynamicPrintConfig*> config_collection) {
bool something_changed = false;
//update width/spacing links
const char* widths[] = { "", "external_perimeter_", "perimeter_", "infill_", "solid_infill_", "top_infill_", "support_material_", "first_layer_", "skirt_" };
for (size_t i = 0; i < sizeof(widths) / sizeof(widths[i]); ++i) {
std::string key_width(widths[i]);
key_width += "extrusion_width";
std::string key_spacing(widths[i]);
key_spacing += "extrusion_spacing";
ConfigOptionFloatOrPercent* width_option = this->option<ConfigOptionFloatOrPercent>(key_width);
ConfigOptionFloatOrPercent* spacing_option = this->option<ConfigOptionFloatOrPercent>(key_spacing);
if (width_option && spacing_option)
if (!spacing_option->phony && width_option->phony)
something_changed |= value_changed(key_spacing, config_collection);
else
something_changed |= value_changed(key_width, config_collection);
}
return something_changed;
}
bool DynamicPrintConfig::value_changed(const t_config_option_key& opt_key, const std::vector<const DynamicPrintConfig*> config_collection) {
if (opt_key == "layer_height") {
update_phony(config_collection);
}
bool something_changed = false;
// width -> spacing
if (opt_key.find("extrusion_spacing") != std::string::npos) {
const ConfigOptionFloats* nozzle_diameter_option = find_option<ConfigOptionFloats>("nozzle_diameter", this, config_collection);
const ConfigOptionFloat* layer_height_option = find_option<ConfigOptionFloat>("layer_height", this, config_collection);
ConfigOptionFloatOrPercent* spacing_option = this->option<ConfigOptionFloatOrPercent>(opt_key);
if (layer_height_option && spacing_option && nozzle_diameter_option) {
//compute spacing with current height and change the width
double max_nozzle_diameter = 0;
for (double dmr : nozzle_diameter_option->values)
max_nozzle_diameter = std::max(max_nozzle_diameter, dmr);
Flow flow = Flow::new_from_spacing(spacing_option->get_abs_value(max_nozzle_diameter), max_nozzle_diameter, layer_height_option->value, false);
if (opt_key == "extrusion_spacing") {
ConfigOptionFloatOrPercent* width_option = this->option<ConfigOptionFloatOrPercent>("extrusion_width");
if (width_option) {
width_option->phony = true;
spacing_option->phony = false;
width_option->value = (spacing_option->percent) ? std::round(100 * flow.width / max_nozzle_diameter) : (std::round(flow.width * 10000) / 10000);
width_option->percent = spacing_option->percent;
something_changed = true;
}
}
if (opt_key == "first_layer_extrusion_spacing") {
ConfigOptionFloatOrPercent* width_option = this->option<ConfigOptionFloatOrPercent>("first_layer_extrusion_width");
if (width_option) {
width_option->phony = true;
spacing_option->phony = false;
width_option->value = (spacing_option->percent) ? std::round(100 * flow.width / max_nozzle_diameter) : (std::round(flow.width * 10000) / 10000);
width_option->percent = spacing_option->percent;
something_changed = true;
}
}
if (opt_key == "perimeter_extrusion_spacing") {
const ConfigOptionPercent* perimeter_overlap_option = find_option<ConfigOptionPercent>("perimeter_overlap", this, config_collection);
ConfigOptionFloatOrPercent* width_option = this->option<ConfigOptionFloatOrPercent>("perimeter_extrusion_width");
if (width_option && perimeter_overlap_option) {
width_option->phony = true;
spacing_option->phony = false;
flow.spacing_ratio = perimeter_overlap_option->get_abs_value(1);
flow.width = spacing_option->get_abs_value(max_nozzle_diameter) + layer_height_option->value * (1. - 0.25 * PI) * flow.spacing_ratio;
width_option->value = (spacing_option->percent) ? std::round(100 * flow.width / max_nozzle_diameter) : (std::round(flow.width * 10000) / 10000);
width_option->percent = spacing_option->percent;
something_changed = true;
}
}
if (opt_key == "external_perimeter_extrusion_spacing") {
const ConfigOptionPercent* external_perimeter_overlap_option = find_option<ConfigOptionPercent>("external_perimeter_overlap", this, config_collection);
ConfigOptionFloatOrPercent* width_option = this->option<ConfigOptionFloatOrPercent>("external_perimeter_extrusion_width");
if (width_option && external_perimeter_overlap_option) {
width_option->phony = true;
spacing_option->phony = false;
flow.spacing_ratio = external_perimeter_overlap_option->get_abs_value(0.5);
flow.width = spacing_option->get_abs_value(max_nozzle_diameter) + layer_height_option->value * (1. - 0.25 * PI) * flow.spacing_ratio;
width_option->value = (spacing_option->percent) ? std::round(100 * flow.width / max_nozzle_diameter) : (std::round(flow.width * 10000) / 10000);
width_option->percent = spacing_option->percent;
something_changed = true;
}
}
if (opt_key == "infill_extrusion_spacing") {
ConfigOptionFloatOrPercent* width_option = this->option<ConfigOptionFloatOrPercent>("infill_extrusion_width");
if (width_option) {
width_option->phony = true;
spacing_option->phony = false;
width_option->value = (spacing_option->percent) ? std::round(100 * flow.width / max_nozzle_diameter) : (std::round(flow.width * 10000) / 10000);
width_option->percent = spacing_option->percent;
something_changed = true;
}
}
if (opt_key == "solid_infill_extrusion_spacing") {
ConfigOptionFloatOrPercent* width_option = this->option<ConfigOptionFloatOrPercent>("solid_infill_extrusion_width");
if (width_option) {
width_option->phony = true;
spacing_option->phony = false;
width_option->value = (spacing_option->percent) ? std::round(100 * flow.width / max_nozzle_diameter) : (std::round(flow.width * 10000) / 10000);
width_option->percent = spacing_option->percent;
something_changed = true;
}
}
if (opt_key == "top_infill_extrusion_spacing") {
ConfigOptionFloatOrPercent* width_option = this->option<ConfigOptionFloatOrPercent>("top_infill_extrusion_width");
if (width_option) {
width_option->phony = true;
spacing_option->phony = false;
width_option->value = (spacing_option->percent) ? std::round(100 * flow.width / max_nozzle_diameter) : (std::round(flow.width * 10000) / 10000);
width_option->percent = spacing_option->percent;
something_changed = true;
}
}
/*if (opt_key == "support_material_extrusion_spacing") {
if (spacing_option->percent)
this->set_key_value("support_material_extrusion_width", new ConfigOptionFloatOrPercent(std::round(100 * flow.width / max_nozzle_diameter), true));
else
this->set_key_value("support_material_extrusion_width", new ConfigOptionFloatOrPercent(std::round(flow.width * 10000) / 10000, false));
something_changed = true;
}
if (opt_key == "skirt_extrusion_spacing") {
if (spacing_option->percent)
this->set_key_value("skirt_extrusion_width", new ConfigOptionFloatOrPercent(std::round(100 * flow.width / max_nozzle_diameter), true));
else
this->set_key_value("skirt_extrusion_width", new ConfigOptionFloatOrPercent(std::round(flow.width * 10000) / 10000, false));
something_changed = true;
}*/
}
}
if (opt_key.find("extrusion_width") != std::string::npos) {
const ConfigOptionFloats* nozzle_diameter_option = find_option<ConfigOptionFloats>("nozzle_diameter", this, config_collection);
const ConfigOptionFloat* layer_height_option = find_option<ConfigOptionFloat>("layer_height", this, config_collection);
ConfigOptionFloatOrPercent* width_option = this->option<ConfigOptionFloatOrPercent>(opt_key);
if (layer_height_option && width_option && nozzle_diameter_option) {
//compute spacing with current height and change the width
double max_nozzle_diameter = 0;
for (double dmr : nozzle_diameter_option->values)
max_nozzle_diameter = std::max(max_nozzle_diameter, dmr);
if (opt_key == "extrusion_width") {
ConfigOptionFloatOrPercent* spacing_option = this->option<ConfigOptionFloatOrPercent>("extrusion_spacing");
if (width_option) {
width_option->phony = false;
spacing_option->phony = true;
Flow flow = Flow::new_from_config_width(FlowRole::frPerimeter, *width_option, max_nozzle_diameter, layer_height_option->value, 0);
spacing_option->value = (width_option->percent) ? std::round(100 * flow.spacing() / max_nozzle_diameter) : (std::round(flow.spacing() * 10000) / 10000);
spacing_option->percent = width_option->percent;
something_changed = true;
}
}
if (opt_key == "first_layer_extrusion_width") {
ConfigOptionFloatOrPercent* spacing_option = this->option<ConfigOptionFloatOrPercent>("first_layer_extrusion_spacing");
if (width_option) {
width_option->phony = false;
spacing_option->phony = true;
Flow flow = Flow::new_from_config_width(FlowRole::frPerimeter, *width_option, max_nozzle_diameter, layer_height_option->value, 0);
spacing_option->value = (width_option->percent) ? std::round(100 * flow.spacing() / max_nozzle_diameter) : (std::round(flow.spacing() * 10000) / 10000);
spacing_option->percent = width_option->percent;
something_changed = true;
}
}
if (opt_key == "perimeter_extrusion_width") {
const ConfigOptionPercent* perimeter_overlap_option = find_option<ConfigOptionPercent>("perimeter_overlap", this, config_collection);
ConfigOptionFloatOrPercent* spacing_option = this->option<ConfigOptionFloatOrPercent>("perimeter_extrusion_spacing");
if (width_option && perimeter_overlap_option) {
width_option->phony = false;
spacing_option->phony = true;
Flow flow = Flow::new_from_config_width(FlowRole::frExternalPerimeter, *width_option, max_nozzle_diameter, layer_height_option->value, 0);
flow.spacing_ratio = perimeter_overlap_option->get_abs_value(1);
spacing_option->value = (width_option->percent) ? std::round(100 * flow.spacing() / max_nozzle_diameter) : (std::round(flow.spacing() * 10000) / 10000);
spacing_option->percent = width_option->percent;
something_changed = true;
}
}
if (opt_key == "external_perimeter_extrusion_width") {
const ConfigOptionPercent* external_perimeter_overlap_option = find_option<ConfigOptionPercent>("external_perimeter_overlap", this, config_collection);
ConfigOptionFloatOrPercent* spacing_option = this->option<ConfigOptionFloatOrPercent>("external_perimeter_extrusion_spacing");
if (width_option && external_perimeter_overlap_option) {
width_option->phony = false;
spacing_option->phony = true;
Flow ext_perimeter_flow = Flow::new_from_config_width(FlowRole::frPerimeter, *width_option, max_nozzle_diameter, layer_height_option->value, 0);
ext_perimeter_flow.spacing_ratio = external_perimeter_overlap_option->get_abs_value(0.5);
spacing_option->value = (width_option->percent) ? std::round(100 * ext_perimeter_flow.spacing() / max_nozzle_diameter) : (std::round(ext_perimeter_flow.spacing() * 10000) / 10000);
spacing_option->percent = width_option->percent;
something_changed = true;
}
}
if (opt_key == "infill_extrusion_width") {
ConfigOptionFloatOrPercent* spacing_option = this->option<ConfigOptionFloatOrPercent>("infill_extrusion_spacing");
if (width_option) {
width_option->phony = false;
spacing_option->phony = true;
Flow flow = Flow::new_from_config_width(FlowRole::frInfill, *width_option, max_nozzle_diameter, layer_height_option->value, 0);
spacing_option->value = (width_option->percent) ? std::round(100 * flow.spacing() / max_nozzle_diameter) : (std::round(flow.spacing() * 10000) / 10000);
spacing_option->percent = width_option->percent;
something_changed = true;
}
}
if (opt_key == "solid_infill_extrusion_width") {
ConfigOptionFloatOrPercent* spacing_option = this->option<ConfigOptionFloatOrPercent>("solid_infill_extrusion_spacing");
if (width_option) {
width_option->phony = false;
spacing_option->phony = true;
Flow flow = Flow::new_from_config_width(FlowRole::frSolidInfill, *width_option, max_nozzle_diameter, layer_height_option->value, 0);
spacing_option->value = (width_option->percent) ? std::round(100 * flow.spacing() / max_nozzle_diameter) : (std::round(flow.spacing() * 10000) / 10000);
spacing_option->percent = width_option->percent;
something_changed = true;
}
}
if (opt_key == "top_infill_extrusion_width") {
ConfigOptionFloatOrPercent* spacing_option = this->option<ConfigOptionFloatOrPercent>("top_infill_extrusion_spacing");
if (width_option) {
width_option->phony = false;
spacing_option->phony = true;
Flow flow = Flow::new_from_config_width(FlowRole::frTopSolidInfill, *width_option, max_nozzle_diameter, layer_height_option->value, 0);
spacing_option->value = (width_option->percent) ? std::round(100 * flow.spacing() / max_nozzle_diameter) : (std::round(flow.spacing() * 10000) / 10000);
spacing_option->percent = width_option->percent;
something_changed = true;
}
}
//if (opt_key == "support_material_extrusion_width") {
// Flow flow = Flow::new_from_config_width(FlowRole::frSupportMaterial, *width_option, max_nozzle_diameter, layer_height_option->value, 0);
// if (width_option->percent)
// this->set_key_value("support_material_extrusion_spacing", new ConfigOptionFloatOrPercent(std::round(100 * flow.spacing() / max_nozzle_diameter), true));
// else
// this->set_key_value("support_material_extrusion_spacing", new ConfigOptionFloatOrPercent(std::round(flow.spacing() * 10000) / 10000, false));
// something_changed = true;
//}
//if (opt_key == "skirt_extrusion_width") {
// Flow flow = Flow::new_from_config_width(FlowRole::frPerimeter, *width_option, max_nozzle_diameter, layer_height_option->value, 0);
// if (width_option->percent)
// this->set_key_value("skirt_extrusion_spacing", new ConfigOptionFloatOrPercent(std::round(100 * flow.spacing() / max_nozzle_diameter), true));
// else
// this->set_key_value("skirt_extrusion_spacing", new ConfigOptionFloatOrPercent(std::round(flow.spacing() * 10000) / 10000, false));
// something_changed = true;
//}
}
}
return something_changed;
}
//FIXME localize this function.
std::string FullPrintConfig::validate()
{
@ -5701,8 +6090,8 @@ std::string FullPrintConfig::validate()
return "Invalid value for --extrusion-multiplier";
// --default-acceleration
if ((this->perimeter_acceleration != 0. || this->infill_acceleration != 0. || this->bridge_acceleration != 0. || this->first_layer_acceleration != 0.) &&
this->default_acceleration == 0.)
if ((this->perimeter_acceleration.value != 0. || this->infill_acceleration.value != 0. || this->bridge_acceleration.value != 0. || this->first_layer_acceleration.value != 0.) &&
this->default_acceleration.value == 0.)
return "Invalid zero value for --default-acceleration when using other acceleration settings";
// --spiral-vase
@ -5732,10 +6121,10 @@ std::string FullPrintConfig::validate()
double max_nozzle_diameter = 0.;
for (double dmr : this->nozzle_diameter.values)
max_nozzle_diameter = std::max(max_nozzle_diameter, dmr);
const char *widths[] = { "external_perimeter", "perimeter", "infill", "solid_infill", "top_infill", "support_material", "first_layer" };
const char *widths[] = { "", "external_perimeter_", "perimeter_", "infill_", "solid_infill_", "top_infill_", "support_material_", "first_layer_", "skirt_" };
for (size_t i = 0; i < sizeof(widths) / sizeof(widths[i]); ++ i) {
std::string key(widths[i]);
key += "_extrusion_width";
key += "extrusion_width";
if (this->get_abs_value(key, max_nozzle_diameter) > 10. * max_nozzle_diameter)
return std::string("Invalid extrusion width (too large): ") + key;
}

View File

@ -456,6 +456,13 @@ public:
void to_prusa(t_config_option_key& opt_key, std::string& value) const override
{ PrintConfigDef::to_prusa(opt_key, value, *this); }
/// <summary>
/// callback to changed other settings that are linked (like width & spacing)
/// </summary>
/// <param name="opt_key">name of the changed option</param>
bool value_changed(const t_config_option_key& opt_key, const std::vector<const DynamicPrintConfig*> config_collection);
bool update_phony(const std::vector<const DynamicPrintConfig*> config_collection);
};
class StaticPrintConfig : public StaticConfig

View File

@ -725,7 +725,7 @@ namespace Slic3r {
steps.emplace_back(posSlice);
} else if (opt_key == "support_material") {
steps.emplace_back(posSupportMaterial);
if (m_config.support_material_contact_distance_top == 0. || m_config.support_material_contact_distance_bottom == 0.) {
if (m_config.support_material_contact_distance_top.value == 0. || m_config.support_material_contact_distance_bottom.value == 0.) {
// Enabling / disabling supports while soluble support interface is enabled.
// This changes the bridging logic (bridging enabled without supports, disabled with supports).
// Reset everything.
@ -1091,20 +1091,20 @@ namespace Slic3r {
if (!intersect.empty()) {
double area_intersect = 0;
// calculate area to decide if area is small enough for autofill
if (layerm->region()->config().infill_dense_algo == dfaAutoNotFull || layerm->region()->config().infill_dense_algo == dfaAutoOrEnlarged)
if (layerm->region()->config().infill_dense_algo.value == dfaAutoNotFull || layerm->region()->config().infill_dense_algo.value == dfaAutoOrEnlarged)
for (ExPolygon poly_inter : intersect)
area_intersect += poly_inter.area();
if (layerm->region()->config().infill_dense_algo == dfaEnlarged
|| (layerm->region()->config().infill_dense_algo == dfaAutoOrEnlarged && surf.area() <= area_intersect * COEFF_SPLIT)) {
if (layerm->region()->config().infill_dense_algo.value == dfaEnlarged
|| (layerm->region()->config().infill_dense_algo.value == dfaAutoOrEnlarged && surf.area() <= area_intersect * COEFF_SPLIT)) {
//expand the area a bit
intersect = offset_ex(intersect, double(scale_(layerm->region()->config().external_infill_margin.get_abs_value(
region->config().perimeters == 0 ? 0 : (layerm->flow(frExternalPerimeter).width + layerm->flow(frPerimeter).spacing() * (region->config().perimeters - 1))))));
} else if (layerm->region()->config().infill_dense_algo == dfaAutoNotFull
|| layerm->region()->config().infill_dense_algo == dfaAutomatic) {
} else if (layerm->region()->config().infill_dense_algo.value == dfaAutoNotFull
|| layerm->region()->config().infill_dense_algo.value == dfaAutomatic) {
//like intersect.empty() but more resilient
if (layerm->region()->config().infill_dense_algo == dfaAutomatic
if (layerm->region()->config().infill_dense_algo.value == dfaAutomatic
|| surf.area() > area_intersect * COEFF_SPLIT) {
ExPolygons cover_intersect;
@ -1237,7 +1237,7 @@ namespace Slic3r {
Polygons layerm_slices_surfaces = to_polygons(layerm->slices().surfaces);
// no_perimeter_full_bridge allow to put bridges where there are nothing, hence adding area to slice, that's why we need to start from the result of PerimeterGenerator.
if (layerm->region()->config().no_perimeter_unsupported_algo == npuaFilled) {
if (layerm->region()->config().no_perimeter_unsupported_algo.value == npuaFilled) {
layerm_slices_surfaces = union_(layerm_slices_surfaces, to_polygons(layerm->fill_surfaces));
}
@ -3512,11 +3512,11 @@ namespace Slic3r {
0.5f * layerms.back()->flow(frPerimeter).scaled_width() +
// Because fill areas for rectilinear and honeycomb are grown
// later to overlap perimeters, we need to counteract that too.
((region->config().fill_pattern == ipRectilinear ||
region->config().fill_pattern == ipMonotonic ||
region->config().fill_pattern == ipGrid ||
region->config().fill_pattern == ipLine ||
region->config().fill_pattern == ipHoneycomb) ? 1.5f : 0.5f) *
((region->config().fill_pattern.value == ipRectilinear ||
region->config().fill_pattern.value == ipMonotonic ||
region->config().fill_pattern.value == ipGrid ||
region->config().fill_pattern.value == ipLine ||
region->config().fill_pattern.value == ipHoneycomb) ? 1.5f : 0.5f) *
layerms.back()->flow(frSolidInfill).scaled_width();
for (ExPolygon& expoly : intersection)
polygons_append(intersection_with_clearance, offset(expoly, clearance_offset));

View File

@ -1242,7 +1242,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_
// it will support layers printed with a bridging flow.
if (SupportMaterialInternal::has_bridging_extrusions(layer)) {
coordf_t bridging_height = layer.height;
if (m_object_config->support_material_contact_distance_type == zdFilament) {
if (m_object_config->support_material_contact_distance_type.value == zdFilament) {
bridging_height = 0.;
for (const LayerRegion *region : layer.regions())
bridging_height += region->region()->bridging_height_avg(*m_print_config);
@ -1513,7 +1513,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::bottom_conta
// According to Jindrich the bottom surfaces work well.
//FIXME test the bridging flow instead?
m_support_material_interface_flow.nozzle_diameter;
layer_new.height_block = ((m_object_config->support_material_contact_distance_type == zdPlane) ? object.layers()[layer_id + 1]->height : layer_new.height);
layer_new.height_block = ((m_object_config->support_material_contact_distance_type.value == zdPlane) ? object.layers()[layer_id + 1]->height : layer_new.height);
layer_new.print_z = m_slicing_params.soluble_interface ? object.layers()[layer_id + 1]->print_z :
(layer.print_z + layer_new.height_block + this->m_slicing_params.gap_object_support);
layer_new.bottom_z = layer.print_z;
@ -2135,7 +2135,7 @@ void PrintObjectSupportMaterial::trim_support_layers_by_object(
const Layer &object_layer = *object.layers()[i];
bool some_region_overlaps = false;
for (LayerRegion *region : object_layer.regions()) {
coordf_t bridging_height = m_object_config->support_material_contact_distance_type == zdFilament
coordf_t bridging_height = m_object_config->support_material_contact_distance_type.value == zdFilament
? region->region()->bridging_height_avg(*this->m_print_config)
: object_layer.height;
if (object_layer.print_z - bridging_height > support_layer.print_z + gap_extra_above - EPSILON)

View File

@ -50,6 +50,18 @@ ButtonsDescription::ButtonsDescription(wxWindow* parent, const std::vector<Entry
grid_sizer->Add(sys_colour, -1, wxALIGN_CENTRE_VERTICAL);
grid_sizer->Add(sys_label, -1, wxALIGN_CENTRE_VERTICAL | wxEXPAND);
auto default_label = new wxStaticText(this, wxID_ANY, _(L("Value is the same as the last saved preset, but is not the system value")));
default_label->SetForegroundColour(wxGetApp().get_label_clr_default());
auto default_colour = new wxColourPickerCtrl(this, wxID_ANY, wxGetApp().get_label_clr_default());
default_colour->Bind(wxEVT_COLOURPICKER_CHANGED, ([default_colour, default_label](wxCommandEvent e)
{
default_label->SetForegroundColour(default_colour->GetColour());
default_label->Refresh();
}));
grid_sizer->Add(0, -1, wxALIGN_CENTRE_VERTICAL);
grid_sizer->Add(default_colour, -1, wxALIGN_CENTRE_VERTICAL);
grid_sizer->Add(default_label, -1, wxALIGN_CENTRE_VERTICAL | wxEXPAND);
auto mod_label = new wxStaticText(this, wxID_ANY, _(L("Value was changed and is not equal to the system value or the last saved preset")));
mod_label->SetForegroundColour(wxGetApp().get_label_clr_modified());
auto mod_colour = new wxColourPickerCtrl(this, wxID_ANY, wxGetApp().get_label_clr_modified());
@ -61,15 +73,29 @@ ButtonsDescription::ButtonsDescription(wxWindow* parent, const std::vector<Entry
grid_sizer->Add(0, -1, wxALIGN_CENTRE_VERTICAL);
grid_sizer->Add(mod_colour, -1, wxALIGN_CENTRE_VERTICAL);
grid_sizer->Add(mod_label, -1, wxALIGN_CENTRE_VERTICAL | wxEXPAND);
auto phony_label = new wxStaticText(this, wxID_ANY, _(L("Value isn't taken into account, it's computed over an other field.")));
phony_label->SetForegroundColour(wxGetApp().get_label_clr_phony());
auto phony_colour = new wxColourPickerCtrl(this, wxID_ANY, wxGetApp().get_label_clr_phony());
phony_colour->Bind(wxEVT_COLOURPICKER_CHANGED, ([phony_colour, phony_label](wxCommandEvent e)
{
phony_label->SetForegroundColour(phony_colour->GetColour());
phony_label->Refresh();
}));
grid_sizer->Add(0, -1, wxALIGN_CENTRE_VERTICAL);
grid_sizer->Add(phony_colour, -1, wxALIGN_CENTRE_VERTICAL);
grid_sizer->Add(phony_label, -1, wxALIGN_CENTRE_VERTICAL | wxEXPAND);
auto buttons = CreateStdDialogButtonSizer(wxOK|wxCANCEL);
main_sizer->Add(buttons, 0, wxALIGN_CENTER_HORIZONTAL | wxBOTTOM, 10);
wxButton* btn = static_cast<wxButton*>(FindWindowById(wxID_OK, this));
btn->Bind(wxEVT_BUTTON, [sys_colour, mod_colour, this](wxCommandEvent&) {
btn->Bind(wxEVT_BUTTON, [sys_colour, mod_colour, default_colour, phony_colour, this](wxCommandEvent&) {
wxGetApp().set_label_clr_sys(sys_colour->GetColour());
wxGetApp().set_label_clr_modified(mod_colour->GetColour());
wxGetApp().set_label_clr_default(default_colour->GetColour());
wxGetApp().set_label_clr_phony(phony_colour->GetColour());
EndModal(wxID_OK);
});

View File

@ -1033,6 +1033,7 @@ void GUI_App::init_label_colours()
m_color_label_sys = wxColour(26, 132, 57);
}
m_color_label_default = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
m_color_label_phony = wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT);
}
void GUI_App::update_label_colours_from_appconfig()
@ -1048,6 +1049,18 @@ void GUI_App::update_label_colours_from_appconfig()
if (str != "")
m_color_label_modified = wxColour(str);
}
if (app_config->has("label_clr_default")) {
auto str = app_config->get("label_clr_default");
if (str != "")
m_color_label_default = wxColour(str);
}
if (app_config->has("label_clr_phony")) {
auto str = app_config->get("label_clr_phony");
if (str != "")
m_color_label_phony = wxColour(str);
}
}
void GUI_App::init_fonts()
@ -1099,6 +1112,22 @@ void GUI_App::set_label_clr_sys(const wxColour& clr) {
app_config->save();
}
void GUI_App::set_label_clr_default(const wxColour& clr) {
m_color_label_default = clr;
auto clr_str = wxString::Format(wxT("#%02X%02X%02X"), clr.Red(), clr.Green(), clr.Blue());
std::string str = clr_str.ToStdString();
app_config->set("label_clr_default", str);
app_config->save();
}
void GUI_App::set_label_clr_phony(const wxColour& clr) {
m_color_label_phony = clr;
auto clr_str = wxString::Format(wxT("#%02X%02X%02X"), clr.Red(), clr.Green(), clr.Blue());
std::string str = clr_str.ToStdString();
app_config->set("label_clr_phony", str);
app_config->save();
}
wxSize GUI_App::get_min_size() const
{
return wxSize(76*m_em_unit, 49 * m_em_unit);
@ -1154,7 +1183,7 @@ void GUI_App::check_printer_presets()
for (const std::string& preset_name : preset_names)
msg_text += "\n \"" + from_u8(preset_name) + "\",";
msg_text.RemoveLast();
msg_text += "\n\n" + _L("But since this version of PrusaSlicer we don't show this information in Printer Settings anymore.\n"
msg_text += "\n\n" + _L("But since this version of " SLIC3R_APP_NAME " we don't show this information in Printer Settings anymore.\n"
"Settings will be available in physical printers settings.") + "\n\n" +
_L("By default new Printer devices will be named as \"Printer N\" during its creation.\n"
"Note: This name can be changed later from the physical printers settings");

View File

@ -116,6 +116,7 @@ private:
wxColour m_color_label_modified;
wxColour m_color_label_sys;
wxColour m_color_label_default;
wxColour m_color_label_phony;
wxFont m_small_font;
wxFont m_bold_font;
@ -171,10 +172,13 @@ public:
void update_fonts(const MainFrame *main_frame = nullptr);
void set_label_clr_modified(const wxColour& clr);
void set_label_clr_sys(const wxColour& clr);
void set_label_clr_default(const wxColour& clr);
void set_label_clr_phony(const wxColour& clr);
const wxColour& get_label_clr_modified(){ return m_color_label_modified; }
const wxColour& get_label_clr_sys() { return m_color_label_sys; }
const wxColour& get_label_clr_default() { return m_color_label_default; }
const wxColour& get_label_clr_phony() { return m_color_label_phony; }
const wxFont& small_font() { return m_small_font; }
const wxFont& bold_font() { return m_bold_font; }

View File

@ -251,6 +251,8 @@ void Tab::create_preset_tab()
for (Tab *tab : wxGetApp().tabs_list) {
tab->m_sys_label_clr = wxGetApp().get_label_clr_sys();
tab->m_modified_label_clr = wxGetApp().get_label_clr_modified();
tab->m_default_text_clr = wxGetApp().get_label_clr_default();
tab->m_phony_text_clr = wxGetApp().get_label_clr_phony();
tab->update_labels_colour();
}
}
@ -260,7 +262,8 @@ void Tab::create_preset_tab()
// Colors for ui "decoration"
m_sys_label_clr = wxGetApp().get_label_clr_sys();
m_modified_label_clr = wxGetApp().get_label_clr_modified();
m_default_text_clr = wxGetApp().get_label_clr_default();
m_default_text_clr = wxGetApp().get_label_clr_default();
m_phony_text_clr = wxGetApp().get_label_clr_phony();
// Sizer with buttons for mode changing
m_mode_sizer = new ModeSizer(panel);
@ -513,6 +516,15 @@ void Tab::update_labels_colour()
else
color = &m_modified_label_clr;
}
if ((opt.second & osCurrentPhony) != 0)
color = &m_phony_text_clr;
else {
if ((opt.second & osInitPhony) != 0)
color = &m_modified_label_clr;
else if ((opt.second & osSystemPhony) != 0)
color = &m_default_text_clr;
}
if (opt.first == "bed_shape" || opt.first == "filament_ramming_parameters" ||
opt.first == "compatible_prints" || opt.first == "compatible_printers" ) {
if (m_colored_Label_colors.find(opt.first) != m_colored_Label_colors.end())
@ -591,7 +603,17 @@ void Tab::decorate()
icon = &m_bmp_white_bullet;
tt = &m_tt_white_bullet;
}
//color for phony things
if ((opt.second & osCurrentPhony) != 0)
color = &m_phony_text_clr;
else {
if ((opt.second & osInitPhony) != 0)
color = &m_modified_label_clr;
else if ((opt.second & osSystemPhony) != 0)
color = &m_default_text_clr;
}
if (colored_label_clr) {
*colored_label_clr = *color;
continue;
@ -634,8 +656,28 @@ void Tab::update_changed_ui()
for (auto& it : m_options_list)
it.second = m_opt_status_value;
for (auto opt_key : dirty_options) m_options_list[opt_key] &= ~osInitValue;
for (auto opt_key : nonsys_options) m_options_list[opt_key] &= ~osSystemValue;
const Preset& edited_preset = m_presets->get_edited_preset();
const Preset& selected_preset = m_presets->get_selected_preset();
const Preset* system_preset = m_presets->get_selected_preset_parent();
for (auto& opt_key : m_presets->get_edited_preset().config.keys()) {
if (edited_preset.config.option(opt_key)->phony)
//ensure that osCurrentPhony is in the bitmask
m_options_list[opt_key] |= osCurrentPhony;
if (selected_preset.config.option(opt_key)->phony)
m_options_list[opt_key] |= osInitPhony;
if (system_preset && system_preset->config.option(opt_key)->phony)
m_options_list[opt_key] |= osSystemPhony;
}
//don't let option that were phony be resetable.
for (auto opt_key : dirty_options)
if( (m_options_list[opt_key] & osInitPhony) == 0)
//ensure that osInitValue is not in the bitmask
m_options_list[opt_key] &= ~osInitValue;
for (auto opt_key : nonsys_options)
if ((m_options_list[opt_key] & osSystemPhony) == 0)
m_options_list[opt_key] &= ~osSystemValue;
decorate();
@ -1141,6 +1183,13 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value)
wxGetApp().plater()->on_extruders_change(boost::any_cast<int>(value));
}
//wxGetApp().preset_bundle->value_changed(opt_key);
if (m_config->value_changed(opt_key, { wxGetApp().plater()->config() })) {
update_dirty();
//# Initialize UI components with the config values.
reload_config();
}
update();
}
@ -2956,6 +3005,7 @@ void Tab::load_current_preset()
update_tab_ui();
// update show/hide tabs
//merill note: this is a bit of anti-inheritance pattern
if (m_type == Slic3r::Preset::TYPE_PRINTER) {
const PrinterTechnology printer_technology = m_presets->get_edited_preset().printer_technology();
if (printer_technology != static_cast<TabPrinter*>(this)->m_printer_technology)
@ -3002,6 +3052,15 @@ void Tab::load_current_preset()
on_presets_changed();
if (m_type == Preset::TYPE_SLA_PRINT || m_type == Preset::TYPE_PRINT)
update_frequently_changed_parameters();
//update width/spacing links
if (m_type == Preset::TYPE_PRINT) {
//verify that spacings are set
if (m_config->update_phony({ wxGetApp().plater()->config() })) {
update_dirty();
reload_config();
}
}
}
m_opt_status_value = (m_presets->get_selected_preset_parent() ? osSystemValue : 0) | osInitValue;

View File

@ -170,6 +170,7 @@ protected:
wxColour m_sys_label_clr;
wxColour m_modified_label_clr;
wxColour m_default_text_clr;
wxColour m_phony_text_clr;
// Tooltip text for reset buttons (for whole options group)
wxString m_ttg_value_lock;
@ -199,7 +200,13 @@ protected:
bool m_show_incompatible_presets;
std::vector<Preset::Type> m_dependent_tabs;
enum OptStatus { osSystemValue = 1, osInitValue = 2 };
enum OptStatus {
osSystemValue = 1,
osInitValue = 2,
osSystemPhony = 4,
osInitPhony = 8,
osCurrentPhony = 16,
};
std::map<std::string, int> m_options_list;
int m_opt_status_value = 0;