From bf3888fc49378c621dd626822ccc33618ce558c4 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Wed, 4 Mar 2020 13:21:03 +0100 Subject: [PATCH 01/20] Reduced ram used by GCodeAnalyzer by replacing doubles with floats into GCodeAnalyzer::GCodeMove --- src/libslic3r/GCode/Analyzer.cpp | 44 ++++++++++++++++---------------- src/libslic3r/GCode/Analyzer.hpp | 26 +++++++++---------- src/slic3r/GUI/GLCanvas3D.cpp | 2 +- 3 files changed, 36 insertions(+), 36 deletions(-) diff --git a/src/libslic3r/GCode/Analyzer.cpp b/src/libslic3r/GCode/Analyzer.cpp index ec5de71b1..f39120a9c 100644 --- a/src/libslic3r/GCode/Analyzer.cpp +++ b/src/libslic3r/GCode/Analyzer.cpp @@ -18,7 +18,7 @@ static const float INCHES_TO_MM = 25.4f; static const float DEFAULT_FEEDRATE = 0.0f; static const unsigned int DEFAULT_EXTRUDER_ID = 0; static const unsigned int DEFAULT_COLOR_PRINT_ID = 0; -static const Slic3r::Vec3d DEFAULT_START_POSITION = Slic3r::Vec3d(0.0f, 0.0f, 0.0f); +static const Slic3r::Vec3f DEFAULT_START_POSITION = Slic3r::Vec3f::Zero(); static const float DEFAULT_START_EXTRUSION = 0.0f; static const float DEFAULT_FAN_SPEED = 0.0f; @@ -33,7 +33,7 @@ const std::string GCodeAnalyzer::Pause_Print_Tag = "_ANALYZER_PAUSE_PRINT"; const std::string GCodeAnalyzer::Custom_Code_Tag = "_ANALYZER_CUSTOM_CODE"; const std::string GCodeAnalyzer::End_Pause_Print_Or_Custom_Code_Tag = "_ANALYZER_END_PAUSE_PRINT_OR_CUSTOM_CODE"; -const double GCodeAnalyzer::Default_mm3_per_mm = 0.0; +const float GCodeAnalyzer::Default_mm3_per_mm = 0.0f; const float GCodeAnalyzer::Default_Width = 0.0f; const float GCodeAnalyzer::Default_Height = 0.0f; @@ -49,7 +49,7 @@ GCodeAnalyzer::Metadata::Metadata() { } -GCodeAnalyzer::Metadata::Metadata(ExtrusionRole extrusion_role, unsigned int extruder_id, double mm3_per_mm, float width, float height, float feedrate, float fan_speed, unsigned int cp_color_id/* = 0*/) +GCodeAnalyzer::Metadata::Metadata(ExtrusionRole extrusion_role, unsigned int extruder_id, float mm3_per_mm, float width, float height, float feedrate, float fan_speed, unsigned int cp_color_id/* = 0*/) : extrusion_role(extrusion_role) , extruder_id(extruder_id) , mm3_per_mm(mm3_per_mm) @@ -90,7 +90,7 @@ bool GCodeAnalyzer::Metadata::operator != (const GCodeAnalyzer::Metadata& other) return false; } -GCodeAnalyzer::GCodeMove::GCodeMove(GCodeMove::EType type, ExtrusionRole extrusion_role, unsigned int extruder_id, double mm3_per_mm, float width, float height, float feedrate, const Vec3d& start_position, const Vec3d& end_position, float delta_extruder, float fan_speed, unsigned int cp_color_id/* = 0*/) +GCodeAnalyzer::GCodeMove::GCodeMove(GCodeMove::EType type, ExtrusionRole extrusion_role, unsigned int extruder_id, float mm3_per_mm, float width, float height, float feedrate, const Vec3f& start_position, const Vec3f& end_position, float delta_extruder, float fan_speed, unsigned int cp_color_id/* = 0*/) : type(type) , data(extrusion_role, extruder_id, mm3_per_mm, width, height, feedrate, fan_speed, cp_color_id) , start_position(start_position) @@ -99,7 +99,7 @@ GCodeAnalyzer::GCodeMove::GCodeMove(GCodeMove::EType type, ExtrusionRole extrusi { } -GCodeAnalyzer::GCodeMove::GCodeMove(GCodeMove::EType type, const GCodeAnalyzer::Metadata& data, const Vec3d& start_position, const Vec3d& end_position, float delta_extruder) +GCodeAnalyzer::GCodeMove::GCodeMove(GCodeMove::EType type, const GCodeAnalyzer::Metadata& data, const Vec3f& start_position, const Vec3f& end_position, float delta_extruder) : type(type) , data(data) , start_position(start_position) @@ -689,7 +689,7 @@ void GCodeAnalyzer::_process_extrusion_role_tag(const std::string& comment, size void GCodeAnalyzer::_process_mm3_per_mm_tag(const std::string& comment, size_t pos) { - _set_mm3_per_mm(::strtod(comment.substr(pos + Mm3_Per_Mm_Tag.length()).c_str(), nullptr)); + _set_mm3_per_mm((float)::strtod(comment.substr(pos + Mm3_Per_Mm_Tag.length()).c_str(), nullptr)); } void GCodeAnalyzer::_process_width_tag(const std::string& comment, size_t pos) @@ -782,12 +782,12 @@ unsigned int GCodeAnalyzer::_get_cp_color_id() const return m_state.data.cp_color_id; } -void GCodeAnalyzer::_set_mm3_per_mm(double value) +void GCodeAnalyzer::_set_mm3_per_mm(float value) { m_state.data.mm3_per_mm = value; } -double GCodeAnalyzer::_get_mm3_per_mm() const +float GCodeAnalyzer::_get_mm3_per_mm() const { return m_state.data.mm3_per_mm; } @@ -862,12 +862,12 @@ void GCodeAnalyzer::_reset_axes_origin() ::memset((void*)m_state.origin, 0, Num_Axis * sizeof(float)); } -void GCodeAnalyzer::_set_start_position(const Vec3d& position) +void GCodeAnalyzer::_set_start_position(const Vec3f& position) { m_state.start_position = position; } -const Vec3d& GCodeAnalyzer::_get_start_position() const +const Vec3f& GCodeAnalyzer::_get_start_position() const { return m_state.start_position; } @@ -898,9 +898,9 @@ float GCodeAnalyzer::_get_delta_extrusion() const return _get_axis_position(E) - m_state.start_extrusion; } -Vec3d GCodeAnalyzer::_get_end_position() const +Vec3f GCodeAnalyzer::_get_end_position() const { - return Vec3d(m_state.position[X], m_state.position[Y], m_state.position[Z]); + return Vec3f(m_state.position[X], m_state.position[Y], m_state.position[Z]); } void GCodeAnalyzer::_store_move(GCodeAnalyzer::GCodeMove::EType type) @@ -911,14 +911,14 @@ void GCodeAnalyzer::_store_move(GCodeAnalyzer::GCodeMove::EType type) it = m_moves_map.insert(TypeToMovesMap::value_type(type, GCodeMovesList())).first; // store move - Vec3d extruder_offset = Vec3d::Zero(); + Vec3f extruder_offset = Vec3f::Zero(); unsigned int extruder_id = _get_extruder_id(); ExtruderOffsetsMap::iterator extr_it = m_extruder_offsets.find(extruder_id); if (extr_it != m_extruder_offsets.end()) - extruder_offset = Vec3d(extr_it->second(0), extr_it->second(1), 0.0); + extruder_offset = Vec3f((float)extr_it->second(0), (float)extr_it->second(1), 0.0f); - Vec3d start_position = _get_start_position() + extruder_offset; - Vec3d end_position = _get_end_position() + extruder_offset; + Vec3f start_position = _get_start_position() + extruder_offset; + Vec3f end_position = _get_end_position() + extruder_offset; it->second.emplace_back(type, _get_extrusion_role(), extruder_id, _get_mm3_per_mm(), _get_width(), _get_height(), _get_feedrate(), start_position, end_position, _get_delta_extrusion(), _get_fan_speed(), _get_cp_color_id()); } @@ -956,8 +956,8 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& previ GCodePreviewData::Extrusion::Path &path = paths.back(); path.polyline = polyline; path.extrusion_role = data.extrusion_role; - path.mm3_per_mm = float(data.mm3_per_mm); - path.width = data.width; + path.mm3_per_mm = data.mm3_per_mm; + path.width = data.width; path.height = data.height; path.feedrate = data.feedrate; path.extruder_id = data.extruder_id; @@ -974,7 +974,7 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& previ Metadata data; float z = FLT_MAX; Polyline polyline; - Vec3d position(FLT_MAX, FLT_MAX, FLT_MAX); + Vec3f position(FLT_MAX, FLT_MAX, FLT_MAX); float volumetric_rate = FLT_MAX; GCodePreviewData::Range height_range; GCodePreviewData::Range width_range; @@ -994,7 +994,7 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& previ if (cancel_callback_curr == 0) cancel_callback(); - if ((data != move.data) || (z != move.start_position.z()) || (position != move.start_position) || (volumetric_rate != move.data.feedrate * (float)move.data.mm3_per_mm)) + if ((data != move.data) || (z != move.start_position.z()) || (position != move.start_position) || (volumetric_rate != move.data.feedrate * move.data.mm3_per_mm)) { // store current polyline polyline.remove_duplicate_points(); @@ -1010,7 +1010,7 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& previ // update current values data = move.data; z = (float)move.start_position.z(); - volumetric_rate = move.data.feedrate * (float)move.data.mm3_per_mm; + volumetric_rate = move.data.feedrate * move.data.mm3_per_mm; height_range.update_from(move.data.height); width_range.update_from(move.data.width); feedrate_range.update_from(move.data.feedrate, GCodePreviewData::FeedrateKind::EXTRUSION); @@ -1058,7 +1058,7 @@ void GCodeAnalyzer::_calc_gcode_preview_travel(GCodePreviewData& preview_data, s return; Polyline3 polyline; - Vec3d position(FLT_MAX, FLT_MAX, FLT_MAX); + Vec3f position(FLT_MAX, FLT_MAX, FLT_MAX); GCodePreviewData::Travel::EType type = GCodePreviewData::Travel::Num_Types; GCodePreviewData::Travel::Polyline::EDirection direction = GCodePreviewData::Travel::Polyline::Num_Directions; float feedrate = FLT_MAX; diff --git a/src/libslic3r/GCode/Analyzer.hpp b/src/libslic3r/GCode/Analyzer.hpp index 781c3f265..f9f6c0001 100644 --- a/src/libslic3r/GCode/Analyzer.hpp +++ b/src/libslic3r/GCode/Analyzer.hpp @@ -24,7 +24,7 @@ public: static const std::string Custom_Code_Tag; static const std::string End_Pause_Print_Or_Custom_Code_Tag; - static const double Default_mm3_per_mm; + static const float Default_mm3_per_mm; static const float Default_Width; static const float Default_Height; @@ -53,7 +53,7 @@ public: { ExtrusionRole extrusion_role; unsigned int extruder_id; - double mm3_per_mm; + float mm3_per_mm; float width; // mm float height; // mm float feedrate; // mm/s @@ -61,7 +61,7 @@ public: unsigned int cp_color_id; Metadata(); - Metadata(ExtrusionRole extrusion_role, unsigned int extruder_id, double mm3_per_mm, float width, float height, float feedrate, float fan_speed, unsigned int cp_color_id = 0); + Metadata(ExtrusionRole extrusion_role, unsigned int extruder_id, float mm3_per_mm, float width, float height, float feedrate, float fan_speed, unsigned int cp_color_id = 0); bool operator != (const Metadata& other) const; }; @@ -81,12 +81,12 @@ public: EType type; Metadata data; - Vec3d start_position; - Vec3d end_position; + Vec3f start_position; + Vec3f end_position; float delta_extruder; - GCodeMove(EType type, ExtrusionRole extrusion_role, unsigned int extruder_id, double mm3_per_mm, float width, float height, float feedrate, const Vec3d& start_position, const Vec3d& end_position, float delta_extruder, float fan_speed, unsigned int cp_color_id = 0); - GCodeMove(EType type, const Metadata& data, const Vec3d& start_position, const Vec3d& end_position, float delta_extruder); + GCodeMove(EType type, ExtrusionRole extrusion_role, unsigned int extruder_id, float mm3_per_mm, float width, float height, float feedrate, const Vec3f& start_position, const Vec3f& end_position, float delta_extruder, float fan_speed, unsigned int cp_color_id = 0); + GCodeMove(EType type, const Metadata& data, const Vec3f& start_position, const Vec3f& end_position, float delta_extruder); }; typedef std::vector GCodeMovesList; @@ -101,7 +101,7 @@ private: EPositioningType global_positioning_type; EPositioningType e_local_positioning_type; Metadata data; - Vec3d start_position = Vec3d::Zero(); + Vec3f start_position = Vec3f::Zero(); float cached_position[5]; float start_extrusion; float position[Num_Axis]; @@ -246,8 +246,8 @@ private: void _set_cp_color_id(unsigned int id); unsigned int _get_cp_color_id() const; - void _set_mm3_per_mm(double value); - double _get_mm3_per_mm() const; + void _set_mm3_per_mm(float value); + float _get_mm3_per_mm() const; void _set_width(float width); float _get_width() const; @@ -272,8 +272,8 @@ private: // Sets origin position to zero void _reset_axes_origin(); - void _set_start_position(const Vec3d& position); - const Vec3d& _get_start_position() const; + void _set_start_position(const Vec3f& position); + const Vec3f& _get_start_position() const; void _set_cached_position(unsigned char axis, float position); float _get_cached_position(unsigned char axis) const; @@ -285,7 +285,7 @@ private: float _get_delta_extrusion() const; // Returns current xyz position (from m_state.position[]) - Vec3d _get_end_position() const; + Vec3f _get_end_position() const; // Adds a new move with the given data void _store_move(GCodeMove::EType type); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index a6eee73e8..98bee3d52 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -6045,7 +6045,7 @@ void GLCanvas3D::_load_gcode_extrusion_paths(const GCodePreviewData& preview_dat case GCodePreviewData::Extrusion::FanSpeed: return path.fan_speed; case GCodePreviewData::Extrusion::VolumetricRate: - return path.feedrate * (float)path.mm3_per_mm; + return path.feedrate * path.mm3_per_mm; case GCodePreviewData::Extrusion::Tool: return (float)path.extruder_id; case GCodePreviewData::Extrusion::ColorPrint: From da86472bf14101470fc28b4f7912fba107f8d782 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 5 Mar 2020 12:16:58 +0100 Subject: [PATCH 02/20] Reduced ram used by GCodeTimeEstimator by removing unused redundant data from GCodeTimeEstimator::Block::Trapezoid --- src/libslic3r/GCodeTimeEstimator.cpp | 24 ++++++++++-------------- src/libslic3r/GCodeTimeEstimator.hpp | 9 ++++----- 2 files changed, 14 insertions(+), 19 deletions(-) diff --git a/src/libslic3r/GCodeTimeEstimator.cpp b/src/libslic3r/GCodeTimeEstimator.cpp index 44b6a3d24..bc432ad1b 100644 --- a/src/libslic3r/GCodeTimeEstimator.cpp +++ b/src/libslic3r/GCodeTimeEstimator.cpp @@ -46,19 +46,19 @@ namespace Slic3r { ::memset(abs_axis_feedrate, 0, Num_Axis * sizeof(float)); } - float GCodeTimeEstimator::Block::Trapezoid::acceleration_time(float acceleration) const + float GCodeTimeEstimator::Block::Trapezoid::acceleration_time(float entry_feedrate, float acceleration) const { - return acceleration_time_from_distance(feedrate.entry, accelerate_until, acceleration); + return acceleration_time_from_distance(entry_feedrate, accelerate_until, acceleration); } float GCodeTimeEstimator::Block::Trapezoid::cruise_time() const { - return (feedrate.cruise != 0.0f) ? cruise_distance() / feedrate.cruise : 0.0f; + return (cruise_feedrate != 0.0f) ? cruise_distance() / cruise_feedrate : 0.0f; } - float GCodeTimeEstimator::Block::Trapezoid::deceleration_time(float acceleration) const + float GCodeTimeEstimator::Block::Trapezoid::deceleration_time(float distance, float acceleration) const { - return acceleration_time_from_distance(feedrate.cruise, (distance - decelerate_after), -acceleration); + return acceleration_time_from_distance(cruise_feedrate, (distance - decelerate_after), -acceleration); } float GCodeTimeEstimator::Block::Trapezoid::cruise_distance() const @@ -78,10 +78,6 @@ namespace Slic3r { return ::sqrt(value); } - GCodeTimeEstimator::Block::Block() - { - } - float GCodeTimeEstimator::Block::move_length() const { float length = ::sqrt(sqr(delta_pos[X]) + sqr(delta_pos[Y]) + sqr(delta_pos[Z])); @@ -100,7 +96,7 @@ namespace Slic3r { float GCodeTimeEstimator::Block::acceleration_time() const { - return trapezoid.acceleration_time(acceleration); + return trapezoid.acceleration_time(feedrate.entry, acceleration); } float GCodeTimeEstimator::Block::cruise_time() const @@ -110,7 +106,7 @@ namespace Slic3r { float GCodeTimeEstimator::Block::deceleration_time() const { - return trapezoid.deceleration_time(acceleration); + return trapezoid.deceleration_time(move_length(), acceleration); } float GCodeTimeEstimator::Block::cruise_distance() const @@ -122,8 +118,7 @@ namespace Slic3r { { float distance = move_length(); - trapezoid.distance = distance; - trapezoid.feedrate = feedrate; + trapezoid.cruise_feedrate = feedrate.cruise; float accelerate_distance = std::max(0.0f, estimate_acceleration_distance(feedrate.entry, feedrate.cruise, acceleration)); float decelerate_distance = std::max(0.0f, estimate_acceleration_distance(feedrate.cruise, feedrate.exit, -acceleration)); @@ -136,7 +131,7 @@ namespace Slic3r { { accelerate_distance = clamp(0.0f, distance, intersection_distance(feedrate.entry, feedrate.exit, acceleration, distance)); cruise_distance = 0.0f; - trapezoid.feedrate.cruise = Trapezoid::speed_from_distance(feedrate.entry, accelerate_distance, acceleration); + trapezoid.cruise_feedrate = Trapezoid::speed_from_distance(feedrate.entry, accelerate_distance, acceleration); } trapezoid.accelerate_until = accelerate_distance; @@ -833,6 +828,7 @@ namespace Slic3r { void GCodeTimeEstimator::_calculate_time() { PROFILE_FUNC(); + _forward_pass(); _reverse_pass(); _recalculate_trapezoids(); diff --git a/src/libslic3r/GCodeTimeEstimator.hpp b/src/libslic3r/GCodeTimeEstimator.hpp index 7c364d9eb..01b285456 100644 --- a/src/libslic3r/GCodeTimeEstimator.hpp +++ b/src/libslic3r/GCodeTimeEstimator.hpp @@ -125,14 +125,13 @@ namespace Slic3r { struct Trapezoid { - float distance; // mm float accelerate_until; // mm float decelerate_after; // mm - FeedrateProfile feedrate; + float cruise_feedrate; // mm/sec - float acceleration_time(float acceleration) const; + float acceleration_time(float entry_feedrate, float acceleration) const; float cruise_time() const; - float deceleration_time(float acceleration) const; + float deceleration_time(float distance, float acceleration) const; float cruise_distance() const; // This function gives the time needed to accelerate from an initial speed to reach a final distance. @@ -162,7 +161,7 @@ namespace Slic3r { Trapezoid trapezoid; float elapsed_time; - Block(); + Block() = default; // Returns the length of the move covered by this block, in mm float move_length() const; From d9d5722bf7fbfe5f634dfc90125a383cc4600ebb Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 5 Mar 2020 14:58:03 +0100 Subject: [PATCH 03/20] Reduced ram used by GCodeTimeEstimator by removing unused data from GCodeTimeEstimator::Block --- src/libslic3r/GCodeTimeEstimator.cpp | 68 ++++++++++++---------------- src/libslic3r/GCodeTimeEstimator.hpp | 13 +----- 2 files changed, 31 insertions(+), 50 deletions(-) diff --git a/src/libslic3r/GCodeTimeEstimator.cpp b/src/libslic3r/GCodeTimeEstimator.cpp index bc432ad1b..89d633857 100644 --- a/src/libslic3r/GCodeTimeEstimator.cpp +++ b/src/libslic3r/GCodeTimeEstimator.cpp @@ -78,22 +78,6 @@ namespace Slic3r { return ::sqrt(value); } - float GCodeTimeEstimator::Block::move_length() const - { - float length = ::sqrt(sqr(delta_pos[X]) + sqr(delta_pos[Y]) + sqr(delta_pos[Z])); - return (length > 0.0f) ? length : std::abs(delta_pos[E]); - } - - float GCodeTimeEstimator::Block::is_extruder_only_move() const - { - return (delta_pos[X] == 0.0f) && (delta_pos[Y] == 0.0f) && (delta_pos[Z] == 0.0f) && (delta_pos[E] != 0.0f); - } - - float GCodeTimeEstimator::Block::is_travel_move() const - { - return delta_pos[E] == 0.0f; - } - float GCodeTimeEstimator::Block::acceleration_time() const { return trapezoid.acceleration_time(feedrate.entry, acceleration); @@ -106,7 +90,7 @@ namespace Slic3r { float GCodeTimeEstimator::Block::deceleration_time() const { - return trapezoid.deceleration_time(move_length(), acceleration); + return trapezoid.deceleration_time(distance, acceleration); } float GCodeTimeEstimator::Block::cruise_distance() const @@ -116,8 +100,6 @@ namespace Slic3r { void GCodeTimeEstimator::Block::calculate_trapezoid() { - float distance = move_length(); - trapezoid.cruise_feedrate = feedrate.cruise; float accelerate_distance = std::max(0.0f, estimate_acceleration_distance(feedrate.entry, feedrate.cruise, acceleration)); @@ -129,7 +111,7 @@ namespace Slic3r { // and start braking in order to reach the exit_feedrate exactly at the end of this block. if (cruise_distance < 0.0f) { - accelerate_distance = clamp(0.0f, distance, intersection_distance(feedrate.entry, feedrate.exit, acceleration, distance)); + accelerate_distance = std::clamp(intersection_distance(feedrate.entry, feedrate.exit, acceleration, distance), 0.0f, distance); cruise_distance = 0.0f; trapezoid.cruise_feedrate = Trapezoid::speed_from_distance(feedrate.entry, accelerate_distance, acceleration); } @@ -1017,11 +999,20 @@ namespace Slic3r { return current_absolute_position; }; + auto move_length = [](const std::array& delta_pos) { + float xyz_length = std::sqrt(sqr(delta_pos[X]) + sqr(delta_pos[Y]) + sqr(delta_pos[Z])); + return (xyz_length > 0.0f) ? xyz_length : std::abs(delta_pos[E]); + }; + + auto is_extruder_only_move = [](const std::array& delta_pos) { + return (delta_pos[X] == 0.0f) && (delta_pos[Y] == 0.0f) && (delta_pos[Z] == 0.0f) && (delta_pos[E] != 0.0f); + }; + PROFILE_FUNC(); increment_g1_line_id(); // updates axes positions from line - float new_pos[Num_Axis]; + std::array new_pos; for (unsigned char a = X; a < Num_Axis; ++a) { new_pos[a] = axis_absolute_position((EAxis)a, line); @@ -1036,10 +1027,11 @@ namespace Slic3r { // calculates block movement deltas float max_abs_delta = 0.0f; + std::array delta_pos; for (unsigned char a = X; a < Num_Axis; ++a) { - block.delta_pos[a] = new_pos[a] - get_axis_position((EAxis)a); - max_abs_delta = std::max(max_abs_delta, std::abs(block.delta_pos[a])); + delta_pos[a] = new_pos[a] - get_axis_position((EAxis)a); + max_abs_delta = std::max(max_abs_delta, std::abs(delta_pos[a])); } // is it a move ? @@ -1047,15 +1039,15 @@ namespace Slic3r { return; // calculates block feedrate - m_curr.feedrate = std::max(get_feedrate(), block.is_travel_move() ? get_minimum_travel_feedrate() : get_minimum_feedrate()); + m_curr.feedrate = std::max(get_feedrate(), (delta_pos[E] == 0.0f) ? get_minimum_travel_feedrate() : get_minimum_feedrate()); - float distance = block.move_length(); - float invDistance = 1.0f / distance; + block.distance = move_length(delta_pos); + float invDistance = 1.0f / block.distance; float min_feedrate_factor = 1.0f; for (unsigned char a = X; a < Num_Axis; ++a) { - m_curr.axis_feedrate[a] = m_curr.feedrate * block.delta_pos[a] * invDistance; + m_curr.axis_feedrate[a] = m_curr.feedrate * delta_pos[a] * invDistance; if (a == E) m_curr.axis_feedrate[a] *= get_extrude_factor_override_percentage(); @@ -1076,12 +1068,12 @@ namespace Slic3r { } // calculates block acceleration - float acceleration = block.is_extruder_only_move() ? get_retract_acceleration() : get_acceleration(); + float acceleration = is_extruder_only_move(delta_pos) ? get_retract_acceleration() : get_acceleration(); for (unsigned char a = X; a < Num_Axis; ++a) { float axis_max_acceleration = get_axis_max_acceleration((EAxis)a); - if (acceleration * std::abs(block.delta_pos[a]) * invDistance > axis_max_acceleration) + if (acceleration * std::abs(delta_pos[a]) * invDistance > axis_max_acceleration) acceleration = axis_max_acceleration; } @@ -1161,7 +1153,7 @@ namespace Slic3r { vmax_junction = m_curr.safe_feedrate; } - float v_allowable = Block::max_allowable_speed(-acceleration, m_curr.safe_feedrate, distance); + float v_allowable = Block::max_allowable_speed(-acceleration, m_curr.safe_feedrate, block.distance); block.feedrate.entry = std::min(vmax_junction, v_allowable); block.max_entry_speed = vmax_junction; @@ -1185,21 +1177,21 @@ namespace Slic3r { // detects block move type block.move_type = Block::Noop; - if (block.delta_pos[E] < 0.0f) + if (delta_pos[E] < 0.0f) { - if ((block.delta_pos[X] != 0.0f) || (block.delta_pos[Y] != 0.0f) || (block.delta_pos[Z] != 0.0f)) + if ((delta_pos[X] != 0.0f) || (delta_pos[Y] != 0.0f) || (delta_pos[Z] != 0.0f)) block.move_type = Block::Move; else block.move_type = Block::Retract; } - else if (block.delta_pos[E] > 0.0f) + else if (delta_pos[E] > 0.0f) { - if ((block.delta_pos[X] == 0.0f) && (block.delta_pos[Y] == 0.0f) && (block.delta_pos[Z] == 0.0f)) + if ((delta_pos[X] == 0.0f) && (delta_pos[Y] == 0.0f) && (delta_pos[Z] == 0.0f)) block.move_type = Block::Unretract; - else if ((block.delta_pos[X] != 0.0f) || (block.delta_pos[Y] != 0.0f)) + else if ((delta_pos[X] != 0.0f) || (delta_pos[Y] != 0.0f)) block.move_type = Block::Extrude; } - else if ((block.delta_pos[X] != 0.0f) || (block.delta_pos[Y] != 0.0f) || (block.delta_pos[Z] != 0.0f)) + else if ((delta_pos[X] != 0.0f) || (delta_pos[Y] != 0.0f) || (delta_pos[Z] != 0.0f)) block.move_type = Block::Move; #endif // ENABLE_MOVE_STATS @@ -1558,7 +1550,7 @@ namespace Slic3r { { if (prev.feedrate.entry < curr.feedrate.entry) { - float entry_speed = std::min(curr.feedrate.entry, Block::max_allowable_speed(-prev.acceleration, prev.feedrate.entry, prev.move_length())); + float entry_speed = std::min(curr.feedrate.entry, Block::max_allowable_speed(-prev.acceleration, prev.feedrate.entry, prev.distance)); // Check for junction speed change if (curr.feedrate.entry != entry_speed) @@ -1580,7 +1572,7 @@ namespace Slic3r { // If nominal length true, max junction speed is guaranteed to be reached. Only compute // for max allowable speed if block is decelerating and nominal length is false. if (!curr.flags.nominal_length && (curr.max_entry_speed > next.feedrate.entry)) - curr.feedrate.entry = std::min(curr.max_entry_speed, Block::max_allowable_speed(-curr.acceleration, next.feedrate.entry, curr.move_length())); + curr.feedrate.entry = std::min(curr.max_entry_speed, Block::max_allowable_speed(-curr.acceleration, next.feedrate.entry, curr.distance)); else curr.feedrate.entry = curr.max_entry_speed; diff --git a/src/libslic3r/GCodeTimeEstimator.hpp b/src/libslic3r/GCodeTimeEstimator.hpp index 01b285456..c7980cd9f 100644 --- a/src/libslic3r/GCodeTimeEstimator.hpp +++ b/src/libslic3r/GCodeTimeEstimator.hpp @@ -152,7 +152,7 @@ namespace Slic3r { #endif // ENABLE_MOVE_STATS Flags flags; - float delta_pos[Num_Axis]; // mm + float distance; // mm float acceleration; // mm/s^2 float max_entry_speed; // mm/s float safe_feedrate; // mm/s @@ -161,17 +161,6 @@ namespace Slic3r { Trapezoid trapezoid; float elapsed_time; - Block() = default; - - // Returns the length of the move covered by this block, in mm - float move_length() const; - - // Returns true if this block is a retract/unretract move only - float is_extruder_only_move() const; - - // Returns true if this block is a move with no extrusion - float is_travel_move() const; - // Returns the time spent accelerating toward cruise speed, in seconds float acceleration_time() const; From 70baa0d2466a3ff5f53c22bede68073f8af3bf34 Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Mon, 30 Mar 2020 13:26:24 +0200 Subject: [PATCH 04/20] Fix arrange for large beds --- src/libslic3r/Model.cpp | 2 +- src/libslic3r/Model.hpp | 2 +- src/slic3r/GUI/Plater.cpp | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index b3a18f26b..59df8eb61 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -419,7 +419,7 @@ bool Model::arrange_objects(coordf_t dist, const BoundingBoxf* bb) if (input[i].bed_idx != 0) ret = false; if (input[i].bed_idx >= 0) { input[i].translation += Vec2crd{input[i].bed_idx * stride, 0}; - instances[i]->apply_arrange_result(input[i].translation, + instances[i]->apply_arrange_result(input[i].translation.cast(), input[i].rotation); } } diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 2fbd58461..2ddad9e59 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -668,7 +668,7 @@ public: arrangement::ArrangePolygon get_arrange_polygon() const; // Apply the arrange result on the ModelInstance - void apply_arrange_result(const Vec2crd& offs, double rotation) + void apply_arrange_result(const Vec2d& offs, double rotation) { // write the transformation data into the model instance set_rotation(Z, rotation); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 67b63d8ad..880aa8223 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1489,7 +1489,7 @@ struct Plater::priv friend priv; public: - void apply_arrange_result(const Vec2crd& tr, double rotation) + void apply_arrange_result(const Vec2d& tr, double rotation) { m_pos = unscaled(tr); m_rotation = rotation; apply_wipe_tower(); @@ -1604,7 +1604,7 @@ struct Plater::priv ap.bed_idx = ap.translation.x() / bed_stride(); ap.setter = [obj, this](const ArrangePolygon &p) { if (p.is_arranged()) { - auto t = p.translation; + Vec2d t = p.translation.cast(); t.x() += p.bed_idx * bed_stride(); obj->apply_arrange_result(t, p.rotation); } @@ -2861,7 +2861,7 @@ void Plater::priv::find_new_position(const ModelInstancePtrs &instances, for (size_t i = 0; i < instances.size(); ++i) if (movable[i].bed_idx == 0) - instances[i]->apply_arrange_result(movable[i].translation, + instances[i]->apply_arrange_result(movable[i].translation.cast(), movable[i].rotation); } From 25d58faaad5240c2f2985ca2a9c89e6b8617a2b1 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Tue, 31 Mar 2020 09:01:48 +0200 Subject: [PATCH 05/20] WIP: Windows specific 3Dconnexion using WM_INPUT. This implementation works with the 3DConnexion driver (sic!) if PrusaSlicer.xml is stored into c:\Program Files\3Dconnexion\3DxWare\3DxWinCore64\Cfg\ The implementation is inspired with Blender, see code inside WITH_INPUT_NDOF blocks. --- src/slic3r/GUI/GUI_App.cpp | 15 +++++ src/slic3r/GUI/MainFrame.cpp | 10 +++ src/slic3r/GUI/Mouse3DController.cpp | 94 +++++++++++----------------- src/slic3r/GUI/Mouse3DController.hpp | 7 ++- 4 files changed, 66 insertions(+), 60 deletions(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index f5a4a3d92..234847bc4 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -47,6 +47,7 @@ #include "SysInfoDialog.hpp" #include "KBShortcutsDialog.hpp" #include "UpdateDialogs.hpp" +#include "Mouse3DController.hpp" #include "RemovableDriveManager.hpp" #ifdef __WXMSW__ @@ -193,6 +194,20 @@ static void register_win32_device_notification_event() } return true; }); + + wxWindow::MSWRegisterMessageHandler(WM_INPUT, [](wxWindow *win, WXUINT /* nMsg */, WXWPARAM wParam, WXLPARAM lParam) { + auto main_frame = dynamic_cast(Slic3r::GUI::find_toplevel_parent(win)); + auto plater = (main_frame == nullptr) ? nullptr : main_frame->plater(); +// if (wParam == RIM_INPUTSINK && plater != nullptr && main_frame->IsActive()) { + if (wParam == RIM_INPUT && plater != nullptr && main_frame->IsActive()) { + RAWINPUT raw; + UINT rawSize = sizeof(RAWINPUT); + ::GetRawInputData((HRAWINPUT)lParam, RID_INPUT, &raw, &rawSize, sizeof(RAWINPUTHEADER)); + if (raw.header.dwType == RIM_TYPEHID && plater->get_mouse3d_controller().handle_raw_input_win32(raw.data.hid.bRawData, raw.data.hid.dwSizeHid)) + return true; + } + return false; + }); } #endif // WIN32 diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 69d20fd9f..437af6d53 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -152,6 +152,16 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S // Failed to get desktop location assert(false); } + + { + static constexpr int device_count = 1; + RAWINPUTDEVICE devices[device_count] = { 0 }; + // multi-axis mouse (SpaceNavigator, etc.) + devices[0].usUsagePage = 0x01; + devices[0].usUsage = 0x08; + if (! RegisterRawInputDevices(devices, device_count, sizeof(RAWINPUTDEVICE))) + BOOST_LOG_TRIVIAL(error) << "RegisterRawInputDevices failed"; + } #endif // _WIN32 // propagate event diff --git a/src/slic3r/GUI/Mouse3DController.cpp b/src/slic3r/GUI/Mouse3DController.cpp index 75ec9c3bc..8f80f6847 100644 --- a/src/slic3r/GUI/Mouse3DController.cpp +++ b/src/slic3r/GUI/Mouse3DController.cpp @@ -484,7 +484,10 @@ void Mouse3DController::init() assert(! m_thread.joinable()); if (! m_thread.joinable()) { m_stop = false; +#ifndef _WIN32 + // Don't start the background thread on Windows, as the HID messages are sent as Windows messages. m_thread = std::thread(&Mouse3DController::run, this); +#endif // _WIN32 } } @@ -600,7 +603,10 @@ bool Mouse3DController::connect_device() : path(path), usage_page(usage_page), usage(usage) {} - bool has_valid_usage() const { return (usage_page == 1) && (usage == 8); } + // https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf + // Usage page 1 - Generic Desktop Controls + // Usage page 1, usage 8 - Multi-axis Controller + bool has_valid_usage() const { return usage_page == 1 && usage == 8; } }; #if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT @@ -688,7 +694,7 @@ bool Mouse3DController::connect_device() if (detected_devices.empty()) return false; - std::string path = ""; + std::string path; unsigned short vendor_id = 0; unsigned short product_id = 0; @@ -865,45 +871,60 @@ void Mouse3DController::collect_input() this->handle_input(packet, res, m_params, m_state); } -// Unpack raw 3DConnexion HID packet of a wired 3D mouse into m_state. Called by the worker thread. -bool Mouse3DController::handle_input(const DataPacketRaw& packet, const int packet_lenght, const Params ¶ms, State &state_in_out) +#ifdef _WIN32 +bool Mouse3DController::handle_raw_input_win32(const unsigned char *data, const int packet_length) { if (! wxGetApp().IsActive()) return false; - int res = packet_lenght; + if (packet_length == 7 || packet_length == 13) { + DataPacketRaw packet; + memcpy(packet.data(), data, packet_length); + handle_packet(packet, packet_length, m_params, m_state); + } + + return true; +} +#endif /* _WIN32 */ + +// Unpack raw 3DConnexion HID packet of a wired 3D mouse into m_state. Called by the worker thread. +bool Mouse3DController::handle_input(const DataPacketRaw& packet, const int packet_length, const Params ¶ms, State &state_in_out) +{ + if (! wxGetApp().IsActive()) + return false; + + int res = packet_length; bool updated = false; - if (res == 7) - updated = handle_packet(packet, params, state_in_out); - else if (res == 13) - updated = handle_wireless_packet(packet, params, state_in_out); - else if ((res == 3) && (packet[0] == 3)) + if (res == 7 || res == 13 || // On Mac button packets can be 3 bytes long - updated = handle_packet(packet, params, state_in_out); + ((res == 3) && (packet[0] == 3))) + updated = handle_packet(packet, res, params, state_in_out); #if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT else if (res > 0) std::cout << "Got unknown data packet of length: " << res << ", code:" << (int)packet[0] << std::endl; #endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT -#if 1 if (updated) { wxGetApp().plater()->set_current_canvas_as_dirty(); // ask for an idle event to update 3D scene wxWakeUpIdle(); } -#endif return updated; } // Unpack raw 3DConnexion HID packet of a wired 3D mouse into m_state. Called by handle_input() from the worker thread. -bool Mouse3DController::handle_packet(const DataPacketRaw& packet, const Params ¶ms, State &state_in_out) +bool Mouse3DController::handle_packet(const DataPacketRaw& packet, const int packet_length, const Params ¶ms, State &state_in_out) { switch (packet[0]) { - case 1: // Translation + case 1: // Translation + Rotation { - if (handle_packet_translation(packet, params, state_in_out)) + bool updated = handle_packet_translation(packet, params, state_in_out); + if (packet_length == 13) + updated |= handle_packet_rotation(packet, 7, params, state_in_out); + + if (updated) return true; break; @@ -941,47 +962,6 @@ bool Mouse3DController::handle_packet(const DataPacketRaw& packet, const Params return false; } -// Unpack raw 3DConnexion HID packet of a wireless 3D mouse into m_state. Called by handle_input() from the worker thread. -bool Mouse3DController::handle_wireless_packet(const DataPacketRaw& packet, const Params ¶ms, State &state_in_out) -{ - switch (packet[0]) - { - case 1: // Translation + Rotation - { - bool updated = handle_packet_translation(packet, params, state_in_out); - updated |= handle_packet_rotation(packet, 7, params, state_in_out); - - if (updated) - return true; - - break; - } - case 3: // Button - { - if (params.buttons_enabled && handle_packet_button(packet, 12, params, state_in_out)) - return true; - - break; - } - case 23: // Battery charge - { -#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT - std::cout << "3DConnexion - battery level: " << (int)packet[1] << " percent" << std::endl; -#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT - break; - } - default: - { -#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT - std::cout << "3DConnexion - Got unknown data packet of code: " << (int)packet[0] << std::endl; -#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT - break; - } - } - - return false; -} - // Convert a signed 16bit word from a 3DConnexion mouse HID packet into a double coordinate, apply a dead zone. static double convert_input(int coord_byte_low, int coord_byte_high, double deadzone) { diff --git a/src/slic3r/GUI/Mouse3DController.hpp b/src/slic3r/GUI/Mouse3DController.hpp index eb1425b88..2c1d0bb6f 100644 --- a/src/slic3r/GUI/Mouse3DController.hpp +++ b/src/slic3r/GUI/Mouse3DController.hpp @@ -190,6 +190,8 @@ public: #endif // __APPLE__ #ifdef WIN32 + bool handle_raw_input_win32(const unsigned char *data, const int packet_lenght); + // Called by Win32 HID enumeration callback. void device_attached(const std::string &device); @@ -218,10 +220,9 @@ private: typedef std::array DataPacketRaw; // Unpack raw 3DConnexion HID packet of a wired 3D mouse into m_state. Called by the worker thread. - static bool handle_input(const DataPacketRaw& packet, const int packet_lenght, const Params ¶ms, State &state_in_out); + static bool handle_input(const DataPacketRaw& packet, const int packet_length, const Params ¶ms, State &state_in_out); // The following is called by handle_input() from the worker thread. - static bool handle_packet(const DataPacketRaw& packet, const Params ¶ms, State &state_in_out); - static bool handle_wireless_packet(const DataPacketRaw& packet, const Params ¶ms, State &state_in_out); + static bool handle_packet(const DataPacketRaw& packet, const int packet_length, const Params ¶ms, State &state_in_out); static bool handle_packet_translation(const DataPacketRaw& packet, const Params ¶ms, State &state_in_out); static bool handle_packet_rotation(const DataPacketRaw& packet, unsigned int first_byte, const Params ¶ms, State &state_in_out); static bool handle_packet_button(const DataPacketRaw& packet, unsigned int packet_size, const Params ¶ms, State &state_in_out); From f1ccd38258f63d7f9a04296cab8309f935de9951 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 31 Mar 2020 12:51:50 +0200 Subject: [PATCH 06/20] Fixed shaders on Intel Cards - not allowed use of 'active' word --- resources/shaders/gouraud.fs | 4 ++-- resources/shaders/gouraud.vs | 8 ++++---- src/slic3r/GUI/3DScene.cpp | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/resources/shaders/gouraud.fs b/resources/shaders/gouraud.fs index dce033d7b..853a5512c 100644 --- a/resources/shaders/gouraud.fs +++ b/resources/shaders/gouraud.fs @@ -8,7 +8,7 @@ const float EPSILON = 0.0001; struct SlopeDetection { - bool active; + bool actived; // x = yellow, y = red vec2 z_range; mat3 volume_world_normal_matrix; @@ -37,7 +37,7 @@ void main() { if (any(lessThan(clipping_planes_dots, ZERO))) discard; - vec3 color = slope.active ? slope_color() : uniform_color.rgb; + vec3 color = slope.actived ? slope_color() : uniform_color.rgb; // if the fragment is outside the print volume -> use darker color color = (any(lessThan(delta_box_min, ZERO)) || any(greaterThan(delta_box_max, ZERO))) ? mix(color, ZERO, 0.3333) : color; gl_FragColor = vec4(vec3(intensity.y, intensity.y, intensity.y) + color * intensity.x, uniform_color.a); diff --git a/resources/shaders/gouraud.vs b/resources/shaders/gouraud.vs index 72d6c18b3..a9f3f6118 100644 --- a/resources/shaders/gouraud.vs +++ b/resources/shaders/gouraud.vs @@ -20,7 +20,7 @@ const vec3 ZERO = vec3(0.0, 0.0, 0.0); struct PrintBoxDetection { - bool active; + bool actived; vec3 min; vec3 max; mat4 volume_world_matrix; @@ -28,7 +28,7 @@ struct PrintBoxDetection struct SlopeDetection { - bool active; + bool actived; // x = yellow, y = red vec2 z_range; mat3 volume_world_normal_matrix; @@ -72,7 +72,7 @@ void main() intensity.x += NdotL * LIGHT_FRONT_DIFFUSE; // compute deltas for out of print volume detection (world coordinates) - if (print_box.active) + if (print_box.actived) { vec3 v = (print_box.volume_world_matrix * gl_Vertex).xyz; delta_box_min = v - print_box.min; @@ -85,7 +85,7 @@ void main() } // z component of normal vector in world coordinate used for slope shading - world_normal_z = slope.active ? (normalize(slope.volume_world_normal_matrix * gl_Normal)).z : 0.0; + world_normal_z = slope.actived ? (normalize(slope.volume_world_normal_matrix * gl_Normal)).z : 0.0; gl_Position = ftransform(); // Point in homogenous coordinates. diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index c13c1b937..e60676ca3 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -655,11 +655,11 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab GLint print_box_min_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "print_box.min") : -1; GLint print_box_max_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "print_box.max") : -1; - GLint print_box_active_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "print_box.active") : -1; + GLint print_box_active_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "print_box.actived") : -1; GLint print_box_worldmatrix_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "print_box.volume_world_matrix") : -1; #if ENABLE_SLOPE_RENDERING - GLint slope_active_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "slope.active") : -1; + GLint slope_active_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "slope.actived") : -1; GLint slope_normal_matrix_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "slope.volume_world_normal_matrix") : -1; GLint slope_z_range_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "slope.z_range") : -1; #endif // ENABLE_SLOPE_RENDERING From 095062e371115c864f7884da2ee927f43ee723f3 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 31 Mar 2020 14:16:53 +0200 Subject: [PATCH 07/20] 3DConnexion settings dialog (Ctrl+M) shown only on Mac --- src/slic3r/GUI/GLCanvas3D.cpp | 14 ++++++-------- src/slic3r/GUI/KBShortcutsDialog.cpp | 6 ++++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index e422dc238..6d9c6eb24 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -3016,15 +3016,13 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) #ifdef __APPLE__ case 'm': case 'M': -#else /* __APPLE__ */ - case WXK_CONTROL_M: + { + Mouse3DController& controller = wxGetApp().plater()->get_mouse3d_controller(); + controller.show_settings_dialog(!controller.is_settings_dialog_shown()); + m_dirty = true; + break; + } #endif /* __APPLE__ */ - { - Mouse3DController& controller = wxGetApp().plater()->get_mouse3d_controller(); - controller.show_settings_dialog(!controller.is_settings_dialog_shown()); - m_dirty = true; - break; - } #ifdef __APPLE__ case 'v': diff --git a/src/slic3r/GUI/KBShortcutsDialog.cpp b/src/slic3r/GUI/KBShortcutsDialog.cpp index d05ecbcd8..d8a079232 100644 --- a/src/slic3r/GUI/KBShortcutsDialog.cpp +++ b/src/slic3r/GUI/KBShortcutsDialog.cpp @@ -185,10 +185,12 @@ void KBShortcutsDialog::fill_shortcuts() { "Z", L("Zoom to selected object\nor all objects in scene, if none selected") }, { "I", L("Zoom in") }, { "O", L("Zoom out") }, - { ctrl + "M", L("Show/Hide 3Dconnexion devices settings dialog") } +#ifdef __APPLE__ + { ctrl + "M", L("Show/Hide 3Dconnexion devices settings dialog") }, +#endif // __APPLE__ #if ENABLE_RENDER_PICKING_PASS // Don't localize debugging texts. - , { "T", "Toggle picking pass texture rendering on/off" } + { "T", "Toggle picking pass texture rendering on/off" }, #endif // ENABLE_RENDER_PICKING_PASS }; From 081a24abf39cc5b1f911c797370566d2b609caa5 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 31 Mar 2020 15:30:24 +0200 Subject: [PATCH 08/20] Follow-up of 095062e371115c864f7884da2ee927f43ee723f3 -> 3DConnexion settings dialog (Ctrl+M) shown only on Linux (not Mac) --- src/slic3r/GUI/GLCanvas3D.cpp | 7 +++---- src/slic3r/GUI/KBShortcutsDialog.cpp | 4 ++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 6d9c6eb24..94489d0d3 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -3013,16 +3013,15 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) post_event(SimpleEvent(EVT_GLTOOLBAR_COPY)); break; -#ifdef __APPLE__ - case 'm': - case 'M': +#ifdef __linux__ + case WXK_CONTROL_M: { Mouse3DController& controller = wxGetApp().plater()->get_mouse3d_controller(); controller.show_settings_dialog(!controller.is_settings_dialog_shown()); m_dirty = true; break; } -#endif /* __APPLE__ */ +#endif /* __linux__ */ #ifdef __APPLE__ case 'v': diff --git a/src/slic3r/GUI/KBShortcutsDialog.cpp b/src/slic3r/GUI/KBShortcutsDialog.cpp index d8a079232..79a6cad20 100644 --- a/src/slic3r/GUI/KBShortcutsDialog.cpp +++ b/src/slic3r/GUI/KBShortcutsDialog.cpp @@ -185,9 +185,9 @@ void KBShortcutsDialog::fill_shortcuts() { "Z", L("Zoom to selected object\nor all objects in scene, if none selected") }, { "I", L("Zoom in") }, { "O", L("Zoom out") }, -#ifdef __APPLE__ +#ifdef __linux__ { ctrl + "M", L("Show/Hide 3Dconnexion devices settings dialog") }, -#endif // __APPLE__ +#endif // __linux__ #if ENABLE_RENDER_PICKING_PASS // Don't localize debugging texts. { "T", "Toggle picking pass texture rendering on/off" }, From e886475fe7b55500d0b5db9e4b1813ab412f4b3b Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Tue, 31 Mar 2020 18:04:49 +0200 Subject: [PATCH 09/20] Fixed build when tech ENABLE_NON_STATIC_CANVAS_MANAGER is disabled --- src/slic3r/GUI/GLCanvas3D.cpp | 6 ++---- src/slic3r/GUI/GLCanvas3D.hpp | 3 +++ 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 6d9c6eb24..d6ca9ca08 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1824,14 +1824,12 @@ void GLCanvas3D::set_color_by(const std::string& value) m_color_by = value; } +#if ENABLE_NON_STATIC_CANVAS_MANAGER void GLCanvas3D::refresh_camera_scene_box() { -#if ENABLE_NON_STATIC_CANVAS_MANAGER wxGetApp().plater()->get_camera().set_scene_box(scene_bounding_box()); -#else - m_camera.set_scene_box(scene_bounding_box()); -#endif // ENABLE_NON_STATIC_CANVAS_MANAGER } +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER BoundingBoxf3 GLCanvas3D::volumes_bounding_box() const { diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 952f45c39..07fa00b9d 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -16,6 +16,9 @@ #include "GUI_ObjectLayers.hpp" #include "GLSelectionRectangle.hpp" #include "MeshUtils.hpp" +#if !ENABLE_NON_STATIC_CANVAS_MANAGER +#include "Camera.hpp" +#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER #include From b843a094f657e987e845d5b7a0c6a72b0849a2cf Mon Sep 17 00:00:00 2001 From: bubnikv Date: Wed, 1 Apr 2020 09:48:56 +0200 Subject: [PATCH 10/20] Slic3r::format(), Slic3r::GUI::format_wxstr(): wrappers around boost::format using C++17 variadic templates, replacing the ugly and verbose (boost::format("template") % arg1 % arg2).str() syntax. The wrappers also implictely convert input parameters including the template from wxString to UTF8. The new format wrapper has been applied at multiple places as a start, also some double macros _(L()) with new single macro _L(). --- src/libslic3r/CMakeLists.txt | 1 + src/libslic3r/Config.cpp | 5 +- src/libslic3r/format.hpp | 57 ++++++ src/libslic3r/pchheader.hpp | 1 + src/slic3r/CMakeLists.txt | 1 + src/slic3r/GUI/DoubleSlider.cpp | 36 ++-- src/slic3r/GUI/Plater.cpp | 307 ++++++++++++++--------------- src/slic3r/GUI/format.hpp | 65 ++++++ src/slic3r/Utils/PresetUpdater.cpp | 129 ++++++------ src/slic3r/pchheader.hpp | 2 + 10 files changed, 364 insertions(+), 240 deletions(-) create mode 100644 src/libslic3r/format.hpp create mode 100644 src/slic3r/GUI/format.hpp diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index 73b7df5bc..b37e09ad0 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -64,6 +64,7 @@ add_library(libslic3r STATIC Fill/FillRectilinear3.hpp Flow.cpp Flow.hpp + format.hpp Format/3mf.cpp Format/3mf.hpp Format/AMF.cpp diff --git a/src/libslic3r/Config.cpp b/src/libslic3r/Config.cpp index 674410388..f3f365b47 100644 --- a/src/libslic3r/Config.cpp +++ b/src/libslic3r/Config.cpp @@ -1,4 +1,5 @@ #include "Config.hpp" +#include "format.hpp" #include "Utils.hpp" #include #include @@ -464,7 +465,7 @@ bool ConfigBase::set_deserialize_nothrow(const t_config_option_key &opt_key_src, void ConfigBase::set_deserialize(const t_config_option_key &opt_key_src, const std::string &value_src, bool append) { if (! this->set_deserialize_nothrow(opt_key_src, value_src, append)) - throw BadOptionTypeException((boost::format("ConfigBase::set_deserialize() failed for parameter \"%1%\", value \"%2%\"") % opt_key_src % value_src).str()); + throw BadOptionTypeException(format("ConfigBase::set_deserialize() failed for parameter \"%1%\", value \"%2%\"", opt_key_src, value_src)); } void ConfigBase::set_deserialize(std::initializer_list items) @@ -620,7 +621,7 @@ void ConfigBase::load_from_gcode_file(const std::string &file) size_t key_value_pairs = load_from_gcode_string(data.data()); if (key_value_pairs < 80) - throw std::runtime_error((boost::format("Suspiciously low number of configuration values extracted from %1%: %2%") % file % key_value_pairs).str()); + throw std::runtime_error(format("Suspiciously low number of configuration values extracted from %1%: %2%", file, key_value_pairs)); } // Load the config keys from the given string. diff --git a/src/libslic3r/format.hpp b/src/libslic3r/format.hpp new file mode 100644 index 000000000..c3747677b --- /dev/null +++ b/src/libslic3r/format.hpp @@ -0,0 +1,57 @@ +#ifndef slic3r_format_hpp_ +#define slic3r_format_hpp_ + +// Functional wrapper around boost::format. +// One day we may replace this wrapper with C++20 format +// https://en.cppreference.com/w/cpp/utility/format/format +// though C++20 format uses a different template pattern for position independent parameters. +// +// Boost::format works around the missing variadic templates by an ugly % chaining operator. The usage of boost::format looks like this: +// (boost::format("template") % arg1 %arg2).str() +// This wrapper allows for a nicer syntax: +// Slic3r::format("template", arg1, arg2) +// One can also override Slic3r::internal::format::cook() function to convert a Slic3r::format() argument to something that +// boost::format may convert to string, see slic3r/GUI/I18N.hpp for a "cook" function to convert wxString to UTF8. + +#include + +namespace Slic3r { + +// https://gist.github.com/gchudnov/6a90d51af004d97337ec +namespace internal { + namespace format { + // Default "cook" function - just forward. + template + inline T&& cook(T&& arg) { + return std::forward(arg); + } + + // End of the recursive chain. + inline std::string format_recursive(boost::format& message) { + return message.str(); + } + + template + std::string format_recursive(boost::format& message, TValue&& arg, TArgs&&... args) { + // Format, possibly convert the argument by the "cook" function. + message % cook(std::forward(arg)); + return format_recursive(message, std::forward(args)...); + } + } +}; + +template +inline std::string format(const char* fmt, TArgs&&... args) { + boost::format message(fmt); + return internal::format::format_recursive(message, std::forward(args)...); +} + +template +inline std::string format(const std::string& fmt, TArgs&&... args) { + boost::format message(fmt); + return internal::format::format_recursive(message, std::forward(args)...); +} + +} // namespace Slic3r + +#endif // slic3r_format_hpp_ diff --git a/src/libslic3r/pchheader.hpp b/src/libslic3r/pchheader.hpp index 1339368bd..a1d6da5fe 100644 --- a/src/libslic3r/pchheader.hpp +++ b/src/libslic3r/pchheader.hpp @@ -111,6 +111,7 @@ #include "BoundingBox.hpp" #include "ClipperUtils.hpp" #include "Config.hpp" +#include "format.hpp" #include "I18N.hpp" #include "MultiPoint.hpp" #include "Point.hpp" diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 7be778de9..c8f7e9f1c 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -22,6 +22,7 @@ set(SLIC3R_GUI_SOURCES GUI/ConfigSnapshotDialog.hpp GUI/3DScene.cpp GUI/3DScene.hpp + GUI/format.hpp GUI/GLShader.cpp GUI/GLShader.hpp GUI/GLCanvas3D.hpp diff --git a/src/slic3r/GUI/DoubleSlider.cpp b/src/slic3r/GUI/DoubleSlider.cpp index 7318153ef..4c4c1aa8d 100644 --- a/src/slic3r/GUI/DoubleSlider.cpp +++ b/src/slic3r/GUI/DoubleSlider.cpp @@ -20,11 +20,13 @@ #include #include #include "Field.hpp" +#include "format.hpp" namespace Slic3r { using GUI::from_u8; using GUI::into_u8; +using GUI::format_wxstr; namespace DoubleSlider { @@ -530,7 +532,7 @@ wxString Control::get_label(int tick) const const wxString str = m_values.empty() ? wxNumberFormatter::ToString(m_label_koef*value, 2, wxNumberFormatter::Style_None) : wxNumberFormatter::ToString(m_values[value], 2, wxNumberFormatter::Style_None); - return from_u8((boost::format("%1%\n(%2%)") % str % (m_values.empty() ? value : value+1)).str()); + return format_wxstr("%1%\n(%2%)", str, m_values.empty() ? value : value+1); } void Control::draw_tick_text(wxDC& dc, const wxPoint& pos, int tick, bool right_side/*=true*/) const @@ -1001,16 +1003,16 @@ wxString Control::get_tooltip(int tick/*=-1*/) // Show custom Gcode as a first string of tooltop tooltip = " "; - tooltip += tick_code_it->gcode == ColorChangeCode ? ( m_mode == t_mode::SingleExtruder ? - from_u8((boost::format(_utf8(L("Color change (\"%1%\")"))) % tick_code_it->gcode ).str()) : - from_u8((boost::format(_utf8(L("Color change (\"%1%\") for Extruder %2%"))) % - tick_code_it->gcode % tick_code_it->extruder).str()) ) : - tick_code_it->gcode == PausePrintCode ? - from_u8((boost::format(_utf8(L("Pause print (\"%1%\")"))) % tick_code_it->gcode ).str()) : - tick_code_it->gcode == ToolChangeCode ? - from_u8((boost::format(_utf8(L("Extruder (tool) is changed to Extruder \"%1%\""))) % - tick_code_it->extruder ).str()) : - from_u8(tick_code_it->gcode); + tooltip += + tick_code_it->gcode == ColorChangeCode ? + (m_mode == t_mode::SingleExtruder ? + format_wxstr(_L("Color change (\"%1%\")"), tick_code_it->gcode) : + format_wxstr(_L("Color change (\"%1%\") for Extruder %2%"), tick_code_it->gcode, tick_code_it->extruder)) : + tick_code_it->gcode == PausePrintCode ? + format_wxstr(_L("Pause print (\"%1%\")"), tick_code_it->gcode) : + tick_code_it->gcode == ToolChangeCode ? + format_wxstr(_L("Extruder (tool) is changed to Extruder \"%1%\""), tick_code_it->extruder) : + from_u8(tick_code_it->gcode); // If tick is marked as a conflict (exclamation icon), // we should to explain why @@ -1176,8 +1178,8 @@ void Control::append_add_color_change_menu_item(wxMenu* menu, bool switch_curren } const wxString menu_name = switch_current_code ? - from_u8((boost::format(_utf8(L("Switch code to Color change (%1%) for:"))) % ColorChangeCode).str()) : - from_u8((boost::format(_utf8(L("Add color change (%1%) for:"))) % ColorChangeCode).str()); + format_wxstr(_L("Switch code to Color change (%1%) for:"), ColorChangeCode) : + format_wxstr(_L("Add color change (%1%) for:"), ColorChangeCode); wxMenuItem* add_color_change_menu_item = menu->AppendSubMenu(add_color_change_menu, menu_name, ""); add_color_change_menu_item->SetBitmap(create_scaled_bitmap("colorchange_add_m")); } @@ -1615,8 +1617,8 @@ static void upgrade_text_entry_dialog(wxTextEntryDialog* dlg, double min = -1.0, static std::string get_custom_code(const std::string& code_in, double height) { - wxString msg_text = from_u8(_utf8(L("Enter custom G-code used on current layer"))) + ":"; - wxString msg_header = from_u8((boost::format(_utf8(L("Custom G-code on current layer (%1% mm)."))) % height).str()); + wxString msg_text = _L("Enter custom G-code used on current layer") + ":"; + wxString msg_header = format_wxstr(_L("Custom G-code on current layer (%1% mm)."), height); // get custom gcode wxTextEntryDialog dlg(nullptr, msg_text, msg_header, code_in, @@ -1631,8 +1633,8 @@ static std::string get_custom_code(const std::string& code_in, double height) static std::string get_pause_print_msg(const std::string& msg_in, double height) { - wxString msg_text = from_u8(_utf8(L("Enter short message shown on Printer display when a print is paused"))) + ":"; - wxString msg_header = from_u8((boost::format(_utf8(L("Message for pause print on current layer (%1% mm)."))) % height).str()); + wxString msg_text = _L("Enter short message shown on Printer display when a print is paused") + ":"; + wxString msg_header = format_wxstr(_L("Message for pause print on current layer (%1% mm)."), height); // get custom gcode wxTextEntryDialog dlg(nullptr, msg_text, msg_header, from_u8(msg_in), diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 880aa8223..5299efc1c 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -138,7 +138,7 @@ public: }; ObjectInfo::ObjectInfo(wxWindow *parent) : - wxStaticBoxSizer(new wxStaticBox(parent, wxID_ANY, _(L("Info"))), wxVERTICAL) + wxStaticBoxSizer(new wxStaticBox(parent, wxID_ANY, _L("Info")), wxVERTICAL) { GetStaticBox()->SetFont(wxGetApp().bold_font()); @@ -157,13 +157,13 @@ ObjectInfo::ObjectInfo(wxWindow *parent) : return text; }; - init_info_label(&info_size, _(L("Size"))); - label_volume = init_info_label(&info_volume, _(L("Volume"))); - init_info_label(&info_facets, _(L("Facets"))); - label_materials = init_info_label(&info_materials, _(L("Materials"))); + init_info_label(&info_size, _L("Size")); + label_volume = init_info_label(&info_volume, _L("Volume")); + init_info_label(&info_facets, _L("Facets")); + label_materials = init_info_label(&info_materials, _L("Materials")); Add(grid_sizer, 0, wxEXPAND); - auto *info_manifold_text = new wxStaticText(parent, wxID_ANY, _(L("Manifold")) + ":"); + auto *info_manifold_text = new wxStaticText(parent, wxID_ANY, _L("Manifold") + ":"); info_manifold_text->SetFont(wxGetApp().small_font()); info_manifold = new wxStaticText(parent, wxID_ANY, ""); info_manifold->SetFont(wxGetApp().small_font()); @@ -213,7 +213,7 @@ private: }; SlicedInfo::SlicedInfo(wxWindow *parent) : - wxStaticBoxSizer(new wxStaticBox(parent, wxID_ANY, _(L("Sliced Info"))), wxVERTICAL) + wxStaticBoxSizer(new wxStaticBox(parent, wxID_ANY, _L("Sliced Info")), wxVERTICAL) { GetStaticBox()->SetFont(wxGetApp().bold_font()); @@ -232,13 +232,13 @@ SlicedInfo::SlicedInfo(wxWindow *parent) : info_vec.push_back(std::pair(text, info_label)); }; - init_info_label(_(L("Used Filament (m)"))); - init_info_label(_(L("Used Filament (mm³)"))); - init_info_label(_(L("Used Filament (g)"))); - init_info_label(_(L("Used Material (unit)"))); - init_info_label(_(L("Cost (money)"))); - init_info_label(_(L("Estimated printing time"))); - init_info_label(_(L("Number of tool changes"))); + init_info_label(_L("Used Filament (m)")); + init_info_label(_L("Used Filament (mm³)")); + init_info_label(_L("Used Filament (g)")); + init_info_label(_L("Used Material (unit)")); + init_info_label(_L("Cost (money)")); + init_info_label(_L("Estimated printing time")); + init_info_label(_L("Number of tool changes")); Add(grid_sizer, 0, wxEXPAND); this->Show(false); @@ -345,7 +345,7 @@ PresetBitmapComboBox(parent, wxSize(15 * wxGetApp().em_unit(), -1)), } edit_btn = new ScalableButton(parent, wxID_ANY, "cog"); - edit_btn->SetToolTip(_(L("Click to edit preset"))); + edit_btn->SetToolTip(_L("Click to edit preset")); edit_btn->Bind(wxEVT_BUTTON, ([preset_type, this](wxCommandEvent) { @@ -546,7 +546,7 @@ FreqChangedParams::FreqChangedParams(wxWindow* parent) : line.append_option(option); auto wiping_dialog_btn = [this](wxWindow* parent) { - m_wiping_dialog_button = new wxButton(parent, wxID_ANY, _(L("Purging volumes")) + dots, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); + m_wiping_dialog_button = new wxButton(parent, wxID_ANY, _L("Purging volumes") + dots, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); m_wiping_dialog_button->SetFont(wxGetApp().normal_font()); auto sizer = new wxBoxSizer(wxHORIZONTAL); sizer->Add(m_wiping_dialog_button, 0, wxALIGN_CENTER_VERTICAL); @@ -817,11 +817,11 @@ Sidebar::Sidebar(Plater *parent) }; p->combos_filament.push_back(nullptr); - init_combo(&p->combo_print, _(L("Print settings")), Preset::TYPE_PRINT, false); - init_combo(&p->combos_filament[0], _(L("Filament")), Preset::TYPE_FILAMENT, true); - init_combo(&p->combo_sla_print, _(L("SLA print settings")), Preset::TYPE_SLA_PRINT, false); - init_combo(&p->combo_sla_material, _(L("SLA material")), Preset::TYPE_SLA_MATERIAL, false); - init_combo(&p->combo_printer, _(L("Printer")), Preset::TYPE_PRINTER, false); + init_combo(&p->combo_print, _L("Print settings"), Preset::TYPE_PRINT, false); + init_combo(&p->combos_filament[0], _L("Filament"), Preset::TYPE_FILAMENT, true); + init_combo(&p->combo_sla_print, _L("SLA print settings"), Preset::TYPE_SLA_PRINT, false); + init_combo(&p->combo_sla_material, _L("SLA material"), Preset::TYPE_SLA_MATERIAL, false); + init_combo(&p->combo_printer, _L("Printer"), Preset::TYPE_PRINTER, false); const int margin_5 = int(0.5*wxGetApp().em_unit());// 5; @@ -880,9 +880,9 @@ Sidebar::Sidebar(Plater *parent) (*btn)->Hide(); }; - init_scalable_btn(&p->btn_send_gcode , "export_gcode", _(L("Send to printer")) + "\tCtrl+Shift+G"); - init_scalable_btn(&p->btn_remove_device, "eject_sd" , _(L("Remove device")) + "\tCtrl+T"); - init_scalable_btn(&p->btn_export_gcode_removable, "export_to_sd", _(L("Export to SD card / Flash drive")) + "\tCtrl+U"); + init_scalable_btn(&p->btn_send_gcode , "export_gcode", _L("Send to printer") + "\tCtrl+Shift+G"); + init_scalable_btn(&p->btn_remove_device, "eject_sd" , _L("Remove device") + "\tCtrl+T"); + init_scalable_btn(&p->btn_export_gcode_removable, "export_to_sd", _L("Export to SD card / Flash drive") + "\tCtrl+U"); // regular buttons "Slice now" and "Export G-code" @@ -893,8 +893,8 @@ Sidebar::Sidebar(Plater *parent) (*btn)->SetFont(wxGetApp().bold_font()); }; - init_btn(&p->btn_export_gcode, _(L("Export G-code")) + dots , scaled_height); - init_btn(&p->btn_reslice , _(L("Slice now")) , scaled_height); + init_btn(&p->btn_export_gcode, _L("Export G-code") + dots , scaled_height); + init_btn(&p->btn_reslice , _L("Slice now") , scaled_height); enable_buttons(false); @@ -1044,7 +1044,7 @@ void Sidebar::update_reslice_btn_tooltip() const { wxString tooltip = wxString("Slice") + " [" + GUI::shortkey_ctrl_prefix() + "R]"; if (m_mode != comSimple) - tooltip += wxString("\n") + _(L("Hold Shift to Slice & Export G-code")); + tooltip += wxString("\n") + _L("Hold Shift to Slice & Export G-code"); p->btn_reslice->SetToolTip(tooltip); } @@ -1154,16 +1154,16 @@ void Sidebar::show_info_sizer() const auto& stats = model_object->get_object_stl_stats();//model_object->volumes.front()->mesh.stl.stats; p->object_info->info_volume->SetLabel(wxString::Format("%.2f", stats.volume)); - p->object_info->info_facets->SetLabel(wxString::Format(_(L("%d (%d shells)")), static_cast(model_object->facets_count()), stats.number_of_parts)); + p->object_info->info_facets->SetLabel(wxString::Format(_L("%d (%d shells)"), static_cast(model_object->facets_count()), stats.number_of_parts)); int errors = stats.degenerate_facets + stats.edges_fixed + stats.facets_removed + stats.facets_added + stats.facets_reversed + stats.backwards_edges; if (errors > 0) { - wxString tooltip = wxString::Format(_(L("Auto-repaired (%d errors)")), errors); + wxString tooltip = wxString::Format(_L("Auto-repaired (%d errors)"), errors); p->object_info->info_manifold->SetLabel(tooltip); - tooltip += ":\n" + wxString::Format(_(L("%d degenerate facets, %d edges fixed, %d facets removed, " - "%d facets added, %d facets reversed, %d backwards edges")), + tooltip += ":\n" + wxString::Format(_L("%d degenerate facets, %d edges fixed, %d facets removed, " + "%d facets added, %d facets reversed, %d backwards edges"), stats.degenerate_facets, stats.edges_fixed, stats.facets_removed, stats.facets_added, stats.facets_reversed, stats.backwards_edges); @@ -1172,7 +1172,7 @@ void Sidebar::show_info_sizer() p->object_info->manifold_warning_icon->SetToolTip(tooltip); } else { - p->object_info->info_manifold->SetLabel(_(L("Yes"))); + p->object_info->info_manifold->SetLabel(_L("Yes")); p->object_info->showing_manifold_warning_icon = false; p->object_info->info_manifold->SetToolTip(""); p->object_info->manifold_warning_icon->SetToolTip(""); @@ -1193,10 +1193,10 @@ void Sidebar::update_sliced_info_sizer() if (p->plater->printer_technology() == ptSLA) { const SLAPrintStatistics& ps = p->plater->sla_print().print_statistics(); - wxString new_label = _(L("Used Material (ml)")) + ":"; + wxString new_label = _L("Used Material (ml)") + ":"; const bool is_supports = ps.support_used_material > 0.0; if (is_supports) - new_label += from_u8((boost::format("\n - %s\n - %s") % _utf8(L("object(s)")) % _utf8(L("supports and pad"))).str()); + new_label += format_wxstr("\n - %s\n - %s", _L("object(s)"), _L("supports and pad")); wxString info_text = is_supports ? wxString::Format("%.2f \n%.2f \n%.2f", (ps.objects_used_material + ps.support_used_material) / 1000, @@ -1218,7 +1218,7 @@ void Sidebar::update_sliced_info_sizer() p->sliced_info->SetTextAndShow(siCost, str_total_cost, "Cost"); wxString t_est = std::isnan(ps.estimated_print_time) ? "N/A" : get_time_dhms(float(ps.estimated_print_time)); - p->sliced_info->SetTextAndShow(siEstimatedTime, t_est, _(L("Estimated printing time")) + ":"); + p->sliced_info->SetTextAndShow(siEstimatedTime, t_est, _L("Estimated printing time") + ":"); // Hide non-SLA sliced info parameters p->sliced_info->SetTextAndShow(siFilament_m, "N/A"); @@ -1231,9 +1231,9 @@ void Sidebar::update_sliced_info_sizer() const PrintStatistics& ps = p->plater->fff_print().print_statistics(); const bool is_wipe_tower = ps.total_wipe_tower_filament > 0; - wxString new_label = _(L("Used Filament (m)")); + wxString new_label = _L("Used Filament (m)"); if (is_wipe_tower) - new_label += from_u8((boost::format(":\n - %1%\n - %2%") % _utf8(L("objects")) % _utf8(L("wipe tower"))).str()); + new_label += format_wxstr(":\n - %1%\n - %2%", _L("objects"), _L("wipe tower")); wxString info_text = is_wipe_tower ? wxString::Format("%.2f \n%.2f \n%.2f", ps.total_used_filament / 1000, @@ -1245,9 +1245,9 @@ void Sidebar::update_sliced_info_sizer() p->sliced_info->SetTextAndShow(siFilament_mm3, wxString::Format("%.2f", ps.total_extruded_volume)); p->sliced_info->SetTextAndShow(siFilament_g, ps.total_weight == 0.0 ? "N/A" : wxString::Format("%.2f", ps.total_weight)); - new_label = _(L("Cost")); + new_label = _L("Cost"); if (is_wipe_tower) - new_label += from_u8((boost::format(":\n - %1%\n - %2%") % _utf8(L("objects")) % _utf8(L("wipe tower"))).str()); + new_label += format_wxstr(":\n - %1%\n - %2%", _L("objects"), _L("wipe tower")); info_text = ps.total_cost == 0.0 ? "N/A" : is_wipe_tower ? @@ -1260,10 +1260,10 @@ void Sidebar::update_sliced_info_sizer() if (ps.estimated_normal_print_time == "N/A" && ps.estimated_silent_print_time == "N/A") p->sliced_info->SetTextAndShow(siEstimatedTime, "N/A"); else { - new_label = _(L("Estimated printing time")) +":"; + new_label = _L("Estimated printing time") +":"; info_text = ""; - wxString str_color = _(L("Color")); - wxString str_pause = _(L("Pause")); + wxString str_color = _L("Color"); + wxString str_pause = _L("Pause"); auto fill_labels = [str_color, str_pause](const std::vector>& times, wxString& new_label, wxString& info_text) @@ -1276,25 +1276,25 @@ void Sidebar::update_sliced_info_sizer() for (int i = (int)times.size() - 1; i >= 0; --i) { if (i == 0 || times[i - 1].first == cgtPausePrint) - new_label += from_u8((boost::format("\n - %1%%2%") % (std::string(str_color.ToUTF8()) + " ") % color_change_count).str()); + new_label += format_wxstr("\n - %1%%2%", str_color + " ", color_change_count); else if (times[i - 1].first == cgtColorChange) - new_label += from_u8((boost::format("\n - %1%%2%") % (std::string(str_color.ToUTF8()) + " ") % color_change_count--).str()); + new_label += format_wxstr("\n - %1%%2%", str_color + " ", color_change_count--); if (i != (int)times.size() - 1 && times[i].first == cgtPausePrint) - new_label += from_u8((boost::format(" -> %1%") % std::string(str_pause.ToUTF8())).str()); + new_label += format_wxstr(" -> %1%", str_pause); - info_text += from_u8((boost::format("\n%1%") % times[i].second).str()); + info_text += format_wxstr("\n%1%", times[i].second); } }; if (ps.estimated_normal_print_time != "N/A") { - new_label += from_u8((boost::format("\n - %1%") % _utf8(L("normal mode"))).str()); - info_text += from_u8((boost::format("\n%1%") % ps.estimated_normal_print_time).str()); + new_label += format_wxstr("\n - %1%", _L("normal mode")); + info_text += format_wxstr("\n%1%", ps.estimated_normal_print_time); fill_labels(ps.estimated_normal_custom_gcode_print_times, new_label, info_text); } if (ps.estimated_silent_print_time != "N/A") { - new_label += from_u8((boost::format("\n - %1%") % _utf8(L("stealth mode"))).str()); - info_text += from_u8((boost::format("\n%1%") % ps.estimated_silent_print_time).str()); + new_label += format_wxstr("\n - %1%", _L("stealth mode")); + info_text += format_wxstr("\n%1%", ps.estimated_silent_print_time); fill_labels(ps.estimated_silent_custom_gcode_print_times, new_label, info_text); } p->sliced_info->SetTextAndShow(siEstimatedTime, info_text, new_label); @@ -1397,11 +1397,11 @@ bool PlaterDropTarget::OnDropFiles(wxCoord x, wxCoord y, const wxArrayString &fi wxString snapshot_label; assert(! paths.empty()); if (paths.size() == 1) { - snapshot_label = _(L("Load File")); + snapshot_label = _L("Load File"); snapshot_label += ": "; snapshot_label += wxString::FromUTF8(paths.front().filename().string().c_str()); } else { - snapshot_label = _(L("Load Files")); + snapshot_label = _L("Load Files"); snapshot_label += ": "; snapshot_label += wxString::FromUTF8(paths.front().filename().string().c_str()); for (size_t i = 1; i < paths.size(); ++ i) { @@ -2201,11 +2201,11 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) this->q->Bind(EVT_REMOVABLE_DRIVE_EJECTED, [this](RemovableDriveEjectEvent &evt) { if (evt.data.second) { this->show_action_buttons(this->ready_to_slice); - Slic3r::GUI::show_info(this->q, (boost::format(_utf8(L("Unmounting successful. The device %s(%s) can now be safely removed from the computer."))) - % evt.data.first.name % evt.data.first.path).str()); + Slic3r::GUI::show_info(this->q, format_wxstr(_L("Unmounting successful. The device %s(%s) can now be safely removed from the computer."), + evt.data.first.name, evt.data.first.path)); } else - Slic3r::GUI::show_info(this->q, (boost::format(_utf8(L("Ejecting of device %s(%s) has failed."))) - % evt.data.first.name % evt.data.first.path).str()); + Slic3r::GUI::show_info(this->q, format_wxstr(_L("Ejecting of device %s(%s) has failed."), + evt.data.first.name, evt.data.first.path)); }); this->q->Bind(EVT_REMOVABLE_DRIVES_CHANGED, [this](RemovableDrivesChangedEvent &) { this->show_action_buttons(this->ready_to_slice); }); // Start the background thread and register this window as a target for update events. @@ -2217,7 +2217,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) #endif /* _WIN32 */ // Initialize the Undo / Redo stack with a first snapshot. - this->take_snapshot(_(L("New Project"))); + this->take_snapshot(_L("New Project")); } Plater::priv::~priv() @@ -2331,7 +2331,7 @@ std::vector Plater::priv::load_files(const std::vector& input_ } } - const auto loading = _(L("Loading")) + dots; + const auto loading = _L("Loading") + dots; wxProgressDialog dlg(loading, loading); dlg.Pulse(); @@ -2341,7 +2341,7 @@ std::vector Plater::priv::load_files(const std::vector& input_ for (size_t i = 0; i < input_files.size(); i++) { const auto &path = input_files[i]; const auto filename = path.filename(); - const auto dlg_info = from_u8((boost::format(_utf8(L("Processing input file %s"))) % from_path(filename)).str()) + "\n"; + const auto dlg_info = format_wxstr(_L("Processing input file %s"), from_path(filename)) + "\n"; dlg.Update(100 * i / input_files.size(), dlg_info); const bool type_3mf = std::regex_match(path.string(), pattern_3mf); @@ -2369,9 +2369,9 @@ std::vector Plater::priv::load_files(const std::vector& input_ if (object->volumes.size() > 1) { Slic3r::GUI::show_info(nullptr, - _(L("You cannot load SLA project with a multi-part object on the bed")) + "\n\n" + - _(L("Please check your object list before preset changing.")), - _(L("Attention!"))); + _L("You cannot load SLA project with a multi-part object on the bed") + "\n\n" + + _L("Please check your object list before preset changing."), + _L("Attention!")); return obj_idxs; } } @@ -2414,19 +2414,19 @@ std::vector Plater::priv::load_files(const std::vector& input_ if (! is_project_file) { if (model.looks_like_multipart_object()) { - wxMessageDialog msg_dlg(q, _(L( + wxMessageDialog msg_dlg(q, _L( "This file contains several objects positioned at multiple heights.\n" "Instead of considering them as multiple objects, should I consider\n" - "this file as a single object having multiple parts?")) + "\n", - _(L("Multi-part object detected")), wxICON_WARNING | wxYES | wxNO); + "this file as a single object having multiple parts?") + "\n", + _L("Multi-part object detected"), wxICON_WARNING | wxYES | wxNO); if (msg_dlg.ShowModal() == wxID_YES) { model.convert_multipart_object(nozzle_dmrs->values.size()); } } } else if ((wxGetApp().get_mode() == comSimple) && (type_3mf || type_any_amf) && model_has_advanced_features(model)) { - wxMessageDialog msg_dlg(q, _(L("This file cannot be loaded in a simple mode. Do you want to switch to an advanced mode?"))+"\n", - _(L("Detected advanced data")), wxICON_WARNING | wxYES | wxNO); + wxMessageDialog msg_dlg(q, _L("This file cannot be loaded in a simple mode. Do you want to switch to an advanced mode?")+"\n", + _L("Detected advanced data"), wxICON_WARNING | wxYES | wxNO); if (msg_dlg.ShowModal() == wxID_YES) { Slic3r::GUI::wxGetApp().save_mode(comAdvanced); @@ -2448,8 +2448,8 @@ std::vector Plater::priv::load_files(const std::vector& input_ for (auto obj : model.objects) if ( obj->volumes.size()>1 ) { Slic3r::GUI::show_error(nullptr, - from_u8((boost::format(_utf8(L("You can't to add the object(s) from %s because of one or some of them is(are) multi-part"))) - % from_path(filename)).str())); + format_wxstr(_L("You can't to add the object(s) from %s because of one or some of them is(are) multi-part"), + from_path(filename))); return obj_idxs; } } @@ -2467,11 +2467,11 @@ std::vector Plater::priv::load_files(const std::vector& input_ } if (new_model != nullptr && new_model->objects.size() > 1) { - wxMessageDialog msg_dlg(q, _(L( + wxMessageDialog msg_dlg(q, _L( "Multiple objects were loaded for a multi-material printer.\n" "Instead of considering them as multiple objects, should I consider\n" - "these files to represent a single object having multiple parts?")) + "\n", - _(L("Multi-part object detected")), wxICON_WARNING | wxYES | wxNO); + "these files to represent a single object having multiple parts?") + "\n", + _L("Multi-part object detected"), wxICON_WARNING | wxYES | wxNO); if (msg_dlg.ShowModal() == wxID_YES) { new_model->convert_multipart_object(nozzle_dmrs->values.size()); } @@ -2484,7 +2484,7 @@ std::vector Plater::priv::load_files(const std::vector& input_ { wxGetApp().app_config->update_skein_dir(input_files[input_files.size() - 1].parent_path().string()); // XXX: Plater.pm had @loaded_files, but didn't seem to fill them with the filenames... - statusbar()->set_status_text(_(L("Loaded"))); + statusbar()->set_status_text(_L("Loaded")); } // automatic selection of added objects @@ -2586,8 +2586,8 @@ std::vector Plater::priv::load_model_objects(const ModelObjectPtrs &mode if (scaled_down) { GUI::show_info(q, - _(L("Your object appears to be too large, so it was automatically scaled down to fit your print bed.")), - _(L("Object too large?"))); + _L("Your object appears to be too large, so it was automatically scaled down to fit your print bed."), + _L("Object too large?")); } for (const size_t idx : obj_idxs) { @@ -2649,26 +2649,26 @@ wxString Plater::priv::get_export_file(GUI::FileType file_type) case FT_STL: { output_file.replace_extension("stl"); - dlg_title = _(L("Export STL file:")); + dlg_title = _L("Export STL file:"); break; } case FT_AMF: { // XXX: Problem on OS X with double extension? output_file.replace_extension("zip.amf"); - dlg_title = _(L("Export AMF file:")); + dlg_title = _L("Export AMF file:"); break; } case FT_3MF: { output_file.replace_extension("3mf"); - dlg_title = _(L("Save file as:")); + dlg_title = _L("Save file as:"); break; } case FT_OBJ: { output_file.replace_extension("obj"); - dlg_title = _(L("Export OBJ file:")); + dlg_title = _L("Export OBJ file:"); break; } default: break; @@ -2740,15 +2740,12 @@ void Plater::priv::object_list_changed() void Plater::priv::select_all() { -// this->take_snapshot(_(L("Select All"))); - view3D->select_all(); this->sidebar->obj_list()->update_selections(); } void Plater::priv::deselect_all() { -// this->take_snapshot(_(L("Deselect All"))); view3D->deselect_all(); } @@ -2770,7 +2767,7 @@ void Plater::priv::remove(size_t obj_idx) void Plater::priv::delete_object_from_model(size_t obj_idx) { - wxString snapshot_label = _(L("Delete Object")); + wxString snapshot_label = _L("Delete Object"); if (! model.objects[obj_idx]->name.empty()) snapshot_label += ": " + wxString::FromUTF8(model.objects[obj_idx]->name.c_str()); Plater::TakeSnapshot snapshot(q, snapshot_label); @@ -2781,7 +2778,7 @@ void Plater::priv::delete_object_from_model(size_t obj_idx) void Plater::priv::reset() { - Plater::TakeSnapshot snapshot(q, _(L("Reset Project"))); + Plater::TakeSnapshot snapshot(q, _L("Reset Project")); set_project_filename(wxEmptyString); @@ -2812,7 +2809,7 @@ void Plater::priv::mirror(Axis axis) void Plater::priv::arrange() { - this->take_snapshot(_(L("Arrange"))); + this->take_snapshot(_L("Arrange")); m_ui_jobs.start(Jobs::Arrange); } @@ -2820,7 +2817,7 @@ void Plater::priv::arrange() // This method will find an optimal orientation for the currently selected item // Very similar in nature to the arrange method above... void Plater::priv::sla_optimize_rotation() { - this->take_snapshot(_(L("Optimize Rotation"))); + this->take_snapshot(_L("Optimize Rotation")); m_ui_jobs.start(Jobs::Rotoptimize); } @@ -2866,7 +2863,7 @@ void Plater::priv::find_new_position(const ModelInstancePtrs &instances, } void Plater::priv::ArrangeJob::process() { - static const auto arrangestr = _(L("Arranging")); + static const auto arrangestr = _L("Arranging"); // FIXME: I don't know how to obtain the minimum distance, it depends // on printer technology. I guess the following should work but it crashes. @@ -2893,14 +2890,14 @@ void Plater::priv::ArrangeJob::process() { }, stopfn); } catch (std::exception & /*e*/) { GUI::show_error(plater().q, - _(L("Could not arrange model objects! " - "Some geometries may be invalid."))); + _L("Could not arrange model objects! " + "Some geometries may be invalid.")); } // finalize just here. update_status(int(count), - was_canceled() ? _(L("Arranging canceled.")) - : _(L("Arranging done."))); + was_canceled() ? _L("Arranging canceled.") + : _L("Arranging done.")); } void Plater::priv::RotoptimizeJob::process() @@ -2916,7 +2913,7 @@ void Plater::priv::RotoptimizeJob::process() [this](unsigned s) { if (s < 100) update_status(int(s), - _(L("Searching for optimal orientation"))); + _L("Searching for optimal orientation")); }, [this]() { return was_canceled(); }); @@ -2949,8 +2946,8 @@ void Plater::priv::RotoptimizeJob::process() } update_status(100, - was_canceled() ? _(L("Orientation search canceled.")) - : _(L("Orientation found."))); + was_canceled() ? _L("Orientation search canceled.") + : _L("Orientation found.")); } @@ -2967,7 +2964,7 @@ void Plater::priv::split_object() if (current_model_object->volumes.size() > 1) { - Slic3r::GUI::warning_catcher(q, _(L("The selected object can't be split because it contains more than one volume/material."))); + Slic3r::GUI::warning_catcher(q, _L("The selected object can't be split because it contains more than one volume/material.")); return; } @@ -2975,10 +2972,10 @@ void Plater::priv::split_object() ModelObjectPtrs new_objects; current_model_object->split(&new_objects); if (new_objects.size() == 1) - Slic3r::GUI::warning_catcher(q, _(L("The selected object couldn't be split because it contains only one part."))); + Slic3r::GUI::warning_catcher(q, _L("The selected object couldn't be split because it contains only one part.")); else { - Plater::TakeSnapshot snapshot(q, _(L("Split to Objects"))); + Plater::TakeSnapshot snapshot(q, _L("Split to Objects")); unsigned int counter = 1; for (ModelObject* m : new_objects) @@ -3103,7 +3100,7 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool if ((return_state & UPDATE_BACKGROUND_PROCESS_INVALID) != 0) { // Validation of the background data failed. - const wxString invalid_str = _(L("Invalid data")); + const wxString invalid_str = _L("Invalid data"); for (auto btn : {ActionButtonType::abReslice, ActionButtonType::abSendGCode, ActionButtonType::abExport}) sidebar->set_btn_label(btn, invalid_str); } @@ -3112,13 +3109,13 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool // Background data is valid. if ((return_state & UPDATE_BACKGROUND_PROCESS_RESTART) != 0 || (return_state & UPDATE_BACKGROUND_PROCESS_REFRESH_SCENE) != 0 ) - this->statusbar()->set_status_text(_(L("Ready to slice"))); + this->statusbar()->set_status_text(_L("Ready to slice")); sidebar->set_btn_label(ActionButtonType::abExport, _(label_btn_export)); sidebar->set_btn_label(ActionButtonType::abSendGCode, _(label_btn_send)); const wxString slice_string = background_process.running() && wxGetApp().get_mode() == comSimple ? - _(L("Slicing")) + dots : _(L("Slice now")); + _L("Slicing") + dots : _L("Slice now"); sidebar->set_btn_label(ActionButtonType::abReslice, slice_string); if (background_process.finished()) @@ -3150,7 +3147,7 @@ bool Plater::priv::restart_background_process(unsigned int state) // The print is valid and it can be started. if (this->background_process.start()) { this->statusbar()->set_cancel_callback([this]() { - this->statusbar()->set_status_text(_(L("Cancelling"))); + this->statusbar()->set_status_text(_L("Cancelling")); this->background_process.stop(); }); return true; @@ -3167,7 +3164,7 @@ void Plater::priv::export_gcode(fs::path output_path, bool output_path_on_remova return; if (background_process.is_export_scheduled()) { - GUI::show_error(q, _(L("Another export job is currently running."))); + GUI::show_error(q, _L("Another export job is currently running.")); return; } @@ -3222,7 +3219,7 @@ void Plater::priv::update_sla_scene() void Plater::priv::reload_from_disk() { - Plater::TakeSnapshot snapshot(q, _(L("Reload from disk"))); + Plater::TakeSnapshot snapshot(q, _L("Reload from disk")); const Selection& selection = get_selection(); @@ -3283,7 +3280,7 @@ void Plater::priv::reload_from_disk() { // ask user to select the missing file fs::path search = missing_input_paths.back(); - wxString title = _(L("Please select the file to reload")); + wxString title = _L("Please select the file to reload"); #if defined(__APPLE__) title += " (" + from_u8(search.filename().string()) + ")"; #endif // __APPLE__ @@ -3318,7 +3315,7 @@ void Plater::priv::reload_from_disk() } else { - wxString message = _(L("It is not allowed to change the file to reload")) + " (" + from_u8(search.filename().string()) + ").\n" + _(L("Do you want to retry")) + " ?"; + wxString message = _L("It is not allowed to change the file to reload") + " (" + from_u8(search.filename().string()) + ").\n" + _L("Do you want to retry") + " ?"; wxMessageDialog dlg(q, message, wxMessageBoxCaptionStr, wxYES_NO | wxYES_DEFAULT | wxICON_QUESTION); if (dlg.ShowModal() != wxID_YES) return; @@ -3336,7 +3333,7 @@ void Plater::priv::reload_from_disk() const auto& path = input_paths[i].string(); wxBusyCursor wait; - wxBusyInfo info(_(L("Reload from:")) + " " + from_u8(path), q->get_current_canvas3D()->get_wxglcanvas()); + wxBusyInfo info(_L("Reload from:") + " " + from_u8(path), q->get_current_canvas3D()->get_wxglcanvas()); Model new_model; try @@ -3425,12 +3422,12 @@ void Plater::priv::reload_from_disk() if (!fail_list.empty()) { - wxString message = _(L("Unable to reload:")) + "\n"; + wxString message = _L("Unable to reload:") + "\n"; for (const wxString& s : fail_list) { message += s + "\n"; } - wxMessageDialog dlg(q, message, _(L("Error during reload")), wxOK | wxOK_DEFAULT | wxICON_WARNING); + wxMessageDialog dlg(q, message, _L("Error during reload"), wxOK | wxOK_DEFAULT | wxICON_WARNING); dlg.ShowModal(); } @@ -3449,7 +3446,7 @@ void Plater::priv::reload_all_from_disk() if (model.objects.empty()) return; - Plater::TakeSnapshot snapshot(q, _(L("Reload all from disk"))); + Plater::TakeSnapshot snapshot(q, _L("Reload all from disk")); Plater::SuppressSnapshots suppress(q); Selection& selection = get_selection(); @@ -3470,7 +3467,7 @@ void Plater::priv::fix_through_netfabb(const int obj_idx, const int vol_idx/* = if (obj_idx < 0) return; - Plater::TakeSnapshot snapshot(q, _(L("Fix Throught NetFabb"))); + Plater::TakeSnapshot snapshot(q, _L("Fix Throught NetFabb")); fix_model_by_win10_sdk_gui(*model.objects[obj_idx], vol_idx); this->update(); @@ -3669,7 +3666,7 @@ void Plater::priv::on_process_completed(wxCommandEvent &evt) if (error) { wxString message = evt.GetString(); if (message.IsEmpty()) - message = _(L("Export failed")); + message = _L("Export failed"); if (q->m_tracking_popup_menu) // We don't want to pop-up a message box when tracking a pop-up menu. // We postpone the error message instead. @@ -3679,7 +3676,7 @@ void Plater::priv::on_process_completed(wxCommandEvent &evt) this->statusbar()->set_status_text(message); } if (canceled) - this->statusbar()->set_status_text(_(L("Cancelled"))); + this->statusbar()->set_status_text(_L("Cancelled")); this->sidebar->show_sliced_info_sizer(success); @@ -3742,8 +3739,6 @@ void Plater::priv::on_action_layersediting(SimpleEvent&) void Plater::priv::on_object_select(SimpleEvent& evt) { -// this->take_snapshot(_(L("Object Selection"))); - wxGetApp().obj_list()->update_selections(); selection_changed(); } @@ -3793,7 +3788,7 @@ void Plater::priv::on_right_click(RBtnEvent& evt) */ const MenuIdentifier id = printer_technology == ptSLA ? miObjectSLA : miObjectFFF; if (wxGetApp().get_mode() == comSimple) { - if (menu->FindItem(_(L("Add instance"))) != wxNOT_FOUND) + if (menu->FindItem(_L("Add instance")) != wxNOT_FOUND) { /* Detach an items from the menu, but don't delete them * so that they can be added back later @@ -3805,7 +3800,7 @@ void Plater::priv::on_right_click(RBtnEvent& evt) } } else { - if (menu->FindItem(_(L("Add instance"))) == wxNOT_FOUND) + if (menu->FindItem(_L("Add instance")) == wxNOT_FOUND) { // Prepend items to the menu, if those aren't not there menu->Prepend(items_set_number_of_copies[id]); @@ -3934,20 +3929,20 @@ void Plater::priv::set_project_filename(const wxString& filename) bool Plater::priv::init_common_menu(wxMenu* menu, const bool is_part/* = false*/) { if (is_part) { - append_menu_item(menu, wxID_ANY, _(L("Delete")) + "\tDel", _(L("Remove the selected object")), + append_menu_item(menu, wxID_ANY, _L("Delete") + "\tDel", _L("Remove the selected object"), [this](wxCommandEvent&) { q->remove_selected(); }, "delete", nullptr, [this]() { return can_delete(); }, q); - append_menu_item(menu, wxID_ANY, _(L("Reload from disk")), _(L("Reload the selected volumes from disk")), + append_menu_item(menu, wxID_ANY, _L("Reload from disk"), _L("Reload the selected volumes from disk"), [this](wxCommandEvent&) { q->reload_from_disk(); }, "", menu, [this]() { return can_reload_from_disk(); }, q); sidebar->obj_list()->append_menu_item_export_stl(menu); } else { - wxMenuItem* item_increase = append_menu_item(menu, wxID_ANY, _(L("Add instance")) + "\t+", _(L("Add one more instance of the selected object")), + wxMenuItem* item_increase = append_menu_item(menu, wxID_ANY, _L("Add instance") + "\t+", _L("Add one more instance of the selected object"), [this](wxCommandEvent&) { q->increase_instances(); }, "add_copies", nullptr, [this]() { return can_increase_instances(); }, q); - wxMenuItem* item_decrease = append_menu_item(menu, wxID_ANY, _(L("Remove instance")) + "\t-", _(L("Remove one instance of the selected object")), + wxMenuItem* item_decrease = append_menu_item(menu, wxID_ANY, _L("Remove instance") + "\t-", _L("Remove one instance of the selected object"), [this](wxCommandEvent&) { q->decrease_instances(); }, "remove_copies", nullptr, [this]() { return can_decrease_instances(); }, q); - wxMenuItem* item_set_number_of_copies = append_menu_item(menu, wxID_ANY, _(L("Set number of instances")) + dots, _(L("Change the number of instances of the selected object")), + wxMenuItem* item_set_number_of_copies = append_menu_item(menu, wxID_ANY, _L("Set number of instances") + dots, _L("Change the number of instances of the selected object"), [this](wxCommandEvent&) { q->set_number_of_copies(); }, "number_of_copies", nullptr, [this]() { return can_increase_instances(); }, q); @@ -3956,7 +3951,7 @@ bool Plater::priv::init_common_menu(wxMenu* menu, const bool is_part/* = false*/ items_set_number_of_copies.push_back(item_set_number_of_copies); // Delete menu was moved to be after +/- instace to make it more difficult to be selected by mistake. - append_menu_item(menu, wxID_ANY, _(L("Delete")) + "\tDel", _(L("Remove the selected object")), + append_menu_item(menu, wxID_ANY, _L("Delete") + "\tDel", _L("Remove the selected object"), [this](wxCommandEvent&) { q->remove_selected(); }, "delete", nullptr, [this]() { return can_delete(); }, q); menu->AppendSeparator(); @@ -3966,10 +3961,10 @@ bool Plater::priv::init_common_menu(wxMenu* menu, const bool is_part/* = false*/ wxMenuItem* menu_item_printable = sidebar->obj_list()->append_menu_item_printable(menu, q); menu->AppendSeparator(); - append_menu_item(menu, wxID_ANY, _(L("Reload from disk")), _(L("Reload the selected object from disk")), + append_menu_item(menu, wxID_ANY, _L("Reload from disk"), _L("Reload the selected object from disk"), [this](wxCommandEvent&) { reload_from_disk(); }, "", nullptr, [this]() { return can_reload_from_disk(); }, q); - append_menu_item(menu, wxID_ANY, _(L("Export as STL")) + dots, _(L("Export the selected object as STL file")), + append_menu_item(menu, wxID_ANY, _L("Export as STL") + dots, _L("Export the selected object as STL file"), [this](wxCommandEvent&) { q->export_stl(false, true); }, "", nullptr, [this]() { const Selection& selection = get_selection(); @@ -3998,14 +3993,14 @@ bool Plater::priv::init_common_menu(wxMenu* menu, const bool is_part/* = false*/ if (mirror_menu == nullptr) return false; - append_menu_item(mirror_menu, wxID_ANY, _(L("Along X axis")), _(L("Mirror the selected object along the X axis")), + append_menu_item(mirror_menu, wxID_ANY, _L("Along X axis"), _L("Mirror the selected object along the X axis"), [this](wxCommandEvent&) { mirror(X); }, "mark_X", menu); - append_menu_item(mirror_menu, wxID_ANY, _(L("Along Y axis")), _(L("Mirror the selected object along the Y axis")), + append_menu_item(mirror_menu, wxID_ANY, _L("Along Y axis"), _L("Mirror the selected object along the Y axis"), [this](wxCommandEvent&) { mirror(Y); }, "mark_Y", menu); - append_menu_item(mirror_menu, wxID_ANY, _(L("Along Z axis")), _(L("Mirror the selected object along the Z axis")), + append_menu_item(mirror_menu, wxID_ANY, _L("Along Z axis"), _L("Mirror the selected object along the Z axis"), [this](wxCommandEvent&) { mirror(Z); }, "mark_Z", menu); - append_submenu(menu, mirror_menu, wxID_ANY, _(L("Mirror")), _(L("Mirror the selected object")), "", + append_submenu(menu, mirror_menu, wxID_ANY, _L("Mirror"), _L("Mirror the selected object"), "", [this]() { return can_mirror(); }, q); return true; @@ -4017,12 +4012,12 @@ bool Plater::priv::complit_init_object_menu() if (split_menu == nullptr) return false; - append_menu_item(split_menu, wxID_ANY, _(L("To objects")), _(L("Split the selected object into individual objects")), + append_menu_item(split_menu, wxID_ANY, _L("To objects"), _L("Split the selected object into individual objects"), [this](wxCommandEvent&) { split_object(); }, "split_object_SMALL", &object_menu, [this]() { return can_split(); }, q); - append_menu_item(split_menu, wxID_ANY, _(L("To parts")), _(L("Split the selected object into individual sub-parts")), + append_menu_item(split_menu, wxID_ANY, _L("To parts"), _L("Split the selected object into individual sub-parts"), [this](wxCommandEvent&) { split_volume(); }, "split_parts_SMALL", &object_menu, [this]() { return can_split(); }, q); - append_submenu(&object_menu, split_menu, wxID_ANY, _(L("Split")), _(L("Split the selected object")), "", + append_submenu(&object_menu, split_menu, wxID_ANY, _L("Split"), _L("Split the selected object"), "", [this]() { return can_split() && wxGetApp().get_mode() > comSimple; }, q); object_menu.AppendSeparator(); @@ -4037,13 +4032,13 @@ bool Plater::priv::complit_init_object_menu() bool Plater::priv::complit_init_sla_object_menu() { - append_menu_item(&sla_object_menu, wxID_ANY, _(L("Split")), _(L("Split the selected object into individual objects")), + append_menu_item(&sla_object_menu, wxID_ANY, _L("Split"), _L("Split the selected object into individual objects"), [this](wxCommandEvent&) { split_object(); }, "split_object_SMALL", nullptr, [this]() { return can_split(); }, q); sla_object_menu.AppendSeparator(); // Add the automatic rotation sub-menu - append_menu_item(&sla_object_menu, wxID_ANY, _(L("Optimize orientation")), _(L("Optimize the rotation of the object for better print results.")), + append_menu_item(&sla_object_menu, wxID_ANY, _L("Optimize orientation"), _L("Optimize the rotation of the object for better print results."), [this](wxCommandEvent&) { sla_optimize_rotation(); }); return true; @@ -4051,7 +4046,7 @@ bool Plater::priv::complit_init_sla_object_menu() bool Plater::priv::complit_init_part_menu() { - append_menu_item(&part_menu, wxID_ANY, _(L("Split")), _(L("Split the selected object into individual sub-parts")), + append_menu_item(&part_menu, wxID_ANY, _L("Split"), _L("Split the selected object into individual sub-parts"), [this](wxCommandEvent&) { split_volume(); }, "split_parts_SMALL", nullptr, [this]() { return can_split(); }, q); part_menu.AppendSeparator(); @@ -4417,8 +4412,8 @@ void Plater::priv::undo_redo_to(std::vector::const_iterator if (printer_technology_changed) { // Switching the printer technology when jumping forwards / backwards in time. Switch to the last active printer profile of the other type. std::string s_pt = (it_snapshot->snapshot_data.printer_technology == ptFFF) ? "FFF" : "SLA"; - if (! wxGetApp().check_unsaved_changes(from_u8((boost::format(_utf8( - L("%1% printer was active at the time the target Undo / Redo snapshot was taken. Switching to %1% printer requires reloading of %1% presets."))) % s_pt).str()))) + if (! wxGetApp().check_unsaved_changes(format_wxstr(_L( + "%1% printer was active at the time the target Undo / Redo snapshot was taken. Switching to %1% printer requires reloading of %1% presets."), s_pt))) // Don't switch the profiles. return; } @@ -4594,7 +4589,7 @@ void Plater::load_project(const wxString& filename) return; // Take the Undo / Redo snapshot. - Plater::TakeSnapshot snapshot(this, _(L("Load Project")) + ": " + wxString::FromUTF8(into_path(filename).stem().string().c_str())); + Plater::TakeSnapshot snapshot(this, _L("Load Project") + ": " + wxString::FromUTF8(into_path(filename).stem().string().c_str())); p->reset(); @@ -4622,11 +4617,11 @@ void Plater::add_model() wxString snapshot_label; assert(! paths.empty()); if (paths.size() == 1) { - snapshot_label = _(L("Import Object")); + snapshot_label = _L("Import Object"); snapshot_label += ": "; snapshot_label += wxString::FromUTF8(paths.front().filename().string().c_str()); } else { - snapshot_label = _(L("Import Objects")); + snapshot_label = _L("Import Objects"); snapshot_label += ": "; snapshot_label += wxString::FromUTF8(paths.front().filename().string().c_str()); for (size_t i = 1; i < paths.size(); ++ i) { @@ -4695,7 +4690,7 @@ void Plater::remove(size_t obj_idx) { p->remove(obj_idx); } void Plater::reset() { p->reset(); } void Plater::reset_with_confirm() { - if (wxMessageDialog((wxWindow*)this, _(L("All objects will be removed, continue?")), wxString(SLIC3R_APP_NAME) + " - " + _(L("Delete all")), wxYES_NO | wxCANCEL | wxYES_DEFAULT | wxCENTRE).ShowModal() == wxID_YES) + if (wxMessageDialog((wxWindow*)this, _L("All objects will be removed, continue?"), wxString(SLIC3R_APP_NAME) + " - " + _L("Delete all"), wxYES_NO | wxCANCEL | wxYES_DEFAULT | wxCENTRE).ShowModal() == wxID_YES) reset(); } @@ -4703,7 +4698,7 @@ void Plater::delete_object_from_model(size_t obj_idx) { p->delete_object_from_mo void Plater::remove_selected() { - Plater::TakeSnapshot snapshot(this, _(L("Delete Selected Objects"))); + Plater::TakeSnapshot snapshot(this, _L("Delete Selected Objects")); this->p->view3D->delete_selected(); } @@ -4711,7 +4706,7 @@ void Plater::increase_instances(size_t num) { if (! can_increase_instances()) { return; } - Plater::TakeSnapshot snapshot(this, _(L("Increase Instances"))); + Plater::TakeSnapshot snapshot(this, _L("Increase Instances")); int obj_idx = p->get_selected_object_idx(); @@ -4746,7 +4741,7 @@ void Plater::decrease_instances(size_t num) { if (! can_decrease_instances()) { return; } - Plater::TakeSnapshot snapshot(this, _(L("Decrease Instances"))); + Plater::TakeSnapshot snapshot(this, _L("Decrease Instances")); int obj_idx = p->get_selected_object_idx(); @@ -4777,12 +4772,12 @@ void Plater::set_number_of_copies(/*size_t num*/) ModelObject* model_object = p->model.objects[obj_idx]; - const int num = wxGetNumberFromUser( " ", _(L("Enter the number of copies:")), - _(L("Copies of the selected object")), model_object->instances.size(), 0, 1000, this ); + const int num = wxGetNumberFromUser( " ", _L("Enter the number of copies:"), + _L("Copies of the selected object"), model_object->instances.size(), 0, 1000, this ); if (num < 0) return; - Plater::TakeSnapshot snapshot(this, wxString::Format(_(L("Set numbers of copies to %d")), num)); + Plater::TakeSnapshot snapshot(this, wxString::Format(_L("Set numbers of copies to %d"), num)); int diff = num - (int)model_object->instances.size(); if (diff > 0) @@ -4812,7 +4807,7 @@ void Plater::cut(size_t obj_idx, size_t instance_idx, coordf_t z, bool keep_uppe return; } - Plater::TakeSnapshot snapshot(this, _(L("Cut by Plane"))); + Plater::TakeSnapshot snapshot(this, _L("Cut by Plane")); wxBusyCursor wait; const auto new_objects = object->cut(instance_idx, z, keep_upper, keep_lower, rotate_lower); @@ -4863,7 +4858,7 @@ void Plater::export_gcode(bool prefer_removable) fs::path output_path; { - wxFileDialog dlg(this, (printer_technology() == ptFFF) ? _(L("Save G-code file as:")) : _(L("Save SL1 file as:")), + wxFileDialog dlg(this, (printer_technology() == ptFFF) ? _L("Save G-code file as:") : _L("Save SL1 file as:"), start_dir, from_path(default_output_file.filename()), GUI::file_wildcards((printer_technology() == ptFFF) ? FT_GCODE : FT_PNGZIP, default_output_file.extension().string()), @@ -4998,7 +4993,7 @@ void Plater::export_stl(bool extended, bool selection_only) } Slic3r::store_stl(path_u8.c_str(), &mesh, true); - p->statusbar()->set_status_text(from_u8((boost::format(_utf8(L("STL file exported to %s"))) % path).str())); + p->statusbar()->set_status_text(format_wxstr(_L("STL file exported to %s"), path)); } void Plater::export_amf() @@ -5015,10 +5010,10 @@ void Plater::export_amf() bool full_pathnames = wxGetApp().app_config->get("export_sources_full_pathnames") == "1"; if (Slic3r::store_amf(path_u8.c_str(), &p->model, export_config ? &cfg : nullptr, full_pathnames)) { // Success - p->statusbar()->set_status_text(from_u8((boost::format(_utf8(L("AMF file exported to %s"))) % path).str())); + p->statusbar()->set_status_text(format_wxstr(_L("AMF file exported to %s"), path)); } else { // Failure - p->statusbar()->set_status_text(from_u8((boost::format(_utf8(L("Error exporting AMF file %s"))) % path).str())); + p->statusbar()->set_status_text(format_wxstr(_L("Error exporting AMF file %s"), path)); } } @@ -5047,12 +5042,12 @@ void Plater::export_3mf(const boost::filesystem::path& output_path) p->generate_thumbnail(thumbnail_data, THUMBNAIL_SIZE_3MF.first, THUMBNAIL_SIZE_3MF.second, false, true, true, true); if (Slic3r::store_3mf(path_u8.c_str(), &p->model, export_config ? &cfg : nullptr, full_pathnames, &thumbnail_data)) { // Success - p->statusbar()->set_status_text(from_u8((boost::format(_utf8(L("3MF file exported to %s"))) % path).str())); + p->statusbar()->set_status_text(format_wxstr(_L("3MF file exported to %s"), path)); p->set_project_filename(path); } else { // Failure - p->statusbar()->set_status_text(from_u8((boost::format(_utf8(L("Error exporting 3MF file %s"))) % path).str())); + p->statusbar()->set_status_text(format_wxstr(_L("Error exporting 3MF file %s"), path)); } } @@ -5112,10 +5107,10 @@ void Plater::reslice() if (p->background_process.running()) { if (wxGetApp().get_mode() == comSimple) - p->sidebar->set_btn_label(ActionButtonType::abReslice, _(L("Slicing")) + dots); + p->sidebar->set_btn_label(ActionButtonType::abReslice, _L("Slicing") + dots); else { - p->sidebar->set_btn_label(ActionButtonType::abReslice, _(L("Slice now"))); + p->sidebar->set_btn_label(ActionButtonType::abReslice, _L("Slice now")); p->show_action_buttons(false); } } @@ -5602,7 +5597,7 @@ void Plater::paste_from_clipboard() if (!can_paste_from_clipboard()) return; - Plater::TakeSnapshot snapshot(this, _(L("Paste From Clipboard"))); + Plater::TakeSnapshot snapshot(this, _L("Paste From Clipboard")); p->view3D->get_canvas3d()->get_selection().paste_from_clipboard(); } diff --git a/src/slic3r/GUI/format.hpp b/src/slic3r/GUI/format.hpp new file mode 100644 index 000000000..1bc4b93d2 --- /dev/null +++ b/src/slic3r/GUI/format.hpp @@ -0,0 +1,65 @@ +#ifndef slic3r_GUI_format_hpp_ +#define slic3r_GUI_format_hpp_ + +// Functional wrapper around boost::format. +// One day we may replace this wrapper with C++20 format +// https://en.cppreference.com/w/cpp/utility/format/format +// though C++20 format uses a different template pattern for position independent parameters. +// This wrapper also manages implicit conversion from wxString to UTF8 and format_wxstr() variants are provided to format into wxString. + +#include + +namespace Slic3r { +namespace GUI { + +// Format input mixing UTF8 encoded strings (const char*, std::string) and wxStrings, return a wxString. +template +inline wxString format_wxstr(const char* fmt, TArgs&&... args) { + boost::format message(fmt); + return wxString::FromUTF8(Slic3r::internal::format::format_recursive(message, std::forward(args)...).c_str()); +} +template +inline wxString format_wxstr(const std::string& fmt, TArgs&&... args) { + boost::format message(fmt); + return wxString::FromUTF8(Slic3r::internal::format::format_recursive(message, std::forward(args)...).c_str()); +} +template +inline wxString format_wxstr(const wxString& fmt, TArgs&&... args) { + return format_wxstr(fmt.ToUTF8().data()); +} +template +inline std::string format(const wxString& fmt, TArgs&&... args) { + return format(fmt.ToUTF8().data()); +} + +} // namespace GUI + +namespace internal { + namespace format { + // Wrapper around wxScopedCharBuffer to indicate that the content is UTF8 formatted. + struct utf8_buffer { + // wxScopedCharBuffer is reference counted, therefore copying by value is cheap. + wxScopedCharBuffer data; + }; + // Accept wxString and convert it to UTF8 to be processed by Slic3r::format(). + inline const utf8_buffer cook(const wxString &arg) { + return utf8_buffer { arg.ToUTF8() }; + } + } +} + +} // namespace Slic3r + +namespace boost { + namespace io { + namespace detail { + // Adaptor for boost::format to accept wxString converted to UTF8. + inline std::ostream& operator<<(std::ostream& os, const Slic3r::internal::format::utf8_buffer& str) { + os << str.data.data(); + return os; + } + } + } +} + +#endif /* slic3r_GUI_format_hpp_ */ diff --git a/src/slic3r/Utils/PresetUpdater.cpp b/src/slic3r/Utils/PresetUpdater.cpp index 48b1fbf8a..7c6c86384 100644 --- a/src/slic3r/Utils/PresetUpdater.cpp +++ b/src/slic3r/Utils/PresetUpdater.cpp @@ -17,6 +17,7 @@ #include #include "libslic3r/libslic3r.h" +#include "libslic3r/format.hpp" #include "libslic3r/Utils.hpp" #include "slic3r/GUI/GUI.hpp" #include "slic3r/GUI/I18N.hpp" @@ -54,7 +55,7 @@ void copy_file_fix(const fs::path &source, const fs::path &target) { static const auto perms = fs::owner_read | fs::owner_write | fs::group_read | fs::others_read; // aka 644 - BOOST_LOG_TRIVIAL(debug) << boost::format("PresetUpdater: Copying %1% -> %2%") % source % target; + BOOST_LOG_TRIVIAL(debug) << format("PresetUpdater: Copying %1% -> %2%", source, target); // Make sure the file has correct permission both before and after we copy over it if (fs::exists(target)) { @@ -190,12 +191,12 @@ bool PresetUpdater::priv::get_file(const std::string &url, const fs::path &targe { bool res = false; fs::path tmp_path = target_path; - tmp_path += (boost::format(".%1%%2%") % get_current_pid() % TMP_EXTENSION).str(); + tmp_path += format(".%1%%2%", get_current_pid(), TMP_EXTENSION); - BOOST_LOG_TRIVIAL(info) << boost::format("Get: `%1%`\n\t-> `%2%`\n\tvia tmp path `%3%`") - % url - % target_path.string() - % tmp_path.string(); + BOOST_LOG_TRIVIAL(info) << format("Get: `%1%`\n\t-> `%2%`\n\tvia tmp path `%3%`", + url, + target_path.string(), + tmp_path.string()); Http::get(url) .on_progress([this](Http::Progress, bool &cancel) { @@ -203,10 +204,10 @@ bool PresetUpdater::priv::get_file(const std::string &url, const fs::path &targe }) .on_error([&](std::string body, std::string error, unsigned http_status) { (void)body; - BOOST_LOG_TRIVIAL(error) << boost::format("Error getting: `%1%`: HTTP %2%, %3%") - % url - % http_status - % error; + BOOST_LOG_TRIVIAL(error) << format("Error getting: `%1%`: HTTP %2%, %3%", + url, + http_status, + error); }) .on_complete([&](std::string body, unsigned /* http_status */) { fs::fstream file(tmp_path, std::ios::out | std::ios::binary | std::ios::trunc); @@ -235,7 +236,7 @@ void PresetUpdater::priv::sync_version() const { if (! enabled_version_check) { return; } - BOOST_LOG_TRIVIAL(info) << boost::format("Downloading %1% online version from: `%2%`") % SLIC3R_APP_NAME % version_check_url; + BOOST_LOG_TRIVIAL(info) << format("Downloading %1% online version from: `%2%`", SLIC3R_APP_NAME, version_check_url); Http::get(version_check_url) .size_limit(SLIC3R_VERSION_BODY_MAX) @@ -244,10 +245,10 @@ void PresetUpdater::priv::sync_version() const }) .on_error([&](std::string body, std::string error, unsigned http_status) { (void)body; - BOOST_LOG_TRIVIAL(error) << boost::format("Error getting: `%1%`: HTTP %2%, %3%") - % version_check_url - % http_status - % error; + BOOST_LOG_TRIVIAL(error) << format("Error getting: `%1%`: HTTP %2%, %3%", + version_check_url, + http_status, + error); }) .on_complete([&](std::string body, unsigned /* http_status */) { boost::trim(body); @@ -257,11 +258,11 @@ void PresetUpdater::priv::sync_version() const } if (! Semver::parse(body)) { - BOOST_LOG_TRIVIAL(warning) << boost::format("Received invalid contents from `%1%`: Not a correct semver: `%2%`") % SLIC3R_APP_NAME % body; + BOOST_LOG_TRIVIAL(warning) << format("Received invalid contents from `%1%`: Not a correct semver: `%2%`", SLIC3R_APP_NAME, body); return; } - BOOST_LOG_TRIVIAL(info) << boost::format("Got %1% online version: `%2%`. Sending to GUI thread...") % SLIC3R_APP_NAME % body; + BOOST_LOG_TRIVIAL(info) << format("Got %1% online version: `%2%`. Sending to GUI thread...", SLIC3R_APP_NAME, body); wxCommandEvent* evt = new wxCommandEvent(EVT_SLIC3R_VERSION_ONLINE); evt->SetString(GUI::from_u8(body)); @@ -315,11 +316,11 @@ void PresetUpdater::priv::sync_config(const VendorMap vendors) try { new_index.load(idx_path_temp); } catch (const std::exception & /* err */) { - BOOST_LOG_TRIVIAL(error) << boost::format("Could not load downloaded index %1% for vendor %2%: invalid index?") % idx_path_temp % vendor.name; + BOOST_LOG_TRIVIAL(error) << format("Could not load downloaded index %1% for vendor %2%: invalid index?", idx_path_temp, vendor.name); continue; } if (new_index.version() < index.version()) { - BOOST_LOG_TRIVIAL(warning) << boost::format("The downloaded index %1% for vendor %2% is older than the active one. Ignoring the downloaded index.") % idx_path_temp % vendor.name; + BOOST_LOG_TRIVIAL(warning) << format("The downloaded index %1% for vendor %2% is older than the active one. Ignoring the downloaded index.", idx_path_temp, vendor.name); continue; } Slic3r::rename_file(idx_path_temp, idx_path); @@ -331,22 +332,22 @@ void PresetUpdater::priv::sync_config(const VendorMap vendors) // See if a there's a new version to download const auto recommended_it = index.recommended(); if (recommended_it == index.end()) { - BOOST_LOG_TRIVIAL(error) << boost::format("No recommended version for vendor: %1%, invalid index?") % vendor.name; + BOOST_LOG_TRIVIAL(error) << format("No recommended version for vendor: %1%, invalid index?", vendor.name); continue; } const auto recommended = recommended_it->config_version; - BOOST_LOG_TRIVIAL(debug) << boost::format("Got index for vendor: %1%: current version: %2%, recommended version: %3%") - % vendor.name - % vendor.config_version.to_string() - % recommended.to_string(); + BOOST_LOG_TRIVIAL(debug) << format("Got index for vendor: %1%: current version: %2%, recommended version: %3%", + vendor.name, + vendor.config_version.to_string(), + recommended.to_string()); if (vendor.config_version >= recommended) { continue; } // Download a fresh bundle BOOST_LOG_TRIVIAL(info) << "Downloading new bundle for vendor: " << vendor.name; - const auto bundle_url = (boost::format("%1%/%2%.ini") % vendor.config_update_url % recommended.to_string()).str(); + const auto bundle_url = format("%1%/%2%.ini", vendor.config_update_url, recommended.to_string()); const auto bundle_path = cache_path / (vendor.id + ".ini"); if (! get_file(bundle_url, bundle_path)) { continue; } if (cancel) { return; } @@ -394,7 +395,7 @@ Updates PresetUpdater::priv::get_config_updates(const Semver &old_slic3r_version auto bundle_path_idx = vendor_path / idx.path().filename(); if (! fs::exists(bundle_path)) { - BOOST_LOG_TRIVIAL(info) << boost::format("Confing bundle not installed for vendor %1%, skipping: ") % idx.vendor(); + BOOST_LOG_TRIVIAL(info) << format("Confing bundle not installed for vendor %1%, skipping: ", idx.vendor()); continue; } @@ -405,7 +406,7 @@ Updates PresetUpdater::priv::get_config_updates(const Semver &old_slic3r_version // from the internet, or installed / updated from the installation resources. auto recommended = idx.recommended(); if (recommended == idx.end()) { - BOOST_LOG_TRIVIAL(error) << boost::format("No recommended version for vendor: %1%, invalid index? Giving up.") % idx.vendor(); + BOOST_LOG_TRIVIAL(error) << format("No recommended version for vendor: %1%, invalid index? Giving up.", idx.vendor()); // XXX: what should be done here? continue; } @@ -413,15 +414,15 @@ Updates PresetUpdater::priv::get_config_updates(const Semver &old_slic3r_version const auto ver_current = idx.find(vp.config_version); const bool ver_current_found = ver_current != idx.end(); - BOOST_LOG_TRIVIAL(debug) << boost::format("Vendor: %1%, version installed: %2%%3%, version cached: %4%") - % vp.name - % vp.config_version.to_string() - % (ver_current_found ? "" : " (not found in index!)") - % recommended->config_version.to_string(); + BOOST_LOG_TRIVIAL(debug) << format("Vendor: %1%, version installed: %2%%3%, version cached: %4%", + vp.name, + vp.config_version.to_string(), + (ver_current_found ? "" : " (not found in index!)"), + recommended->config_version.to_string()); if (! ver_current_found) { // Any published config shall be always found in the latest config index. - auto message = (boost::format("Preset bundle `%1%` version not found in index: %2%") % idx.vendor() % vp.config_version.to_string()).str(); + auto message = format("Preset bundle `%1%` version not found in index: %2%", idx.vendor(), vp.config_version.to_string()); BOOST_LOG_TRIVIAL(error) << message; GUI::show_error(nullptr, message); continue; @@ -440,7 +441,7 @@ Updates PresetUpdater::priv::get_config_updates(const Semver &old_slic3r_version } if (recommended->config_version < vp.config_version) { - BOOST_LOG_TRIVIAL(warning) << (boost::format("Recommended config version for the currently running PrusaSlicer is older than the currently installed config for vendor %1%. This should not happen.") % idx.vendor()).str(); + BOOST_LOG_TRIVIAL(warning) << format("Recommended config version for the currently running PrusaSlicer is older than the currently installed config for vendor %1%. This should not happen.", idx.vendor()); continue; } @@ -482,7 +483,7 @@ Updates PresetUpdater::priv::get_config_updates(const Semver &old_slic3r_version found = true; } } catch (const std::exception &ex) { - BOOST_LOG_TRIVIAL(info) << boost::format("Failed to load the config bundle `%1%`: %2%") % path_in_cache.string() % ex.what(); + BOOST_LOG_TRIVIAL(info) << format("Failed to load the config bundle `%1%`: %2%", path_in_cache.string(), ex.what()); } } @@ -496,13 +497,13 @@ Updates PresetUpdater::priv::get_config_updates(const Semver &old_slic3r_version try { rsrc_vp = VendorProfile::from_ini(path_in_rsrc, false); } catch (const std::exception &ex) { - BOOST_LOG_TRIVIAL(info) << boost::format("Cannot load the config bundle at `%1%`: %2%") % path_in_rsrc.string() % ex.what(); + BOOST_LOG_TRIVIAL(info) << format("Cannot load the config bundle at `%1%`: %2%", path_in_rsrc.string(), ex.what()); } if (rsrc_vp.valid()) { try { rsrc_idx.load(path_idx_in_rsrc); } catch (const std::exception &ex) { - BOOST_LOG_TRIVIAL(info) << boost::format("Cannot load the config index at `%1%`: %2%") % path_idx_in_rsrc.string() % ex.what(); + BOOST_LOG_TRIVIAL(info) << format("Cannot load the config index at `%1%`: %2%", path_idx_in_rsrc.string(), ex.what()); } recommended = rsrc_idx.recommended(); if (recommended != rsrc_idx.end() && recommended->config_version == rsrc_vp.config_version && recommended->config_version > vp.config_version) { @@ -510,8 +511,8 @@ Updates PresetUpdater::priv::get_config_updates(const Semver &old_slic3r_version bundle_path_idx_to_install = path_idx_in_rsrc; found = true; } else { - BOOST_LOG_TRIVIAL(warning) << (boost::format("The recommended config version for vendor `%1%` in resources does not match the recommended\n" - " config version for this version of PrusaSlicer. Corrupted installation?") % idx.vendor()).str(); + BOOST_LOG_TRIVIAL(warning) << format("The recommended config version for vendor `%1%` in resources does not match the recommended\n" + " config version for this version of PrusaSlicer. Corrupted installation?", idx.vendor()); } } } @@ -529,11 +530,11 @@ Updates PresetUpdater::priv::get_config_updates(const Semver &old_slic3r_version /*const auto existing_recommended = existing_idx.recommended(old_slic3r_version); if (existing_recommended != existing_idx.end() && recommended->config_version == existing_recommended->config_version) { // The user has already seen (and presumably rejected) this update - BOOST_LOG_TRIVIAL(info) << boost::format("Downloaded index for `%1%` is the same as installed one, not offering an update.") % idx.vendor(); + BOOST_LOG_TRIVIAL(info) << format("Downloaded index for `%1%` is the same as installed one, not offering an update.",idx.vendor()); continue; }*/ } catch (const std::exception &err) { - BOOST_LOG_TRIVIAL(error) << boost::format("Cannot load the installed index at `%1%`: %2%") % bundle_path_idx % err.what(); + BOOST_LOG_TRIVIAL(error) << format("Cannot load the installed index at `%1%`: %2%", bundle_path_idx, err.what()); } } @@ -542,10 +543,10 @@ Updates PresetUpdater::priv::get_config_updates(const Semver &old_slic3r_version { const auto recommended_snap = SnapshotDB::singleton().snapshot_with_vendor_preset(vp.name, recommended->config_version); if (recommended_snap != SnapshotDB::singleton().end()) { - BOOST_LOG_TRIVIAL(info) << boost::format("Bundle update %1% %2% already found in snapshot %3%, skipping...") - % vp.name - % recommended->config_version.to_string() - % recommended_snap->id; + BOOST_LOG_TRIVIAL(info) << format("Bundle update %1% %2% already found in snapshot %3%, skipping...", + vp.name, + recommended->config_version.to_string(), + recommended_snap->id); continue; } } @@ -555,9 +556,9 @@ Updates PresetUpdater::priv::get_config_updates(const Semver &old_slic3r_version // offered updates and to not offer the same update again if it was cancelled by the user. copy_file_fix(bundle_path_idx_to_install, bundle_path_idx); } else { - BOOST_LOG_TRIVIAL(warning) << boost::format("Index for vendor %1% indicates update (%2%) but the new bundle was found neither in cache nor resources") - % idx.vendor() - % recommended->config_version.to_string(); + BOOST_LOG_TRIVIAL(warning) << format("Index for vendor %1% indicates update (%2%) but the new bundle was found neither in cache nor resources", + idx.vendor(), + recommended->config_version.to_string()); } } @@ -572,7 +573,7 @@ void PresetUpdater::priv::perform_updates(Updates &&updates, bool snapshot) cons SnapshotDB::singleton().take_snapshot(*GUI::wxGetApp().app_config, Snapshot::SNAPSHOT_DOWNGRADE); } - BOOST_LOG_TRIVIAL(info) << boost::format("Deleting %1% incompatible bundles") % updates.incompats.size(); + BOOST_LOG_TRIVIAL(info) << format("Deleting %1% incompatible bundles", updates.incompats.size()); for (auto &incompat : updates.incompats) { BOOST_LOG_TRIVIAL(info) << '\t' << incompat; @@ -587,7 +588,7 @@ void PresetUpdater::priv::perform_updates(Updates &&updates, bool snapshot) cons SnapshotDB::singleton().take_snapshot(*GUI::wxGetApp().app_config, Snapshot::SNAPSHOT_UPGRADE); } - BOOST_LOG_TRIVIAL(info) << boost::format("Performing %1% updates") % updates.updates.size(); + BOOST_LOG_TRIVIAL(info) << format("Performing %1% updates", updates.updates.size()); for (const auto &update : updates.updates) { BOOST_LOG_TRIVIAL(info) << '\t' << update; @@ -597,8 +598,7 @@ void PresetUpdater::priv::perform_updates(Updates &&updates, bool snapshot) cons PresetBundle bundle; bundle.load_configbundle(update.source.string(), PresetBundle::LOAD_CFGBNDLE_SYSTEM); - BOOST_LOG_TRIVIAL(info) << boost::format("Deleting %1% conflicting presets") - % (bundle.prints.size() + bundle.filaments.size() + bundle.printers.size()); + BOOST_LOG_TRIVIAL(info) << format("Deleting %1% conflicting presets", bundle.prints.size() + bundle.filaments.size() + bundle.printers.size()); auto preset_remover = [](const Preset &preset) { BOOST_LOG_TRIVIAL(info) << '\t' << preset.file; @@ -611,8 +611,8 @@ void PresetUpdater::priv::perform_updates(Updates &&updates, bool snapshot) cons // Also apply the `obsolete_presets` property, removing obsolete ini files - BOOST_LOG_TRIVIAL(info) << boost::format("Deleting %1% obsolete presets") - % (bundle.obsolete_presets.prints.size() + bundle.obsolete_presets.filaments.size() + bundle.obsolete_presets.printers.size()); + BOOST_LOG_TRIVIAL(info) << format("Deleting %1% obsolete presets", + bundle.obsolete_presets.prints.size() + bundle.obsolete_presets.filaments.size() + bundle.obsolete_presets.printers.size()); auto obsolete_remover = [](const char *subdir, const std::string &preset) { auto path = fs::path(Slic3r::data_dir()) / subdir / preset; @@ -694,7 +694,7 @@ PresetUpdater::UpdateResult PresetUpdater::config_update(const Semver &old_slic3 auto updates = p->get_config_updates(old_slic3r_version); if (updates.incompats.size() > 0) { - BOOST_LOG_TRIVIAL(info) << boost::format("%1% bundles incompatible. Asking for action...") % updates.incompats.size(); + BOOST_LOG_TRIVIAL(info) << format("%1% bundles incompatible. Asking for action...", updates.incompats.size()); std::unordered_map incompats_map; for (const auto &incompat : updates.incompats) { @@ -702,15 +702,14 @@ PresetUpdater::UpdateResult PresetUpdater::config_update(const Semver &old_slic3 const auto max_slic3r = incompat.version.max_slic3r_version; wxString restrictions; if (min_slic3r != Semver::zero() && max_slic3r != Semver::inf()) { - restrictions = GUI::from_u8((boost::format(_utf8(L("requires min. %s and max. %s"))) - % min_slic3r.to_string() - % max_slic3r.to_string()).str() - ); + restrictions = GUI::format_wxstr(_L("requires min. %s and max. %s"), + min_slic3r.to_string(), + max_slic3r.to_string()); } else if (min_slic3r != Semver::zero()) { - restrictions = GUI::from_u8((boost::format(_utf8(L("requires min. %s"))) % min_slic3r.to_string()).str()); + restrictions = GUI::format_wxstr(_L("requires min. %s"), min_slic3r.to_string()); BOOST_LOG_TRIVIAL(debug) << "Bundle is not downgrade, user will now have to do whole wizard. This should not happen."; } else { - restrictions = GUI::from_u8((boost::format(_utf8(L("requires max. %s"))) % max_slic3r.to_string()).str()); + restrictions = GUI::format_wxstr(_L("requires max. %s"), max_slic3r.to_string()); } incompats_map.emplace(std::make_pair(incompat.vendor, std::move(restrictions))); @@ -742,13 +741,13 @@ PresetUpdater::UpdateResult PresetUpdater::config_update(const Semver &old_slic3 for (const auto& update : updates.updates) { incompatible_version = (update.forced_update ? true : incompatible_version); //td::cout << update.forced_update << std::endl; - //BOOST_LOG_TRIVIAL(info) << boost::format("Update requires higher version."); + //BOOST_LOG_TRIVIAL(info) << format("Update requires higher version."); } //forced update if(incompatible_version) { - BOOST_LOG_TRIVIAL(info) << boost::format("Update of %1% bundles available. At least one requires higher version of Slicer.") % updates.updates.size(); + BOOST_LOG_TRIVIAL(info) << format("Update of %1% bundles available. At least one requires higher version of Slicer.", updates.updates.size()); std::vector updates_msg; for (const auto& update : updates.updates) { @@ -778,7 +777,7 @@ PresetUpdater::UpdateResult PresetUpdater::config_update(const Semver &old_slic3 } // regular update - BOOST_LOG_TRIVIAL(info) << boost::format("Update of %1% bundles available. Asking for confirmation ...") % updates.updates.size(); + BOOST_LOG_TRIVIAL(info) << format("Update of %1% bundles available. Asking for confirmation ...", updates.updates.size()); std::vector updates_msg; for (const auto &update : updates.updates) { @@ -813,7 +812,7 @@ void PresetUpdater::install_bundles_rsrc(std::vector bundles, bool { Updates updates; - BOOST_LOG_TRIVIAL(info) << boost::format("Installing %1% bundles from resources ...") % bundles.size(); + BOOST_LOG_TRIVIAL(info) << format("Installing %1% bundles from resources ...", bundles.size()); for (const auto &bundle : bundles) { auto path_in_rsrc = (p->rsrc_path / bundle).replace_extension(".ini"); diff --git a/src/slic3r/pchheader.hpp b/src/slic3r/pchheader.hpp index 3b321d960..a33b8a3a6 100644 --- a/src/slic3r/pchheader.hpp +++ b/src/slic3r/pchheader.hpp @@ -183,3 +183,5 @@ #include "libslic3r/BoundingBox.hpp" #include "libslic3r/ClipperUtils.hpp" #include "libslic3r/libslic3r.h" + +#include "GUI/format.hpp" From 1f3046f65d4f14ad56f571b982d15d1e271128a5 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 1 Apr 2020 09:58:31 +0200 Subject: [PATCH 11/20] #3964 - Attempt to fix crash when closing on Linux (Debian unstable) --- src/libslic3r/Technologies.hpp | 10 +++------- src/slic3r/GUI/MainFrame.cpp | 4 ++++ src/slic3r/GUI/Plater.cpp | 15 +++++++++++++++ src/slic3r/GUI/Plater.hpp | 1 + 4 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index c66cca8ea..8deed7502 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -44,19 +44,15 @@ // Enable fix for dragging mouse event handling for gizmobar #define ENABLE_GIZMO_TOOLBAR_DRAGGING_FIX (1 && ENABLE_2_2_0_FINAL) -//============ -// 2.3.0 techs -//============ -#define ENABLE_2_3_0 1 - -// Enable rendering of objects colored by facets' slope -#define ENABLE_SLOPE_RENDERING (1 && ENABLE_2_3_0) //=================== // 2.3.0.alpha1 techs //=================== #define ENABLE_2_3_0_ALPHA1 1 +// Enable rendering of objects colored by facets' slope +#define ENABLE_SLOPE_RENDERING (1 && ENABLE_2_3_0_ALPHA1) + // Moves GLCanvas3DManager from being a static member of _3DScene to be a normal member of GUI_App #define ENABLE_NON_STATIC_CANVAS_MANAGER (1 && ENABLE_2_3_0_ALPHA1) diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 437af6d53..6a1964506 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -214,6 +214,10 @@ void MainFrame::shutdown() // when closing the application using Command+Q, a mouse event is triggered after this lambda is completed, // causing a crash if (m_plater) m_plater->unbind_canvas_event_handlers(); + + // Cleanup of canvases' volumes needs to be done here or a crash may happen on some Linux Debian flavours + // see: https://github.com/prusa3d/PrusaSlicer/issues/3964 + if (m_plater) m_plater->reset_canvas_volumes(); #endif // ENABLE_NON_STATIC_CANVAS_MANAGER // Weird things happen as the Paint messages are floating around the windows being destructed. diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 880aa8223..34fa9e1ee 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1834,6 +1834,7 @@ struct Plater::priv GLCanvas3D* get_current_canvas3D(); #if ENABLE_NON_STATIC_CANVAS_MANAGER void unbind_canvas_event_handlers(); + void reset_canvas_volumes(); #endif // ENABLE_NON_STATIC_CANVAS_MANAGER bool init_view_toolbar(); @@ -4084,6 +4085,15 @@ void Plater::priv::unbind_canvas_event_handlers() if (preview != nullptr) preview->get_canvas3d()->unbind_event_handlers(); } + +void Plater::priv::reset_canvas_volumes() +{ + if (view3D != nullptr) + view3D->get_canvas3d()->reset_volumes(); + + if (preview != nullptr) + preview->get_canvas3d()->reset_volumes(); +} #endif // ENABLE_NON_STATIC_CANVAS_MANAGER bool Plater::priv::init_view_toolbar() @@ -5500,6 +5510,11 @@ void Plater::unbind_canvas_event_handlers() { p->unbind_canvas_event_handlers(); } + +void Plater::reset_canvas_volumes() +{ + p->reset_canvas_volumes(); +} #endif // ENABLE_NON_STATIC_CANVAS_MANAGER PrinterTechnology Plater::printer_technology() const diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index a1ce52389..efdaa75cc 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -262,6 +262,7 @@ public: void set_current_canvas_as_dirty(); #if ENABLE_NON_STATIC_CANVAS_MANAGER void unbind_canvas_event_handlers(); + void reset_canvas_volumes(); #endif // ENABLE_NON_STATIC_CANVAS_MANAGER PrinterTechnology printer_technology() const; From 22c671e5939309e9fc6009cbfb816ebf579944e3 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Wed, 1 Apr 2020 10:08:03 +0200 Subject: [PATCH 12/20] Fixing OSX and Linux builds --- src/slic3r/GUI/Plater.cpp | 1 + src/slic3r/pchheader.hpp | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index ebc8a7933..bd8f8130f 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -94,6 +94,7 @@ namespace fs = boost::filesystem; using Slic3r::_3DScene; using Slic3r::Preset; using Slic3r::PrintHostJob; +using Slic3r::GUI::format_wxstr; static const std::pair THUMBNAIL_SIZE_3MF = { 256, 256 }; diff --git a/src/slic3r/pchheader.hpp b/src/slic3r/pchheader.hpp index a33b8a3a6..ebdabe836 100644 --- a/src/slic3r/pchheader.hpp +++ b/src/slic3r/pchheader.hpp @@ -184,4 +184,6 @@ #include "libslic3r/ClipperUtils.hpp" #include "libslic3r/libslic3r.h" +#ifdef _WIN32 #include "GUI/format.hpp" +#endif // _WIN32 From 3a1bb2fecec2f68bcb504578c5a6aaca38157574 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Wed, 1 Apr 2020 10:30:33 +0200 Subject: [PATCH 13/20] fixed missing include --- src/slic3r/GUI/Plater.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index bd8f8130f..5a9e8a22f 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -59,6 +59,7 @@ #include "GUI_Utils.hpp" #include "wxExtensions.hpp" #include "MainFrame.hpp" +#include "format.hpp" #include "3DScene.hpp" #include "GLCanvas3D.hpp" #include "Selection.hpp" From 8027fc2fb2b242bd6082df12e34e1e1406aadd93 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Wed, 1 Apr 2020 10:42:10 +0200 Subject: [PATCH 14/20] Yet another missing include that windows compiler did not mind. --- src/slic3r/Utils/PresetUpdater.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/slic3r/Utils/PresetUpdater.cpp b/src/slic3r/Utils/PresetUpdater.cpp index 7c6c86384..b86775c88 100644 --- a/src/slic3r/Utils/PresetUpdater.cpp +++ b/src/slic3r/Utils/PresetUpdater.cpp @@ -25,6 +25,7 @@ #include "slic3r/GUI/UpdateDialogs.hpp" #include "slic3r/GUI/ConfigWizard.hpp" #include "slic3r/GUI/GUI_App.hpp" +#include "slic3r/GUI/format.hpp" #include "slic3r/Utils/Http.hpp" #include "slic3r/Config/Version.hpp" #include "slic3r/Config/Snapshot.hpp" From 4945a0dc0e76e5bfe42f5e59bbcb5e9aced0c66f Mon Sep 17 00:00:00 2001 From: tamasmeszaros Date: Wed, 1 Apr 2020 12:34:50 +0200 Subject: [PATCH 15/20] Follow-up fix for big bed arrangement --- src/slic3r/GUI/Plater.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 5a9e8a22f..c7c5798ce 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1594,9 +1594,9 @@ struct Plater::priv } // Stride between logical beds - coord_t bed_stride() const { + double bed_stride() const { double bedwidth = plater().bed_shape_bb().size().x(); - return scaled((1. + LOGICAL_BED_GAP) * bedwidth); + return scaled((1. + LOGICAL_BED_GAP) * bedwidth); } // Set up arrange polygon for a ModelInstance and Wipe tower From f4cc0ce075ffb3719467ab0b60fc299d9e5aa733 Mon Sep 17 00:00:00 2001 From: bubnikv Date: Wed, 1 Apr 2020 13:27:00 +0200 Subject: [PATCH 16/20] Fixed the new Slic3r::GUI::format_wxstr(): The arguments were not passed. --- src/slic3r/GUI/format.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/format.hpp b/src/slic3r/GUI/format.hpp index 1bc4b93d2..5cb3aed4c 100644 --- a/src/slic3r/GUI/format.hpp +++ b/src/slic3r/GUI/format.hpp @@ -25,11 +25,11 @@ inline wxString format_wxstr(const std::string& fmt, TArgs&&... args) { } template inline wxString format_wxstr(const wxString& fmt, TArgs&&... args) { - return format_wxstr(fmt.ToUTF8().data()); + return format_wxstr(fmt.ToUTF8().data(), std::forward(args)...); } template inline std::string format(const wxString& fmt, TArgs&&... args) { - return format(fmt.ToUTF8().data()); + return format(fmt.ToUTF8().data(), std::forward(args)...); } } // namespace GUI From 31b0ae164da86f1373aacc030092498c6072d3db Mon Sep 17 00:00:00 2001 From: bubnikv Date: Wed, 1 Apr 2020 13:42:26 +0200 Subject: [PATCH 17/20] Optimization of the GCodeTimeEstimator to only keep a fixed number of trapeziodal blocks around. The number is hard coded to 64, and 3x64 blocks are flushed everytime the queue grows over 4x64 blocks. This time estimator is slightly more close to what the firmware does, which keeps a fixed number of blocks and it recalculates all the blocks every time a new block is added while the oldest block is pushed out of the queue. Therefore this optimization shall produce negligible differences to what the previous code produced. --- src/libslic3r/GCodeTimeEstimator.cpp | 135 ++++++++++++--------------- src/libslic3r/GCodeTimeEstimator.hpp | 42 ++++----- 2 files changed, 78 insertions(+), 99 deletions(-) diff --git a/src/libslic3r/GCodeTimeEstimator.cpp b/src/libslic3r/GCodeTimeEstimator.cpp index 44b6a3d24..97d6ab3ff 100644 --- a/src/libslic3r/GCodeTimeEstimator.cpp +++ b/src/libslic3r/GCodeTimeEstimator.cpp @@ -207,11 +207,8 @@ namespace Slic3r { { PROFILE_FUNC(); if (start_from_beginning) - { _reset_time(); - m_last_st_synchronized_block_id = -1; - } - _calculate_time(); + _calculate_time(0); if (m_needs_custom_gcode_times && (m_custom_gcode_time_cache != 0.0f)) m_custom_gcode_times.push_back({ cgtColorChange, m_custom_gcode_time_cache }); @@ -221,6 +218,7 @@ namespace Slic3r { #endif // ENABLE_MOVE_STATS } +#if 0 void GCodeTimeEstimator::calculate_time_from_text(const std::string& gcode) { reset(); @@ -229,7 +227,7 @@ namespace Slic3r { [this](GCodeReader &reader, const GCodeReader::GCodeLine &line) { this->_process_gcode_line(reader, line); }); - _calculate_time(); + _calculate_time(0); if (m_needs_custom_gcode_times && (m_custom_gcode_time_cache != 0.0f)) m_custom_gcode_times.push_back({ cgtColorChange, m_custom_gcode_time_cache }); @@ -244,7 +242,7 @@ namespace Slic3r { reset(); m_parser.parse_file(file, boost::bind(&GCodeTimeEstimator::_process_gcode_line, this, _1, _2)); - _calculate_time(); + _calculate_time(0); if (m_needs_custom_gcode_times && (m_custom_gcode_time_cache != 0.0f)) m_custom_gcode_times.push_back({ cgtColorChange, m_custom_gcode_time_cache }); @@ -262,7 +260,7 @@ namespace Slic3r { { this->_process_gcode_line(reader, line); }; for (const std::string& line : gcode_lines) m_parser.parse_line(line, action); - _calculate_time(); + _calculate_time(0); if (m_needs_custom_gcode_times && (m_custom_gcode_time_cache != 0.0f)) m_custom_gcode_times.push_back({ cgtColorChange, m_custom_gcode_time_cache}); @@ -271,6 +269,7 @@ namespace Slic3r { _log_moves_stats(); #endif // ENABLE_MOVE_STATS } +#endif bool GCodeTimeEstimator::post_process(const std::string& filename, float interval_sec, const PostProcessData* const normal_mode, const PostProcessData* const silent_mode) { @@ -317,25 +316,25 @@ namespace Slic3r { if (data == nullptr) return; - assert((g1_line_id >= (int)data->g1_line_ids.size()) || (data->g1_line_ids[g1_line_id].first >= g1_lines_count)); - const Block* block = nullptr; - if (g1_line_id < (int)data->g1_line_ids.size()) + assert((g1_line_id >= (int)data->g1_times.size()) || (data->g1_times[g1_line_id].first >= (int)g1_lines_count)); + float elapsed_time = -1.0f; + if (g1_line_id < (int)data->g1_times.size()) { - const G1LineIdToBlockId& map_item = data->g1_line_ids[g1_line_id]; + const G1LineIdTime& map_item = data->g1_times[g1_line_id]; if (map_item.first == g1_lines_count) { - if (line.has_e() && (map_item.second < (unsigned int)data->blocks.size())) - block = &data->blocks[map_item.second]; + if (line.has_e()) + elapsed_time = map_item.second; ++g1_line_id; } } - if ((block != nullptr) && (block->elapsed_time != -1.0f)) + if (elapsed_time != -1.0f) { - float block_remaining_time = data->time - block->elapsed_time; + float block_remaining_time = data->time - elapsed_time; if (std::abs(last_recorded_time - block_remaining_time) > interval_sec) { - sprintf(line_M73, time_mask.c_str(), std::to_string((int)(100.0f * block->elapsed_time / data->time)).c_str(), _get_time_minutes(block_remaining_time).c_str()); + sprintf(line_M73, time_mask.c_str(), std::to_string((int)(100.0f * elapsed_time / data->time)).c_str(), _get_time_minutes(block_remaining_time).c_str()); gcode_line += line_M73; last_recorded_time = block_remaining_time; @@ -643,22 +642,6 @@ namespace Slic3r { m_state.extruder_id = m_state.extruder_id_unloaded; } - void GCodeTimeEstimator::add_additional_time(float timeSec) - { - PROFILE_FUNC(); - m_state.additional_time += timeSec; - } - - void GCodeTimeEstimator::set_additional_time(float timeSec) - { - m_state.additional_time = timeSec; - } - - float GCodeTimeEstimator::get_additional_time() const - { - return m_state.additional_time; - } - void GCodeTimeEstimator::set_default() { set_units(Millimeters); @@ -788,7 +771,7 @@ namespace Slic3r { { size_t out = sizeof(*this); out += SLIC3R_STDVEC_MEMSIZE(this->m_blocks, Block); - out += SLIC3R_STDVEC_MEMSIZE(this->m_g1_line_ids, G1LineIdToBlockId); + out += SLIC3R_STDVEC_MEMSIZE(this->m_g1_times, G1LineIdTime); return out; } @@ -807,13 +790,9 @@ namespace Slic3r { if (get_e_local_positioning_type() == Absolute) set_axis_position(E, 0.0f); - set_additional_time(0.0f); - reset_extruder_id(); reset_g1_line_id(); - m_g1_line_ids.clear(); - - m_last_st_synchronized_block_id = -1; + m_g1_times.clear(); m_needs_custom_gcode_times = false; m_custom_gcode_times.clear(); @@ -830,17 +809,19 @@ namespace Slic3r { m_blocks.clear(); } - void GCodeTimeEstimator::_calculate_time() + void GCodeTimeEstimator::_calculate_time(size_t keep_last_n_blocks) { PROFILE_FUNC(); + + assert(keep_last_n_blocks <= m_blocks.size()); + _forward_pass(); _reverse_pass(); _recalculate_trapezoids(); - m_time += get_additional_time(); - m_custom_gcode_time_cache += get_additional_time(); - - for (int i = m_last_st_synchronized_block_id + 1; i < (int)m_blocks.size(); ++i) + size_t n_blocks_process = m_blocks.size() - keep_last_n_blocks; + m_g1_times.reserve(m_g1_times.size() + n_blocks_process); + for (size_t i = 0; i < n_blocks_process; ++ i) { Block& block = m_blocks[i]; float block_time = 0.0f; @@ -848,7 +829,8 @@ namespace Slic3r { block_time += block.cruise_time(); block_time += block.deceleration_time(); m_time += block_time; - block.elapsed_time = m_time; + if (block.g1_line_id >= 0) + m_g1_times.emplace_back(block.g1_line_id, m_time); #if ENABLE_MOVE_STATS MovesStatsMap::iterator it = _moves_stats.find(block.move_type); @@ -862,9 +844,10 @@ namespace Slic3r { m_custom_gcode_time_cache += block_time; } - m_last_st_synchronized_block_id = (int)m_blocks.size() - 1; - // The additional time has been consumed (added to the total time), reset it to zero. - set_additional_time(0.); + if (keep_last_n_blocks) + m_blocks.erase(m_blocks.begin(), m_blocks.begin() + n_blocks_process); + else + m_blocks.clear(); } void GCodeTimeEstimator::_process_gcode_line(GCodeReader&, const GCodeReader::GCodeLine& line) @@ -1208,8 +1191,11 @@ namespace Slic3r { #endif // ENABLE_MOVE_STATS // adds block to blocks list + block.g1_line_id = this->get_g1_line_id(); m_blocks.emplace_back(block); - m_g1_line_ids.emplace_back(G1LineIdToBlockIdMap::value_type(get_g1_line_id(), (unsigned int)m_blocks.size() - 1)); + + if (m_blocks.size() > planner_refresh_if_larger) + _calculate_time(planner_queue_size); } void GCodeTimeEstimator::_processG4(const GCodeReader::GCodeLine& line) @@ -1218,8 +1204,9 @@ namespace Slic3r { GCodeFlavor dialect = get_dialect(); float value; + float extra_time = 0.f; if (line.has_value('P', value)) - add_additional_time(value * MILLISEC_TO_SEC); + extra_time += value * MILLISEC_TO_SEC; // see: http://reprap.org/wiki/G-code#G4:_Dwell if ((dialect == gcfRepetier) || @@ -1228,10 +1215,10 @@ namespace Slic3r { (dialect == gcfRepRap)) { if (line.has_value('S', value)) - add_additional_time(value); + extra_time += value; } - _simulate_st_synchronize(); + _simulate_st_synchronize(extra_time); } void GCodeTimeEstimator::_processG20(const GCodeReader::GCodeLine& line) @@ -1296,7 +1283,7 @@ namespace Slic3r { anyFound = true; } else - _simulate_st_synchronize(); + _simulate_st_synchronize(0.f); if (!anyFound) { @@ -1310,7 +1297,7 @@ namespace Slic3r { void GCodeTimeEstimator::_processM1(const GCodeReader::GCodeLine& line) { PROFILE_FUNC(); - _simulate_st_synchronize(); + _simulate_st_synchronize(0.f); } void GCodeTimeEstimator::_processM82(const GCodeReader::GCodeLine& line) @@ -1462,9 +1449,9 @@ namespace Slic3r { // MK3 MMU2 specific M code: // M702 C is expected to be sent by the custom end G-code when finalizing a print. // The MK3 unit shall unload and park the active filament into the MMU2 unit. - add_additional_time(get_filament_unload_time(get_extruder_id())); + float extra_time = get_filament_unload_time(get_extruder_id()); reset_extruder_id(); - _simulate_st_synchronize(); + _simulate_st_synchronize(extra_time); } } @@ -1478,10 +1465,10 @@ namespace Slic3r { { // Specific to the MK3 MMU2: The initial extruder ID is set to -1 indicating // that the filament is parked in the MMU2 unit and there is nothing to be unloaded yet. - add_additional_time(get_filament_unload_time(get_extruder_id())); + float extra_time = get_filament_unload_time(get_extruder_id()); set_extruder_id(id); - add_additional_time(get_filament_load_time(get_extruder_id())); - _simulate_st_synchronize(); + extra_time += get_filament_load_time(get_extruder_id()); + _simulate_st_synchronize(extra_time); } } } @@ -1513,7 +1500,9 @@ namespace Slic3r { { PROFILE_FUNC(); m_needs_custom_gcode_times = true; - _calculate_time(); + //FIXME this simulates st_synchronize! is it correct? + // The estimated time may be longer than the real print time. + _simulate_st_synchronize(0.f); if (m_custom_gcode_time_cache != 0.0f) { m_custom_gcode_times.push_back({code, m_custom_gcode_time_cache}); @@ -1521,34 +1510,26 @@ namespace Slic3r { } } - void GCodeTimeEstimator::_simulate_st_synchronize() + void GCodeTimeEstimator::_simulate_st_synchronize(float extra_time) { PROFILE_FUNC(); - _calculate_time(); + m_time += extra_time; + m_custom_gcode_time_cache += extra_time; + _calculate_time(0); } void GCodeTimeEstimator::_forward_pass() { PROFILE_FUNC(); - if (m_blocks.size() > 1) - { - for (int i = m_last_st_synchronized_block_id + 1; i < (int)m_blocks.size() - 1; ++i) - { - _planner_forward_pass_kernel(m_blocks[i], m_blocks[i + 1]); - } - } + for (int i = 0; i + 1 < (int)m_blocks.size(); ++i) + _planner_forward_pass_kernel(m_blocks[i], m_blocks[i + 1]); } void GCodeTimeEstimator::_reverse_pass() { PROFILE_FUNC(); - if (m_blocks.size() > 1) - { - for (int i = (int)m_blocks.size() - 1; i >= m_last_st_synchronized_block_id + 2; --i) - { - _planner_reverse_pass_kernel(m_blocks[i - 1], m_blocks[i]); - } - } + for (int i = (int)m_blocks.size() - 1; i > 0; -- i) + _planner_reverse_pass_kernel(m_blocks[i - 1], m_blocks[i]); } void GCodeTimeEstimator::_planner_forward_pass_kernel(Block& prev, Block& curr) @@ -1598,7 +1579,7 @@ namespace Slic3r { Block* curr = nullptr; Block* next = nullptr; - for (int i = m_last_st_synchronized_block_id + 1; i < (int)m_blocks.size(); ++i) + for (size_t i = 0; i < m_blocks.size(); ++ i) { Block& b = m_blocks[i]; @@ -1657,7 +1638,7 @@ namespace Slic3r { { char buffer[64]; - int minutes = std::round(time_in_secs / 60.); + int minutes = int(std::round(time_in_secs / 60.)); if (minutes <= 0) { ::sprintf(buffer, "%ds", (int)time_in_secs); } else { diff --git a/src/libslic3r/GCodeTimeEstimator.hpp b/src/libslic3r/GCodeTimeEstimator.hpp index 7c364d9eb..0448fdcbe 100644 --- a/src/libslic3r/GCodeTimeEstimator.hpp +++ b/src/libslic3r/GCodeTimeEstimator.hpp @@ -85,7 +85,6 @@ namespace Slic3r { // 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 float minimum_travel_feedrate; // mm/s float extrude_factor_override_percentage; @@ -160,7 +159,9 @@ namespace Slic3r { FeedrateProfile feedrate; Trapezoid trapezoid; - float elapsed_time; + + // Ordnary index of this G1 line in the file. + int g1_line_id { -1 }; Block(); @@ -217,16 +218,13 @@ namespace Slic3r { #endif // ENABLE_MOVE_STATS public: - typedef std::pair G1LineIdToBlockId; - typedef std::vector G1LineIdToBlockIdMap; + typedef std::pair G1LineIdTime; + typedef std::vector G1LineIdsTimes; struct PostProcessData { - const G1LineIdToBlockIdMap& g1_line_ids; - const BlocksList& blocks; + const G1LineIdsTimes& g1_times; float time; - - PostProcessData(const G1LineIdToBlockIdMap& g1_line_ids, const BlocksList& blocks, float time) : g1_line_ids(g1_line_ids), blocks(blocks), time(time) {} }; private: @@ -236,10 +234,14 @@ namespace Slic3r { Feedrates m_curr; Feedrates m_prev; BlocksList m_blocks; - // Map between g1 line id and blocks id, used to speed up export of remaining times - G1LineIdToBlockIdMap m_g1_line_ids; - // Index of the last block already st_synchronized - int m_last_st_synchronized_block_id; + // Size of the firmware planner queue. The old 8-bit Marlins usually just managed 16 trapezoidal blocks. + // Let's be conservative and plan for newer boards with more memory. + static constexpr size_t planner_queue_size = 64; + // The firmware recalculates last planner_queue_size trapezoidal blocks each time a new block is added. + // We are not simulating the firmware exactly, we calculate a sequence of blocks once a reasonable number of blocks accumulate. + static constexpr size_t planner_refresh_if_larger = planner_queue_size * 4; + // Map from g1 line id to its elapsed time from the start of the print. + G1LineIdsTimes m_g1_times; float m_time; // s // data to calculate custom code times @@ -267,13 +269,13 @@ namespace Slic3r { void calculate_time(bool start_from_beginning); // Calculates the time estimate from the given gcode in string format - void calculate_time_from_text(const std::string& gcode); + //void calculate_time_from_text(const std::string& gcode); // Calculates the time estimate from the gcode contained in the file with the given filename - void calculate_time_from_file(const std::string& file); + //void calculate_time_from_file(const std::string& file); // Calculates the time estimate from the gcode contained in given list of gcode lines - void calculate_time_from_lines(const std::vector& gcode_lines); + //void calculate_time_from_lines(const std::vector& gcode_lines); // Process the gcode contained in the file with the given filename, // replacing placeholders with correspondent new lines M73 @@ -350,10 +352,6 @@ namespace Slic3r { unsigned int get_extruder_id() const; void reset_extruder_id(); - void add_additional_time(float timeSec); - void set_additional_time(float timeSec); - float get_additional_time() const; - void set_default(); // Call this method before to start adding lines using add_gcode_line() when reusing an instance of GCodeTimeEstimator @@ -389,7 +387,7 @@ namespace Slic3r { // Return an estimate of the memory consumed by the time estimator. size_t memory_used() const; - PostProcessData get_post_process_data() const { return PostProcessData(m_g1_line_ids, m_blocks, m_time); } + PostProcessData get_post_process_data() const { return PostProcessData{ m_g1_times, m_time }; } private: void _reset(); @@ -397,7 +395,7 @@ namespace Slic3r { void _reset_blocks(); // Calculates the time estimate - void _calculate_time(); + void _calculate_time(size_t keep_last_n_blocks); // Processes the given gcode line void _process_gcode_line(GCodeReader&, const GCodeReader::GCodeLine& line); @@ -470,7 +468,7 @@ namespace Slic3r { void _process_custom_gcode_tag(CustomGcodeType code); // Simulates firmware st_synchronize() call - void _simulate_st_synchronize(); + void _simulate_st_synchronize(float additional_time); void _forward_pass(); void _reverse_pass(); From cfb6ac76fc643bc95911580b69929f6b9c27f60b Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 1 Apr 2020 15:54:25 +0200 Subject: [PATCH 18/20] Fixed build on AppleClang --- src/libslic3r/GCodeTimeEstimator.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/GCodeTimeEstimator.cpp b/src/libslic3r/GCodeTimeEstimator.cpp index bc077e9f0..833421d14 100644 --- a/src/libslic3r/GCodeTimeEstimator.cpp +++ b/src/libslic3r/GCodeTimeEstimator.cpp @@ -982,12 +982,12 @@ namespace Slic3r { }; auto move_length = [](const std::array& delta_pos) { - float xyz_length = std::sqrt(sqr(delta_pos[X]) + sqr(delta_pos[Y]) + sqr(delta_pos[Z])); - return (xyz_length > 0.0f) ? xyz_length : std::abs(delta_pos[E]); + float xyz_length = std::sqrt(sqr(delta_pos[(size_t)X]) + sqr(delta_pos[(size_t)Y]) + sqr(delta_pos[(size_t)Z])); + return (xyz_length > 0.0f) ? xyz_length : std::abs(delta_pos[(size_t)E]); }; auto is_extruder_only_move = [](const std::array& delta_pos) { - return (delta_pos[X] == 0.0f) && (delta_pos[Y] == 0.0f) && (delta_pos[Z] == 0.0f) && (delta_pos[E] != 0.0f); + return (delta_pos[(size_t)X] == 0.0f) && (delta_pos[(size_t)Y] == 0.0f) && (delta_pos[(size_t)Z] == 0.0f) && (delta_pos[(size_t)E] != 0.0f); }; PROFILE_FUNC(); From f27999e1360df10af470892e0876c8f9cda5b189 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 1 Apr 2020 16:47:35 +0200 Subject: [PATCH 19/20] Follow-up of cfb6ac76fc643bc95911580b69929f6b9c27f60b - Another attempt to fix the build on AppleClang (std::array in lambdas) --- src/libslic3r/GCodeTimeEstimator.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/libslic3r/GCodeTimeEstimator.cpp b/src/libslic3r/GCodeTimeEstimator.cpp index 833421d14..51293ed17 100644 --- a/src/libslic3r/GCodeTimeEstimator.cpp +++ b/src/libslic3r/GCodeTimeEstimator.cpp @@ -981,13 +981,15 @@ namespace Slic3r { return current_absolute_position; }; - auto move_length = [](const std::array& delta_pos) { - float xyz_length = std::sqrt(sqr(delta_pos[(size_t)X]) + sqr(delta_pos[(size_t)Y]) + sqr(delta_pos[(size_t)Z])); - return (xyz_length > 0.0f) ? xyz_length : std::abs(delta_pos[(size_t)E]); + // delta_pos must have size >= 4 + auto move_length = [](const float* delta_pos) { + float xyz_length = std::sqrt(sqr(delta_pos[X]) + sqr(delta_pos[Y]) + sqr(delta_pos[Z])); + return (xyz_length > 0.0f) ? xyz_length : std::abs(delta_pos[E]); }; - auto is_extruder_only_move = [](const std::array& delta_pos) { - return (delta_pos[(size_t)X] == 0.0f) && (delta_pos[(size_t)Y] == 0.0f) && (delta_pos[(size_t)Z] == 0.0f) && (delta_pos[(size_t)E] != 0.0f); + // delta_pos must have size >= 4 + auto is_extruder_only_move = [](const float* delta_pos) { + return (delta_pos[X] == 0.0f) && (delta_pos[Y] == 0.0f) && (delta_pos[Z] == 0.0f) && (delta_pos[E] != 0.0f); }; PROFILE_FUNC(); @@ -1023,7 +1025,7 @@ namespace Slic3r { // calculates block feedrate m_curr.feedrate = std::max(get_feedrate(), (delta_pos[E] == 0.0f) ? get_minimum_travel_feedrate() : get_minimum_feedrate()); - block.distance = move_length(delta_pos); + block.distance = move_length(delta_pos.data()); float invDistance = 1.0f / block.distance; float min_feedrate_factor = 1.0f; @@ -1050,7 +1052,7 @@ namespace Slic3r { } // calculates block acceleration - float acceleration = is_extruder_only_move(delta_pos) ? get_retract_acceleration() : get_acceleration(); + float acceleration = is_extruder_only_move(delta_pos.data()) ? get_retract_acceleration() : get_acceleration(); for (unsigned char a = X; a < Num_Axis; ++a) { From 815989d488f4c3a3ccbc552509fa09c49dd359be Mon Sep 17 00:00:00 2001 From: YuSanka Date: Wed, 1 Apr 2020 19:01:00 +0200 Subject: [PATCH 20/20] The print bed is limited to 1.2m x 1.2m. (related to #2877) --- src/slic3r/GUI/BedShapeDialog.cpp | 4 ++++ src/slic3r/GUI/Field.cpp | 31 ++++++++++++++++++++++++++++--- src/slic3r/GUI/Field.hpp | 1 + 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/BedShapeDialog.cpp b/src/slic3r/GUI/BedShapeDialog.cpp index 58c76fe26..4357a371a 100644 --- a/src/slic3r/GUI/BedShapeDialog.cpp +++ b/src/slic3r/GUI/BedShapeDialog.cpp @@ -74,6 +74,8 @@ void BedShapePanel::build_panel(const ConfigOptionPoints& default_pt, const Conf ConfigOptionDef def; def.type = coPoints; def.set_default_value(new ConfigOptionPoints{ Vec2d(200, 200) }); + def.min = 0; + def.max = 1200; def.label = L("Size"); def.tooltip = L("Size in X and Y of the rectangular plate."); Option option(def, "rect_size"); @@ -81,6 +83,8 @@ void BedShapePanel::build_panel(const ConfigOptionPoints& default_pt, const Conf def.type = coPoints; def.set_default_value(new ConfigOptionPoints{ Vec2d(0, 0) }); + def.min = -600; + def.max = 600; def.label = L("Origin"); def.tooltip = L("Distance of the 0,0 G-code coordinate from the front left corner of the rectangle."); option = Option(def, "rect_origin"); diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp index 6d9007974..a1a6583bc 100644 --- a/src/slic3r/GUI/Field.cpp +++ b/src/slic3r/GUI/Field.cpp @@ -1242,12 +1242,24 @@ void PointCtrl::msw_rescale(bool rescale_sidetext/* = false*/) y_textctrl->SetMinSize(field_size); } +bool PointCtrl::value_was_changed(wxTextCtrl* win) +{ + if (m_value.empty()) + return true; + + boost::any val = m_value; + // update m_value! + get_value(); + + return boost::any_cast(m_value) != boost::any_cast(val); +} + void PointCtrl::propagate_value(wxTextCtrl* win) { - if (!win->GetValue().empty()) - on_change_field(); - else + if (win->GetValue().empty()) on_kill_focus(); + else if (value_was_changed(win)) + on_change_field(); } void PointCtrl::set_value(const Vec2d& value, bool change_event) @@ -1281,6 +1293,19 @@ boost::any& PointCtrl::get_value() double x, y; x_textctrl->GetValue().ToDouble(&x); y_textctrl->GetValue().ToDouble(&y); + + if (m_opt.min > x || x > m_opt.max || + m_opt.min > y || y > m_opt.max) + { + if (m_opt.min > x) x = m_opt.min; + if (x > m_opt.max) x = m_opt.max; + if (m_opt.min > y) y = m_opt.min; + if (y > m_opt.max) y = m_opt.max; + set_value(Vec2d(x, y), true); + + show_error(m_parent, _(L("Input value is out of range"))); + } + return m_value = Vec2d(x, y); } diff --git a/src/slic3r/GUI/Field.hpp b/src/slic3r/GUI/Field.hpp index 1f8b642b1..5bdbfadc8 100644 --- a/src/slic3r/GUI/Field.hpp +++ b/src/slic3r/GUI/Field.hpp @@ -445,6 +445,7 @@ public: wxTextCtrl* y_textctrl{ nullptr }; void BUILD() override; + bool value_was_changed(wxTextCtrl* win); // Propagate value from field to the OptionGroupe and Config after kill_focus/ENTER void propagate_value(wxTextCtrl* win); void set_value(const Vec2d& value, bool change_event = false);