diff --git a/xs/src/libslic3r/Config.hpp b/xs/src/libslic3r/Config.hpp index bde1eb651..377bdbea4 100644 --- a/xs/src/libslic3r/Config.hpp +++ b/xs/src/libslic3r/Config.hpp @@ -291,6 +291,8 @@ public: ConfigOptionFloats() : ConfigOptionVector() {} explicit ConfigOptionFloats(size_t n, double value) : ConfigOptionVector(n, value) {} explicit ConfigOptionFloats(std::initializer_list il) : ConfigOptionVector(std::move(il)) {} + explicit ConfigOptionFloats(const std::vector &vec) : ConfigOptionVector(vec) {} + explicit ConfigOptionFloats(std::vector &&vec) : ConfigOptionVector(std::move(vec)) {} static ConfigOptionType static_type() { return coFloats; } ConfigOptionType type() const override { return static_type(); } diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp index b581b3e76..479af7abe 100644 --- a/xs/src/libslic3r/GCode.cpp +++ b/xs/src/libslic3r/GCode.cpp @@ -1411,7 +1411,7 @@ void GCode::apply_print_config(const PrintConfig &print_config) void GCode::append_full_config(const Print& print, std::string& str) { - const StaticPrintConfig *configs[] = { &print.config, &print.default_object_config, &print.default_region_config }; + const StaticPrintConfig *configs[] = { static_cast(&print.config), &print.default_object_config, &print.default_region_config }; for (size_t i = 0; i < sizeof(configs) / sizeof(configs[0]); ++i) { const StaticPrintConfig *cfg = configs[i]; for (const std::string &key : cfg->keys()) diff --git a/xs/src/libslic3r/I18N.hpp b/xs/src/libslic3r/I18N.hpp new file mode 100644 index 000000000..bc9345f11 --- /dev/null +++ b/xs/src/libslic3r/I18N.hpp @@ -0,0 +1,16 @@ +#ifndef slic3r_I18N_hpp_ +#define slic3r_I18N_hpp_ + +#include + +namespace Slic3r { + +typedef std::string (*translate_fn_type)(const char*); +extern translate_fn_type translate_fn; +inline void set_translate_callback(translate_fn_type fn) { translate_fn = fn; } +inline std::string translate(const std::string &s) { return (translate_fn == nullptr) ? s : (*translate_fn)(s.c_str()); } +inline std::string translate(const char *ptr) { return (translate_fn == nullptr) ? std::string(ptr) : (*translate_fn)(ptr); } + +} // namespace Slic3r + +#endif /* slic3r_I18N_hpp_ */ diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index 08802139d..c8d3ccde1 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -4,6 +4,7 @@ #include "Extruder.hpp" #include "Flow.hpp" #include "Geometry.hpp" +#include "I18N.hpp" #include "SupportMaterial.hpp" #include "GCode/WipeTowerPrusaMM.hpp" #include @@ -11,6 +12,10 @@ #include #include +//! macro used to mark string used at localization, +//! return same string +#define L(s) translate(s) + namespace Slic3r { template class PrintState; @@ -523,7 +528,7 @@ std::string Print::validate() const print_volume.min.z = -1e10; for (PrintObject *po : this->objects) { if (!print_volume.contains(po->model_object()->tight_bounding_box(false))) - return "Some objects are outside of the print volume."; + return L("Some objects are outside of the print volume."); } if (this->config.complete_objects) { @@ -550,7 +555,7 @@ std::string Print::validate() const Polygon p = convex_hull; p.translate(copy); if (! intersection(convex_hulls_other, p).empty()) - return "Some objects are too close; your extruder will collide with them."; + return L("Some objects are too close; your extruder will collide with them."); polygons_append(convex_hulls_other, p); } } @@ -565,7 +570,7 @@ std::string Print::validate() const // it will be printed as last one so its height doesn't matter. object_height.pop_back(); if (! object_height.empty() && object_height.back() > scale_(this->config.extruder_clearance_height.value)) - return "Some objects are too tall and cannot be printed without extruder collisions."; + return L("Some objects are too tall and cannot be printed without extruder collisions."); } } // end if (this->config.complete_objects) @@ -575,27 +580,22 @@ std::string Print::validate() const total_copies_count += object->copies().size(); // #4043 if (total_copies_count > 1 && ! this->config.complete_objects.value) - return "The Spiral Vase option can only be used when printing a single object."; + return L("The Spiral Vase option can only be used when printing a single object."); if (this->regions.size() > 1) - return "The Spiral Vase option can only be used when printing single material objects."; + return L("The Spiral Vase option can only be used when printing single material objects."); } if (this->config.single_extruder_multi_material) { for (size_t i=1; iconfig.nozzle_diameter.values.size(); ++i) if (this->config.nozzle_diameter.values[i] != this->config.nozzle_diameter.values[i-1]) - return "All extruders must have the same diameter for single extruder multimaterial printer."; + return L("All extruders must have the same diameter for single extruder multimaterial printer."); } if (this->has_wipe_tower() && ! this->objects.empty()) { - #if 0 - for (auto dmr : this->config.nozzle_diameter.values) - if (std::abs(dmr - 0.4) > EPSILON) - return "The Wipe Tower is currently only supported for the 0.4mm nozzle diameter."; - #endif if (this->config.gcode_flavor != gcfRepRap && this->config.gcode_flavor != gcfMarlin) - return "The Wipe Tower is currently only supported for the Marlin and RepRap/Sprinter G-code flavors."; + return L("The Wipe Tower is currently only supported for the Marlin and RepRap/Sprinter G-code flavors."); if (! this->config.use_relative_e_distances) - return "The Wipe Tower is currently only supported with the relative extruder addressing (use_relative_e_distances=1)."; + return L("The Wipe Tower is currently only supported with the relative extruder addressing (use_relative_e_distances=1)."); SlicingParameters slicing_params0 = this->objects.front()->slicing_parameters(); const PrintObject* tallest_object = this->objects.front(); // let's find the tallest object @@ -607,13 +607,13 @@ std::string Print::validate() const SlicingParameters slicing_params = object->slicing_parameters(); if (std::abs(slicing_params.first_print_layer_height - slicing_params0.first_print_layer_height) > EPSILON || std::abs(slicing_params.layer_height - slicing_params0.layer_height ) > EPSILON) - return "The Wipe Tower is only supported for multiple objects if they have equal layer heigths"; + return L("The Wipe Tower is only supported for multiple objects if they have equal layer heigths"); if (slicing_params.raft_layers() != slicing_params0.raft_layers()) - return "The Wipe Tower is only supported for multiple objects if they are printed over an equal number of raft layers"; + return L("The Wipe Tower is only supported for multiple objects if they are printed over an equal number of raft layers"); if (object->config.support_material_contact_distance != this->objects.front()->config.support_material_contact_distance) - return "The Wipe Tower is only supported for multiple objects if they are printed with the same support_material_contact_distance"; + return L("The Wipe Tower is only supported for multiple objects if they are printed with the same support_material_contact_distance"); if (! equal_layering(slicing_params, slicing_params0)) - return "The Wipe Tower is only supported for multiple objects if they are sliced equally."; + return L("The Wipe Tower is only supported for multiple objects if they are sliced equally."); bool was_layer_height_profile_valid = object->layer_height_profile_valid; object->update_layer_height_profile(); object->layer_height_profile_valid = was_layer_height_profile_valid; @@ -637,13 +637,8 @@ std::string Print::validate() const failed = true; if (failed) - return "The Wipe tower is only supported if all objects have the same layer height profile"; + return L("The Wipe tower is only supported if all objects have the same layer height profile"); } - - /*for (size_t i = 5; i < object->layer_height_profile.size(); i += 2) - if (object->layer_height_profile[i-1] > slicing_params.object_print_z_min + EPSILON && - std::abs(object->layer_height_profile[i] - object->config.layer_height) > EPSILON) - return "The Wipe Tower is currently only supported with constant Z layer spacing. Layer editing is not allowed.";*/ } } @@ -651,7 +646,7 @@ std::string Print::validate() const // find the smallest nozzle diameter std::vector extruders = this->extruders(); if (extruders.empty()) - return "The supplied settings will cause an empty print."; + return L("The supplied settings will cause an empty print."); std::vector nozzle_diameters; for (unsigned int extruder_id : extruders) @@ -661,7 +656,7 @@ std::string Print::validate() const unsigned int total_extruders_count = this->config.nozzle_diameter.size(); for (const auto& extruder_idx : extruders) if ( extruder_idx >= total_extruders_count ) - return "One or more object were assigned an extruder that the printer does not have."; + return L("One or more object were assigned an extruder that the printer does not have."); for (PrintObject *object : this->objects) { if ((object->config.support_material_extruder == -1 || object->config.support_material_interface_extruder == -1) && @@ -670,13 +665,13 @@ std::string Print::validate() const // will be printed with the current tool without a forced tool change. Play safe, assert that all object nozzles // are of the same diameter. if (nozzle_diameters.size() > 1) - return "Printing with multiple extruders of differing nozzle diameters. " + return L("Printing with multiple extruders of differing nozzle diameters. " "If support is to be printed with the current extruder (support_material_extruder == 0 or support_material_interface_extruder == 0), " - "all nozzles have to be of the same diameter."; + "all nozzles have to be of the same diameter."); } // validate first_layer_height - double first_layer_height = object->config.get_abs_value("first_layer_height"); + double first_layer_height = object->config.get_abs_value(L("first_layer_height")); double first_layer_min_nozzle_diameter; if (object->config.raft_layers > 0) { // if we have raft layers, only support material extruder is used on first layer @@ -691,11 +686,11 @@ std::string Print::validate() const first_layer_min_nozzle_diameter = min_nozzle_diameter; } if (first_layer_height > first_layer_min_nozzle_diameter) - return "First layer height can't be greater than nozzle diameter"; + return L("First layer height can't be greater than nozzle diameter"); // validate layer_height if (object->config.layer_height.value > min_nozzle_diameter) - return "Layer height can't be greater than nozzle diameter"; + return L("Layer height can't be greater than nozzle diameter"); } } @@ -1212,7 +1207,7 @@ std::string Print::output_filename() try { return this->placeholder_parser.process(this->config.output_filename_format.value, 0); } catch (std::runtime_error &err) { - throw std::runtime_error(std::string("Failed processing of the output_filename_format template.\n") + err.what()); + throw std::runtime_error(L("Failed processing of the output_filename_format template.") + "\n" + err.what()); } } diff --git a/xs/src/libslic3r/PrintConfig.cpp b/xs/src/libslic3r/PrintConfig.cpp index b77a3a76e..c5e520b4f 100644 --- a/xs/src/libslic3r/PrintConfig.cpp +++ b/xs/src/libslic3r/PrintConfig.cpp @@ -1,7 +1,10 @@ #include "PrintConfig.hpp" +#include "I18N.hpp" #include #include +#include +#include #include #include @@ -11,7 +14,7 @@ namespace Slic3r { //! macro used to mark string used at localization, //! return same string -#define L(s) s +#define L(s) translate(s) PrintConfigDef::PrintConfigDef() { @@ -853,6 +856,85 @@ PrintConfigDef::PrintConfigDef() def->min = 0; def->default_value = new ConfigOptionFloat(0.3); + { + struct AxisDefault { + std::string name; + std::vector max_feedrate; + std::vector max_acceleration; + std::vector max_jerk; + }; + std::vector axes { + // name, max_feedrate, max_acceleration, max_jerk + { "x", { 200., 200. }, { 1000., 1000. }, { 10., 10. } }, + { "y", { 200., 200. }, { 1000., 1000. }, { 10., 10. } }, + { "z", { 12., 12. }, { 200., 200. }, { 0.4, 0.4 } }, + { "e", { 120., 120. }, { 5000., 5000. }, { 2.5, 2.5 } } + }; + for (const AxisDefault &axis : axes) { + std::string axis_upper = boost::to_upper_copy(axis.name); + // Add the machine feedrate limits for XYZE axes. (M203) + def = this->add("machine_max_feedrate_" + axis.name, coFloats); + def->label = (boost::format(L("Maximum feedrate %1%")) % axis_upper).str(); + def->category = L("Machine limits"); + def->tooltip = (boost::format(L("Maximum feedrate of the %1% axis")) % axis_upper).str(); + def->sidetext = L("mm/s"); + def->min = 0; + def->default_value = new ConfigOptionFloats(axis.max_feedrate); + // Add the machine acceleration limits for XYZE axes (M201) + def = this->add("machine_max_acceleration_" + axis.name, coFloats); + def->label = (boost::format(L("Maximum acceleration %1%")) % axis_upper).str(); + def->category = L("Machine limits"); + def->tooltip = (boost::format(L("Maximum acceleration of the %1% axis")) % axis_upper).str(); + def->sidetext = L("mm/s²"); + def->min = 0; + def->default_value = new ConfigOptionFloats(axis.max_acceleration); + // Add the machine jerk limits for XYZE axes (M205) + def = this->add("machine_max_jerk_" + axis.name, coFloats); + def->label = (boost::format(L("Maximum jerk %1%")) % axis_upper).str(); + def->category = L("Machine limits"); + def->tooltip = (boost::format(L("Maximum jerk of the %1% axis")) % axis_upper).str(); + def->sidetext = L("mm/s"); + def->min = 0; + def->default_value = new ConfigOptionFloats(axis.max_jerk); + } + } + + // M205 S... [mm/sec] + def = this->add("machine_min_extruding_rate", coFloats); + def->label = L("Minimum feedrate when extruding"); + def->category = L("Machine limits"); + def->tooltip = L("Minimum feedrate when extruding") + " (M205 S)"; + def->sidetext = L("mm/s"); + def->min = 0; + def->default_value = new ConfigOptionFloats(0., 0.); + + // M205 T... [mm/sec] + def = this->add("machine_min_travel_rate", coFloats); + def->label = L("Minimum travel feedrate"); + def->category = L("Machine limits"); + def->tooltip = L("Minimum travel feedrate") + " (M205 T)"; + def->sidetext = L("mm/s"); + def->min = 0; + def->default_value = new ConfigOptionFloats(0., 0.); + + // M204 S... [mm/sec^2] + def = this->add("machine_max_acceleration_extruding", coFloats); + def->label = L("Maximum acceleration when extruding"); + def->category = L("Machine limits"); + def->tooltip = L("Maximum acceleration when extruding") + " (M204 S)"; + def->sidetext = L("mm/s²"); + def->min = 0; + def->default_value = new ConfigOptionFloats(1250., 1250.); + + // M204 T... [mm/sec^2] + def = this->add("machine_max_acceleration_retracting", coFloats); + def->label = L("Maximum acceleration when retracting"); + def->category = L("Machine limits"); + def->tooltip = L("Maximum acceleration when retracting") + " (M204 T)"; + def->sidetext = L("mm/s²"); + def->min = 0; + def->default_value = new ConfigOptionFloats(1250., 1250.); + def = this->add("max_fan_speed", coInts); def->label = L("Max"); def->tooltip = L("This setting represents the maximum speed of your fan."); @@ -2198,6 +2280,7 @@ std::string FullPrintConfig::validate() // Declare the static caches for each StaticPrintConfig derived class. StaticPrintConfig::StaticCache PrintObjectConfig::s_cache_PrintObjectConfig; StaticPrintConfig::StaticCache PrintRegionConfig::s_cache_PrintRegionConfig; +StaticPrintConfig::StaticCache MachineEnvelopeConfig::s_cache_MachineEnvelopeConfig; StaticPrintConfig::StaticCache GCodeConfig::s_cache_GCodeConfig; StaticPrintConfig::StaticCache PrintConfig::s_cache_PrintConfig; StaticPrintConfig::StaticCache HostConfig::s_cache_HostConfig; diff --git a/xs/src/libslic3r/PrintConfig.hpp b/xs/src/libslic3r/PrintConfig.hpp index 2e36ca665..f3be03c2a 100644 --- a/xs/src/libslic3r/PrintConfig.hpp +++ b/xs/src/libslic3r/PrintConfig.hpp @@ -455,6 +455,56 @@ protected: } }; +class MachineEnvelopeConfig : public StaticPrintConfig +{ + STATIC_PRINT_CONFIG_CACHE(MachineEnvelopeConfig) +public: + // M201 X... Y... Z... E... [mm/sec^2] + ConfigOptionFloats machine_max_acceleration_x; + ConfigOptionFloats machine_max_acceleration_y; + ConfigOptionFloats machine_max_acceleration_z; + ConfigOptionFloats machine_max_acceleration_e; + // M203 X... Y... Z... E... [mm/sec] + ConfigOptionFloats machine_max_feedrate_x; + ConfigOptionFloats machine_max_feedrate_y; + ConfigOptionFloats machine_max_feedrate_z; + ConfigOptionFloats machine_max_feedrate_e; + // M204 S... [mm/sec^2] + ConfigOptionFloats machine_max_acceleration_extruding; + // M204 T... [mm/sec^2] + ConfigOptionFloats machine_max_acceleration_retracting; + // M205 X... Y... Z... E... [mm/sec] + ConfigOptionFloats machine_max_jerk_x; + ConfigOptionFloats machine_max_jerk_y; + ConfigOptionFloats machine_max_jerk_z; + ConfigOptionFloats machine_max_jerk_e; + // M205 T... [mm/sec] + ConfigOptionFloats machine_min_travel_rate; + // M205 S... [mm/sec] + ConfigOptionFloats machine_min_extruding_rate; + +protected: + void initialize(StaticCacheBase &cache, const char *base_ptr) + { + OPT_PTR(machine_max_acceleration_x); + OPT_PTR(machine_max_acceleration_y); + OPT_PTR(machine_max_acceleration_z); + OPT_PTR(machine_max_acceleration_e); + OPT_PTR(machine_max_feedrate_x); + OPT_PTR(machine_max_feedrate_y); + OPT_PTR(machine_max_feedrate_z); + OPT_PTR(machine_max_feedrate_e); + OPT_PTR(machine_max_acceleration_extruding); + OPT_PTR(machine_max_acceleration_retracting); + OPT_PTR(machine_max_jerk_x); + OPT_PTR(machine_max_jerk_y); + OPT_PTR(machine_max_jerk_z); + OPT_PTR(machine_max_jerk_e); + OPT_PTR(machine_min_travel_rate); + OPT_PTR(machine_min_extruding_rate); + } +}; + // This object is mapped to Perl as Slic3r::Config::GCode. class GCodeConfig : public StaticPrintConfig { @@ -566,7 +616,7 @@ protected: }; // This object is mapped to Perl as Slic3r::Config::Print. -class PrintConfig : public GCodeConfig +class PrintConfig : public MachineEnvelopeConfig, public GCodeConfig { STATIC_PRINT_CONFIG_CACHE_DERIVED(PrintConfig) PrintConfig() : GCodeConfig(0) { initialize_cache(); *this = s_cache_PrintConfig.defaults(); } @@ -642,6 +692,7 @@ protected: PrintConfig(int) : GCodeConfig(1) {} void initialize(StaticCacheBase &cache, const char *base_ptr) { + this->MachineEnvelopeConfig::initialize(cache, base_ptr); this->GCodeConfig::initialize(cache, base_ptr); OPT_PTR(avoid_crossing_perimeters); OPT_PTR(bed_shape); diff --git a/xs/src/libslic3r/utils.cpp b/xs/src/libslic3r/utils.cpp index 745d07fcd..2d177da3c 100644 --- a/xs/src/libslic3r/utils.cpp +++ b/xs/src/libslic3r/utils.cpp @@ -1,4 +1,5 @@ #include "Utils.hpp" +#include "I18N.hpp" #include #include @@ -123,6 +124,9 @@ const std::string& localization_dir() return g_local_dir; } +// Translate function callback, to call wxWidgets translate function to convert non-localized UTF8 string to a localized one. +translate_fn_type translate_fn = nullptr; + static std::string g_data_dir; void set_data_dir(const std::string &dir) diff --git a/xs/xsp/Config.xsp b/xs/xsp/Config.xsp index 6adfc49a2..b8ad84ba4 100644 --- a/xs/xsp/Config.xsp +++ b/xs/xsp/Config.xsp @@ -74,13 +74,13 @@ static StaticPrintConfig* new_GCodeConfig() %code{% RETVAL = new GCodeConfig(); %}; static StaticPrintConfig* new_PrintConfig() - %code{% RETVAL = new PrintConfig(); %}; + %code{% RETVAL = static_cast(new PrintConfig()); %}; static StaticPrintConfig* new_PrintObjectConfig() %code{% RETVAL = new PrintObjectConfig(); %}; static StaticPrintConfig* new_PrintRegionConfig() %code{% RETVAL = new PrintRegionConfig(); %}; static StaticPrintConfig* new_FullPrintConfig() - %code{% RETVAL = static_cast(new FullPrintConfig()); %}; + %code{% RETVAL = static_cast(new FullPrintConfig()); %}; ~StaticPrintConfig(); bool has(t_config_option_key opt_key); SV* as_hash() @@ -119,7 +119,7 @@ auto config = new FullPrintConfig(); try { config->load(path); - RETVAL = static_cast(config); + RETVAL = static_cast(config); } catch (std::exception& e) { delete config; croak("Error extracting configuration from %s:\n%s\n", path, e.what()); diff --git a/xs/xsp/Print.xsp b/xs/xsp/Print.xsp index b53b5e82d..e336131d0 100644 --- a/xs/xsp/Print.xsp +++ b/xs/xsp/Print.xsp @@ -133,7 +133,7 @@ _constant() ~Print(); Ref config() - %code%{ RETVAL = &THIS->config; %}; + %code%{ RETVAL = static_cast(&THIS->config); %}; Ref default_object_config() %code%{ RETVAL = &THIS->default_object_config; %}; Ref default_region_config()