Merge remote-tracking branch 'origin/master' into feature_arrange_with_libnest2d

This commit is contained in:
tamasmeszaros 2018-07-18 16:45:20 +02:00
commit 170034dd15
15 changed files with 291 additions and 163 deletions

View file

@ -412,45 +412,54 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
// resets time estimators
m_normal_time_estimator.reset();
m_normal_time_estimator.set_dialect(print.config.gcode_flavor);
m_normal_time_estimator.set_acceleration(print.config.machine_max_acceleration_extruding.values[0]);
m_normal_time_estimator.set_retract_acceleration(print.config.machine_max_acceleration_retracting.values[0]);
m_normal_time_estimator.set_minimum_feedrate(print.config.machine_min_extruding_rate.values[0]);
m_normal_time_estimator.set_minimum_travel_feedrate(print.config.machine_min_travel_rate.values[0]);
m_normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::X, print.config.machine_max_acceleration_x.values[0]);
m_normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Y, print.config.machine_max_acceleration_y.values[0]);
m_normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Z, print.config.machine_max_acceleration_z.values[0]);
m_normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::E, print.config.machine_max_acceleration_e.values[0]);
m_normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::X, print.config.machine_max_feedrate_x.values[0]);
m_normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Y, print.config.machine_max_feedrate_y.values[0]);
m_normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Z, print.config.machine_max_feedrate_z.values[0]);
m_normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::E, print.config.machine_max_feedrate_e.values[0]);
m_normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::X, print.config.machine_max_jerk_x.values[0]);
m_normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Y, print.config.machine_max_jerk_y.values[0]);
m_normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Z, print.config.machine_max_jerk_z.values[0]);
m_normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::E, print.config.machine_max_jerk_e.values[0]);
m_silent_time_estimator_enabled = (print.config.gcode_flavor == gcfMarlin) && print.config.silent_mode;
m_silent_time_estimator_enabled = (print.config.gcode_flavor == gcfMarlin) && print.config.silent_mode && boost::starts_with(print.config.printer_model.value, "MK3");
if (m_silent_time_estimator_enabled)
{
m_silent_time_estimator.reset();
m_silent_time_estimator.set_dialect(print.config.gcode_flavor);
m_silent_time_estimator.set_acceleration(print.config.machine_max_acceleration_extruding.values[1]);
m_silent_time_estimator.set_retract_acceleration(print.config.machine_max_acceleration_retracting.values[1]);
m_silent_time_estimator.set_minimum_feedrate(print.config.machine_min_extruding_rate.values[1]);
m_silent_time_estimator.set_minimum_travel_feedrate(print.config.machine_min_travel_rate.values[1]);
m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::X, print.config.machine_max_acceleration_x.values[1]);
m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Y, print.config.machine_max_acceleration_y.values[1]);
m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Z, print.config.machine_max_acceleration_z.values[1]);
m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::E, print.config.machine_max_acceleration_e.values[1]);
m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::X, print.config.machine_max_feedrate_x.values[1]);
m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Y, print.config.machine_max_feedrate_y.values[1]);
m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Z, print.config.machine_max_feedrate_z.values[1]);
m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::E, print.config.machine_max_feedrate_e.values[1]);
m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::X, print.config.machine_max_jerk_x.values[1]);
m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Y, print.config.machine_max_jerk_y.values[1]);
m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Z, print.config.machine_max_jerk_z.values[1]);
m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::E, print.config.machine_max_jerk_e.values[1]);
// Until we have a UI support for the other firmwares than the Marlin, use the hardcoded default values
// and let the user to enter the G-code limits into the start G-code.
// If the following block is enabled for other firmwares than the Marlin, then the function
// this->print_machine_envelope(file, print);
// shall be adjusted as well to produce a G-code block compatible with the particular firmware flavor.
if (print.config.gcode_flavor.value == gcfMarlin) {
m_normal_time_estimator.set_max_acceleration(print.config.machine_max_acceleration_extruding.values[0]);
m_normal_time_estimator.set_retract_acceleration(print.config.machine_max_acceleration_retracting.values[0]);
m_normal_time_estimator.set_minimum_feedrate(print.config.machine_min_extruding_rate.values[0]);
m_normal_time_estimator.set_minimum_travel_feedrate(print.config.machine_min_travel_rate.values[0]);
m_normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::X, print.config.machine_max_acceleration_x.values[0]);
m_normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Y, print.config.machine_max_acceleration_y.values[0]);
m_normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Z, print.config.machine_max_acceleration_z.values[0]);
m_normal_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::E, print.config.machine_max_acceleration_e.values[0]);
m_normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::X, print.config.machine_max_feedrate_x.values[0]);
m_normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Y, print.config.machine_max_feedrate_y.values[0]);
m_normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Z, print.config.machine_max_feedrate_z.values[0]);
m_normal_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::E, print.config.machine_max_feedrate_e.values[0]);
m_normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::X, print.config.machine_max_jerk_x.values[0]);
m_normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Y, print.config.machine_max_jerk_y.values[0]);
m_normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Z, print.config.machine_max_jerk_z.values[0]);
m_normal_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::E, print.config.machine_max_jerk_e.values[0]);
if (m_silent_time_estimator_enabled)
{
m_silent_time_estimator.reset();
m_silent_time_estimator.set_dialect(print.config.gcode_flavor);
m_silent_time_estimator.set_max_acceleration(print.config.machine_max_acceleration_extruding.values[1]);
m_silent_time_estimator.set_retract_acceleration(print.config.machine_max_acceleration_retracting.values[1]);
m_silent_time_estimator.set_minimum_feedrate(print.config.machine_min_extruding_rate.values[1]);
m_silent_time_estimator.set_minimum_travel_feedrate(print.config.machine_min_travel_rate.values[1]);
m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::X, print.config.machine_max_acceleration_x.values[1]);
m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Y, print.config.machine_max_acceleration_y.values[1]);
m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::Z, print.config.machine_max_acceleration_z.values[1]);
m_silent_time_estimator.set_axis_max_acceleration(GCodeTimeEstimator::E, print.config.machine_max_acceleration_e.values[1]);
m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::X, print.config.machine_max_feedrate_x.values[1]);
m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Y, print.config.machine_max_feedrate_y.values[1]);
m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::Z, print.config.machine_max_feedrate_z.values[1]);
m_silent_time_estimator.set_axis_max_feedrate(GCodeTimeEstimator::E, print.config.machine_max_feedrate_e.values[1]);
m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::X, print.config.machine_max_jerk_x.values[1]);
m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Y, print.config.machine_max_jerk_y.values[1]);
m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Z, print.config.machine_max_jerk_z.values[1]);
m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::E, print.config.machine_max_jerk_e.values[1]);
}
}
// resets analyzer
m_analyzer.reset();
m_enable_analyzer = preview_data != nullptr;
@ -613,6 +622,9 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
m_cooling_buffer->set_current_extruder(initial_extruder_id);
// Emit machine envelope limits for the Marlin firmware.
this->print_machine_envelope(file, print);
// Disable fan.
if (! print.config.cooling.get_at(initial_extruder_id) || print.config.disable_fan_first_layers.get_at(initial_extruder_id))
_write(file, m_writer.set_fan(0, true));
@ -968,6 +980,35 @@ static bool custom_gcode_sets_temperature(const std::string &gcode, const int mc
return temp_set_by_gcode;
}
// Print the machine envelope G-code for the Marlin firmware based on the "machine_max_xxx" parameters.
// Do not process this piece of G-code by the time estimator, it already knows the values through another sources.
void GCode::print_machine_envelope(FILE *file, Print &print)
{
if (print.config.gcode_flavor.value == gcfMarlin) {
fprintf(file, "M201 X%d Y%d Z%d E%d ; sets maximum accelerations, mm/sec^2\n",
int(print.config.machine_max_acceleration_x.values.front() + 0.5),
int(print.config.machine_max_acceleration_y.values.front() + 0.5),
int(print.config.machine_max_acceleration_z.values.front() + 0.5),
int(print.config.machine_max_acceleration_e.values.front() + 0.5));
fprintf(file, "M203 X%d Y%d Z%d E%d ; sets maximum feedrates, mm/sec\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));
fprintf(file, "M204 S%d T%d ; sets acceleration (S) and retract acceleration (T), mm/sec^2\n",
int(print.config.machine_max_acceleration_extruding.values.front() + 0.5),
int(print.config.machine_max_acceleration_retracting.values.front() + 0.5));
fprintf(file, "M205 X%.2lf Y%.2lf Z%.2lf E%.2lf ; sets the jerk limits, mm/sec\n",
print.config.machine_max_jerk_x.values.front(),
print.config.machine_max_jerk_y.values.front(),
print.config.machine_max_jerk_z.values.front(),
print.config.machine_max_jerk_e.values.front());
fprintf(file, "M205 S%d T%d ; sets the minimum extruding and travel feed rate, mm/sec\n",
int(print.config.machine_min_extruding_rate.values.front() + 0.5),
int(print.config.machine_min_travel_rate.values.front() + 0.5));
}
}
// Write 1st layer bed temperatures into the G-code.
// Only do that if the start G-code does not already contain any M-code controlling an extruder temperature.
// M140 - Set Extruder Temperature

View file

@ -327,6 +327,7 @@ protected:
void _write_format(FILE* file, const char* format, ...);
std::string _extrude(const ExtrusionPath &path, std::string description = "", double speed = -1);
void print_machine_envelope(FILE *file, Print &print);
void _print_first_layer_bed_temperature(FILE *file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait);
void _print_first_layer_extruder_temperatures(FILE *file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait);
// this flag triggers first layer speeds

View file

@ -440,13 +440,13 @@ bool WipingExtrusions::is_overriddable(const ExtrusionEntityCollection& eec, con
// Following function iterates through all extrusions on the layer, remembers those that could be used for wiping after toolchange
// and returns volume that is left to be wiped on the wipe tower.
float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int new_extruder, float volume_to_wipe)
float WipingExtrusions::mark_wiping_extrusions(const Print& print, unsigned int old_extruder, unsigned int new_extruder, float volume_to_wipe)
{
const LayerTools& lt = *m_layer_tools;
const float min_infill_volume = 0.f; // ignore infill with smaller volume than this
if (print.config.filament_soluble.get_at(new_extruder))
return volume_to_wipe; // Soluble filament cannot be wiped in a random infill
if (print.config.filament_soluble.get_at(old_extruder) || print.config.filament_soluble.get_at(new_extruder))
return volume_to_wipe; // Soluble filament cannot be wiped in a random infill, neither the filament after it
// we will sort objects so that dedicated for wiping are at the beginning:
PrintObjectPtrs object_list = print.objects;

View file

@ -28,7 +28,7 @@ public:
// This function goes through all infill entities, decides which ones will be used for wiping and
// marks them by the extruder id. Returns volume that remains to be wiped on the wipe tower:
float mark_wiping_extrusions(const Print& print, unsigned int new_extruder, float volume_to_wipe);
float mark_wiping_extrusions(const Print& print, unsigned int old_extruder, unsigned int new_extruder, float volume_to_wipe);
void ensure_perimeters_infills_order(const Print& print);

View file

@ -414,7 +414,10 @@ namespace Slic3r {
void GCodeTimeEstimator::set_acceleration(float acceleration_mm_sec2)
{
_state.acceleration = acceleration_mm_sec2;
_state.acceleration = (_state.max_acceleration == 0) ?
acceleration_mm_sec2 :
// Clamp the acceleration with the maximum.
std::min(_state.max_acceleration, acceleration_mm_sec2);
}
float GCodeTimeEstimator::get_acceleration() const
@ -422,6 +425,18 @@ namespace Slic3r {
return _state.acceleration;
}
void GCodeTimeEstimator::set_max_acceleration(float acceleration_mm_sec2)
{
_state.max_acceleration = acceleration_mm_sec2;
if (acceleration_mm_sec2 > 0)
_state.acceleration = acceleration_mm_sec2;
}
float GCodeTimeEstimator::get_max_acceleration() const
{
return _state.max_acceleration;
}
void GCodeTimeEstimator::set_retract_acceleration(float acceleration_mm_sec2)
{
_state.retract_acceleration = acceleration_mm_sec2;
@ -540,6 +555,9 @@ namespace Slic3r {
set_e_local_positioning_type(Absolute);
set_feedrate(DEFAULT_FEEDRATE);
// Setting the maximum acceleration to zero means that the there is no limit and the G-code
// is allowed to set excessive values.
set_max_acceleration(0);
set_acceleration(DEFAULT_ACCELERATION);
set_retract_acceleration(DEFAULT_RETRACT_ACCELERATION);
set_minimum_feedrate(DEFAULT_MINIMUM_FEEDRATE);

View file

@ -72,6 +72,8 @@ namespace Slic3r {
Axis axis[Num_Axis];
float feedrate; // mm/s
float acceleration; // mm/s^2
// hard limit for the acceleration, to which the firmware will clamp.
float max_acceleration; // mm/s^2
float retract_acceleration; // mm/s^2
float additional_time; // s
float minimum_feedrate; // mm/s
@ -263,6 +265,10 @@ namespace Slic3r {
void set_acceleration(float acceleration_mm_sec2);
float get_acceleration() const;
// Maximum acceleration for the machine. The firmware simulator will clamp the M204 Sxxx to this maximum.
void set_max_acceleration(float acceleration_mm_sec2);
float get_max_acceleration() const;
void set_retract_acceleration(float acceleration_mm_sec2);
float get_retract_acceleration() const;

View file

@ -18,7 +18,9 @@ void GCodeWriter::apply_print_config(const PrintConfig &print_config)
{
this->config.apply(print_config, true);
m_extrusion_axis = this->config.get_extrusion_axis();
this->m_single_extruder_multi_material = print_config.single_extruder_multi_material.value;
m_single_extruder_multi_material = print_config.single_extruder_multi_material.value;
m_max_acceleration = (print_config.gcode_flavor.value == gcfMarlin) ?
print_config.machine_max_acceleration_extruding.values.front() : 0;
}
void GCodeWriter::set_extruders(const std::vector<unsigned int> &extruder_ids)
@ -85,7 +87,7 @@ std::string GCodeWriter::set_temperature(unsigned int temperature, bool wait, in
}
gcode << temperature;
if (tool != -1 &&
( (this->multiple_extruders && ! this->m_single_extruder_multi_material) ||
( (this->multiple_extruders && ! m_single_extruder_multi_material) ||
FLAVOR_IS(gcfMakerWare) || FLAVOR_IS(gcfSailfish)) ) {
gcode << " T" << tool;
}
@ -170,6 +172,10 @@ std::string GCodeWriter::set_fan(unsigned int speed, bool dont_save)
std::string GCodeWriter::set_acceleration(unsigned int acceleration)
{
// Clamp the acceleration to the allowed maximum.
if (m_max_acceleration > 0 && acceleration > m_max_acceleration)
acceleration = m_max_acceleration;
if (acceleration == 0 || acceleration == m_last_acceleration)
return std::string();

View file

@ -18,7 +18,7 @@ public:
GCodeWriter() :
multiple_extruders(false), m_extrusion_axis("E"), m_extruder(nullptr),
m_single_extruder_multi_material(false),
m_last_acceleration(0), m_last_fan_speed(0),
m_last_acceleration(0), m_max_acceleration(0), m_last_fan_speed(0),
m_last_bed_temperature(0), m_last_bed_temperature_reached(true),
m_lifted(0)
{}
@ -74,6 +74,9 @@ private:
bool m_single_extruder_multi_material;
Extruder* m_extruder;
unsigned int m_last_acceleration;
// Limit for setting the acceleration, to respect the machine limits set for the Marlin firmware.
// If set to zero, the limit is not in action.
unsigned int m_max_acceleration;
unsigned int m_last_fan_speed;
unsigned int m_last_bed_temperature;
bool m_last_bed_temperature_reached;

View file

@ -1132,7 +1132,7 @@ void Print::_make_wipe_tower()
float volume_to_wipe = wipe_volumes[current_extruder_id][extruder_id]; // total volume to wipe after this toolchange
// try to assign some infills/objects for the wiping:
volume_to_wipe = layer_tools.wiping_extrusions().mark_wiping_extrusions(*this, extruder_id, wipe_volumes[current_extruder_id][extruder_id]);
volume_to_wipe = layer_tools.wiping_extrusions().mark_wiping_extrusions(*this, current_extruder_id, extruder_id, wipe_volumes[current_extruder_id][extruder_id]);
wipe_tower.plan_toolchange(layer_tools.print_z, layer_tools.wipe_tower_layer_height, current_extruder_id, extruder_id, first_layer && extruder_id == m_tool_ordering.all_extruders().back(), volume_to_wipe);
current_extruder_id = extruder_id;

View file

@ -772,7 +772,7 @@ PrintConfigDef::PrintConfigDef()
def->enum_labels.push_back("Machinekit");
def->enum_labels.push_back("Smoothie");
def->enum_labels.push_back(L("No extrusion"));
def->default_value = new ConfigOptionEnum<GCodeFlavor>(gcfMarlin);
def->default_value = new ConfigOptionEnum<GCodeFlavor>(gcfRepRap);
def = this->add("infill_acceleration", coFloat);
def->label = L("Infill");
@ -907,10 +907,10 @@ PrintConfigDef::PrintConfigDef()
};
std::vector<AxisDefault> axes {
// name, max_feedrate, max_acceleration, max_jerk
{ "x", { 500., 200. }, { 9000., 1000. }, { 10., 10. } },
{ "y", { 500., 200. }, { 9000., 1000. }, { 10., 10. } },
{ "z", { 12., 12. }, { 500., 200. }, { 0.2, 0.4 } },
{ "e", { 120., 120. }, { 10000., 5000. }, { 2.5, 2.5 } }
{ "x", { 500., 200. }, { 9000., 1000. }, { 10. , 10. } },
{ "y", { 500., 200. }, { 9000., 1000. }, { 10. , 10. } },
{ "z", { 12., 12. }, { 500., 200. }, { 0.2, 0.4 } },
{ "e", { 120., 120. }, { 10000., 5000. }, { 2.5, 2.5 } }
};
for (const AxisDefault &axis : axes) {
std::string axis_upper = boost::to_upper_copy<std::string>(axis.name);

View file

@ -14,7 +14,7 @@
#include <boost/thread.hpp>
#define SLIC3R_FORK_NAME "Slic3r Prusa Edition"
#define SLIC3R_VERSION "1.40.1"
#define SLIC3R_VERSION "1.41.0-alpha"
#define SLIC3R_BUILD "UNKNOWN"
typedef int32_t coord_t;

View file

@ -1742,27 +1742,27 @@ PageShp TabPrinter::build_kinematics_page()
}
std::vector<std::string> axes{ "x", "y", "z", "e" };
auto optgroup = page->new_optgroup(_(L("Maximum accelerations")));
for (const std::string &axis : axes) {
append_option_line(optgroup, "machine_max_acceleration_" + axis);
}
optgroup = page->new_optgroup(_(L("Maximum feedrates")));
auto optgroup = page->new_optgroup(_(L("Maximum feedrates")));
for (const std::string &axis : axes) {
append_option_line(optgroup, "machine_max_feedrate_" + axis);
}
optgroup = page->new_optgroup(_(L("Starting Acceleration")));
optgroup = page->new_optgroup(_(L("Maximum accelerations")));
for (const std::string &axis : axes) {
append_option_line(optgroup, "machine_max_acceleration_" + axis);
}
append_option_line(optgroup, "machine_max_acceleration_extruding");
append_option_line(optgroup, "machine_max_acceleration_retracting");
optgroup = page->new_optgroup(_(L("Advanced")));
append_option_line(optgroup, "machine_min_extruding_rate");
append_option_line(optgroup, "machine_min_travel_rate");
optgroup = page->new_optgroup(_(L("Jerk limits")));
for (const std::string &axis : axes) {
append_option_line(optgroup, "machine_max_jerk_" + axis);
}
optgroup = page->new_optgroup(_(L("Minimum feedrates")));
append_option_line(optgroup, "machine_min_extruding_rate");
append_option_line(optgroup, "machine_min_travel_rate");
return page;
}
@ -1900,11 +1900,18 @@ void TabPrinter::update(){
bool is_marlin_flavor = m_config->option<ConfigOptionEnum<GCodeFlavor>>("gcode_flavor")->value == gcfMarlin;
const std::string &printer_model = m_config->opt_string("printer_model");
bool can_use_silent_mode = printer_model.empty() ? false : printer_model == "MK3"; // "true" only for MK3 printers
{
Field *sm = get_field("silent_mode");
if (! is_marlin_flavor)
// Disable silent mode for non-marlin firmwares.
get_field("silent_mode")->toggle(false);
if (is_marlin_flavor)
sm->enable();
else
sm->disable();
}
get_field("silent_mode")->toggle(can_use_silent_mode && is_marlin_flavor);
if (can_use_silent_mode && m_use_silent_mode != m_config->opt_bool("silent_mode")) {
if (m_use_silent_mode != m_config->opt_bool("silent_mode")) {
m_rebuild_kinematics_page = true;
m_use_silent_mode = m_config->opt_bool("silent_mode");
}