OrcaSlicer latest
OrcaSlicer
Loading...
Searching...
No Matches
Slic3r::GCodeProcessor Class Reference

#include </home/runner/work/OrcaSlicer/OrcaSlicer/src/libslic3r/GCode/GCodeProcessor.hpp>

Collaboration diagram for Slic3r::GCodeProcessor:

Classes

struct  CachedPosition
struct  CpColor
struct  FeedrateProfile
struct  Trapezoid
struct  TimeBlock
struct  TimeMachine
struct  UsedFilaments
struct  TimeProcessor
class  PreCoolingInjector
class  SeamsDetector
class  OptionsZCorrector
struct  MassLocation
struct  PositionState

Public Types

enum class  ETags : unsigned char {
  Role , Wipe_Start , Wipe_End , Height ,
  Width , Layer_Change , Color_Change , Pause_Print ,
  Custom_Code , First_Line_M73_Placeholder , Last_Line_M73_Placeholder , Estimated_Printing_Time_Placeholder ,
  Total_Layer_Number_Placeholder , Manual_Tool_Change , During_Print_Exhaust_Fan , Wipe_Tower_Start ,
  Wipe_Tower_End , PA_Change , Print_Time_Total_Sec_Placeholder , Print_Time_Day_Placeholder ,
  Print_Time_Hour_Placeholder , Print_Time_Minute_Placeholder , Print_Time_Sec_Placeholder , Used_Filament_Length_Placeholder ,
  Normal_Print_Time_Placeholder , Silent_Print_Time_Placeholder , Total_Weight_Placeholder , Total_Cost_Placeholder ,
  Total_Wipe_Tower_Cost_Placeholder , Total_Wipe_Tower_Filament_Placeholder
}
using MassLocator = std::function<MassLocation(const Vec3d &point, bool support)>

Public Member Functions

 GCodeProcessor ()
void init_filament_maps_and_nozzle_type_when_import_only_gcode ()
void ensure_nozzle_group_result (int min_filament_count)
bool check_multi_extruder_gcode_valid (const int extruder_size, const Pointfs plate_printable_area, const double plate_printable_height, const Pointfs wrapping_exclude_area, const std::vector< Polygons > &unprintable_areas, const std::vector< double > &printable_heights, const std::vector< int > &filament_map, const std::vector< std::set< int > > &unprintable_filament_types)
void apply_config (const PrintConfig &config)
void configure_exclusion_volume_path_check (const PrintConfig &config)
void set_print (Print *print)
void set_mass_locator (MassLocator locator, std::vector< GCodeProcessorResult::ObjectMass > objects)
void initialize_from_context (const std::shared_ptr< MultiNozzleUtils::NozzleGroupResultBase > &nozzle_group_result)
DynamicConfig export_config_for_render () const
bool is_stealth_time_estimator_enabled () const
void enable_machine_envelope_processing (bool enabled)
void reset ()
const GCodeProcessorResult & get_result () const
GCodeProcessorResult & result ()
GCodeProcessorResult && extract_result ()
PositionState get_current_position () const
void process_file (const std::string &filename, std::function< void()> cancel_callback=nullptr)
void initialize (const std::string &filename)
void initialize_result_moves ()
void process_buffer (const std::string &buffer)
void finalize (bool post_process)
double get_time (PrintEstimatedStatistics::ETimeMode mode) const
float get_prepare_time (PrintEstimatedStatistics::ETimeMode mode) const
std::string get_time_dhm (PrintEstimatedStatistics::ETimeMode mode) const
std::vector< std::pair< CustomGCode::Type, std::pair< float, float > > > get_custom_gcode_times (PrintEstimatedStatistics::ETimeMode mode, bool include_remaining) const
float get_first_layer_time (PrintEstimatedStatistics::ETimeMode mode) const
void set_xy_offset (double x, double y)
void detect_layer_based_on_tag (bool enabled)

Static Public Member Functions

static const std::string & reserved_tag (ETags tag)
static bool contains_reserved_tag (const std::string &gcode, std::string &found_tag)
static bool contains_reserved_tags (const std::string &gcode, unsigned int max_count, std::vector< std::string > &found_tag, bool is_bbl_printer)
static int get_gcode_last_filament (const std::string &gcode_str)
static bool get_last_z_from_gcode (const std::string &gcode_str, double &z)
static bool get_last_position_from_gcode (const std::string &gcode_str, Vec3f &pos)

Static Public Attributes

static constexpr size_t Output_Block_Size = 65536
static const std::string Skippable_Start_Tag = " SKIPPABLE_START"
static const std::string Skippable_End_Tag = " SKIPPABLE_END"
static const std::string Skippable_Type_Tag = " SKIPTYPE: "
static const std::string Machine_Start_GCode_End_Tag = " MACHINE_START_GCODE_END"
static const std::string Machine_End_GCode_Start_Tag = " MACHINE_END_GCODE_START"
static const std::string Nozzle_Change_Start_Tag = " NOZZLE_CHANGE_START"
static const std::string Nozzle_Change_End_Tag = " NOZZLE_CHANGE_END"
static const std::string Toolchange_Wipe_Tag = " CP_TOOLCHANGE_WIPE"
static const float Wipe_Width = 0.05f
static const float Wipe_Height = 0.05f
static bool s_IsBBLPrinter = true

Private Types

enum class  EUnits : unsigned char { Millimeters , Inches }
enum class  EPositioningType : unsigned char { Absolute , Relative }
enum class  EProducer {
  Unknown , OrcaSlicer , Slic3rPE , Slic3r ,
  SuperSlicer , Cura , Simplify3D , CraftWare ,
  ideaMaker , KissSlicer
}
enum class  G1DiscretizationOrigin { G1 , G2G3 }
using AxisCoords = std::array<double, 4>
using ExtruderColors = std::vector<unsigned char>
using ExtruderTemps = std::vector<float>

Private Member Functions

void register_commands ()
void apply_config (const DynamicPrintConfig &config)
void apply_config_simplify3d (const std::string &filename)
void apply_config_superslicer (const std::string &filename)
void process_gcode_line (const GCodeReader::GCodeLine &line, bool producers_enabled)
void process_tags (const std::string_view comment, bool producers_enabled)
bool process_producers_tags (const std::string_view comment)
bool process_bambuslicer_tags (const std::string_view comment)
bool process_cura_tags (const std::string_view comment)
bool process_simplify3d_tags (const std::string_view comment)
bool process_craftware_tags (const std::string_view comment)
bool process_ideamaker_tags (const std::string_view comment)
bool process_kissslicer_tags (const std::string_view comment)
bool detect_producer (const std::string_view comment)
void process_G0 (const GCodeReader::GCodeLine &line)
void process_G1 (const GCodeReader::GCodeLine &line, const std::optional< unsigned int > &remaining_internal_g1_lines=std::nullopt)
void process_G1 (const std::array< std::optional< double >, 4 > &axes={ std::nullopt, std::nullopt, std::nullopt, std::nullopt }, const std::optional< double > &feedrate=std::nullopt, G1DiscretizationOrigin origin=G1DiscretizationOrigin::G1, const std::optional< unsigned int > &remaining_internal_g1_lines=std::nullopt)
void update_position_known_from_move (const std::array< std::optional< double >, 4 > &axes, G1DiscretizationOrigin origin)
void update_position_known_from_move (const GCodeReader::GCodeLine &line)
void update_exclusion_volume_path_check_result ()
void process_G2_G3 (const GCodeReader::GCodeLine &line, bool clockwise)
void process_VG1 (const GCodeReader::GCodeLine &line)
void process_G4 (const GCodeReader::GCodeLine &line)
void process_G10 (const GCodeReader::GCodeLine &line)
void process_G11 (const GCodeReader::GCodeLine &line)
void process_G20 (const GCodeReader::GCodeLine &line)
void process_G21 (const GCodeReader::GCodeLine &line)
void process_G22 (const GCodeReader::GCodeLine &line)
void process_G23 (const GCodeReader::GCodeLine &line)
void process_G28 (const GCodeReader::GCodeLine &line)
void process_G29 (const GCodeReader::GCodeLine &line)
void process_G90 (const GCodeReader::GCodeLine &line)
void process_G91 (const GCodeReader::GCodeLine &line)
void process_G92 (const GCodeReader::GCodeLine &line)
void process_M1 (const GCodeReader::GCodeLine &line)
void process_M82 (const GCodeReader::GCodeLine &line)
void process_M83 (const GCodeReader::GCodeLine &line)
void process_M104 (const GCodeReader::GCodeLine &line)
void process_VM104 (const GCodeReader::GCodeLine &line)
void process_VM109 (const GCodeReader::GCodeLine &line)
void process_M106 (const GCodeReader::GCodeLine &line)
void process_M107 (const GCodeReader::GCodeLine &line)
void process_M900 (const GCodeReader::GCodeLine &line)
void process_M572 (const GCodeReader::GCodeLine &line)
void process_SET_PRESSURE_ADVANCE (const GCodeReader::GCodeLine &line)
void process_M108 (const GCodeReader::GCodeLine &line)
void process_M109 (const GCodeReader::GCodeLine &line)
void process_M132 (const GCodeReader::GCodeLine &line)
void process_M135 (const GCodeReader::GCodeLine &line)
void process_M140 (const GCodeReader::GCodeLine &line)
void process_M190 (const GCodeReader::GCodeLine &line)
void process_M191 (const GCodeReader::GCodeLine &line)
void process_M201 (const GCodeReader::GCodeLine &line)
void process_M203 (const GCodeReader::GCodeLine &line)
void process_M204 (const GCodeReader::GCodeLine &line)
void process_M205 (const GCodeReader::GCodeLine &line)
void process_SET_VELOCITY_LIMIT (const GCodeReader::GCodeLine &line)
void process_M221 (const GCodeReader::GCodeLine &line)
void process_M400 (const GCodeReader::GCodeLine &line)
void process_M401 (const GCodeReader::GCodeLine &line)
void process_M402 (const GCodeReader::GCodeLine &line)
void process_M566 (const GCodeReader::GCodeLine &line)
void process_M702 (const GCodeReader::GCodeLine &line)
void process_M6211 (const GCodeReader::GCodeLine &line)
void process_elegoo_M6211 (const GCodeReader::GCodeLine &line)
void process_SYNC (const GCodeReader::GCodeLine &line)
void process_T (const GCodeReader::GCodeLine &line)
void process_T (const std::string_view command)
void process_T (const std::string_view command, int nozzle_id)
void process_M1020 (const GCodeReader::GCodeLine &line)
void process_M622 (const GCodeReader::GCodeLine &line)
void process_M623 (const GCodeReader::GCodeLine &line)
void process_filament_change (int id)
void process_filament_change (int id, int nozzle_id)
std::optional< MultiNozzleUtils::NozzleInfo > resolve_target_nozzle (const MultiNozzleUtils::NozzleGroupResultBase &group, int id, int nozzle_id) const
int get_machine_config_idx () const
bool use_multi_nozzle_change_time_model () const
void run_post_process ()
void run_second_pass_injection ()
void handle_offsets_of_second_process (const TimeProcessor::InsertedLinesMap &inserted_operation_lines)
void store_move_vertex (EMoveType type, EMovePathType path_type=EMovePathType::Noop_move, bool internal_only=false)
void add_object_mass (int filament_id, float volume)
void finalize_object_masses ()
void set_extrusion_role (ExtrusionRole role)
void set_skippable_type (const std::string_view type)
float minimum_feedrate (PrintEstimatedStatistics::ETimeMode mode, float feedrate) const
float minimum_travel_feedrate (PrintEstimatedStatistics::ETimeMode mode, float feedrate) const
float get_axis_max_feedrate (PrintEstimatedStatistics::ETimeMode mode, Axis axis) const
float get_axis_max_feedrate (PrintEstimatedStatistics::ETimeMode mode, Axis axis, int machine_idx) const
float get_axis_max_acceleration (PrintEstimatedStatistics::ETimeMode mode, Axis axis) const
float get_axis_max_acceleration (PrintEstimatedStatistics::ETimeMode mode, Axis axis, int machine_idx) const
float get_axis_max_jerk_with_jd (PrintEstimatedStatistics::ETimeMode mode, Axis axis, float acceleration) const
float get_axis_max_jerk_with_jd (PrintEstimatedStatistics::ETimeMode mode, Axis axis) const
float get_junction_deviation (PrintEstimatedStatistics::ETimeMode mode, float acceleration) const
float calc_junction_acceleration (const TimeBlock &block, const Vec4f &junction_unit_vec, PrintEstimatedStatistics::ETimeMode mode) const
float calc_vmax_junction_deviation (const TimeBlock &block, const TimeMachine::State &prev, const TimeMachine::State &curr, bool has_prev_move, PrintEstimatedStatistics::ETimeMode mode) const
float get_axis_max_jerk (PrintEstimatedStatistics::ETimeMode mode, Axis axis) const
Vec3f get_xyz_max_jerk (PrintEstimatedStatistics::ETimeMode mode) const
float get_retract_acceleration (PrintEstimatedStatistics::ETimeMode mode) const
void set_retract_acceleration (PrintEstimatedStatistics::ETimeMode mode, float value)
float get_acceleration (PrintEstimatedStatistics::ETimeMode mode) const
void set_acceleration (PrintEstimatedStatistics::ETimeMode mode, float value)
float get_travel_acceleration (PrintEstimatedStatistics::ETimeMode mode) const
void set_travel_acceleration (PrintEstimatedStatistics::ETimeMode mode, float value)
float get_filament_load_time (size_t extruder_id)
float get_filament_unload_time (size_t extruder_id)
float get_extruder_change_time (size_t extruder_id)
int get_filament_vitrification_temperature (size_t extrude_id)
void process_custom_gcode_time (CustomGCode::Type code)
void process_filaments (CustomGCode::Type code)
void calculate_time (GCodeProcessorResult &result, size_t keep_last_n_blocks=0, float additional_time=0.0f, EMoveType target_move_type=EMoveType::Noop, bool is_final=false)
void simulate_st_synchronize (float additional_time=0.0f, EMoveType target_move_type=EMoveType::Noop)
void update_estimated_times_stats ()
double extract_absolute_position_on_axis (Axis axis, const GCodeReader::GCodeLine &line, double area_filament_cross_section)
void update_slice_warnings ()
int get_filament_id (bool force_initialize=true) const
int get_last_filament_id (bool force_initialize=true) const
int get_extruder_id (bool force_initialize=true) const

Private Attributes

CommandProcessor m_command_processor
GCodeReader m_parser
DynamicConfig m_belt_render_config
EUnits m_units
EPositioningType m_global_positioning_type
EPositioningType m_e_local_positioning_type
std::vector< Vec3f > m_extruder_offsets
GCodeFlavor m_flavor
std::vector< float > m_nozzle_volume
AxisCoords m_start_position
AxisCoords m_end_position
AxisCoords m_origin
std::array< bool, 3 > m_axis_position_known { false, false, false }
std::array< bool, 3 > m_axis_origin_known { true, true, true }
bool m_processing_homing_move { false }
ExclusionVolumePathChecker m_exclusion_volume_path_checker
CachedPosition m_cached_position
bool m_wiping
bool m_flushing
bool m_virtual_flushing
bool m_wipe_tower
bool m_skippable {false}
SkipType m_skippable_type {SkipType::stNone}
int m_object_label_id {-1}
MassLocator m_mass_locator
float m_print_z {0.0f}
std::vector< float > m_remaining_volume
ExtruderTemps m_filament_nozzle_temp
ExtruderTemps m_filament_nozzle_temp_first_layer
std::vector< int > m_physical_extruder_map
std::vector< int > m_extruder_max_nozzle_count {1}
std::vector< std::string > m_filament_types
std::vector< double > m_nozzle_diameter
std::vector< double > m_hotend_cooling_rate { 2.f }
std::vector< double > m_hotend_heating_rate { 2.f }
std::vector< int > m_filament_pre_cooling_temp { 0 }
std::vector< double > m_filament_preheat_temperature_delta
bool m_enable_pre_heating { false }
bool m_handle_hotend_as_extruder { false }
bool m_has_filament_switcher { false }
std::vector< std::pair< unsigned int, unsigned int > > m_skippable_blocks
std::vector< ExtruderPreHeating::FilamentUsageBlock > m_filament_blocks
std::vector< ExtruderPreHeating::ExtruderUsageBlcok > m_extruder_blocks
unsigned int m_machine_start_gcode_end_line_id { (unsigned int) (-1) }
unsigned int m_machine_end_gcode_start_line_id { (unsigned int) (-1) }
bool m_skip_end_gcode_delays { false }
MultiNozzleUtils::NozzleStatusRecorder m_nozzle_status_recorder
std::shared_ptr< MultiNozzleUtils::NozzleGroupResultBase > m_nozzle_group_result
bool m_manual_filament_change { false }
double m_x_offset { 0 }
double m_y_offset { 0 }
MachineFrameTransform m_machine_frame_transform
bool m_belt_printer { false }
unsigned int m_line_id
unsigned int m_last_line_id
float m_feedrate
float m_width
float m_height
float m_forced_width
float m_forced_height
float m_mm3_per_mm
float m_travel_dist
float m_fan_speed
float m_z_offset
float m_pressure_advance
ExtrusionRole m_extrusion_role
std::vector< int > m_filament_maps
std::vector< unsigned char > m_last_filament_id
std::vector< unsigned char > m_filament_id
unsigned char m_extruder_id
int m_machine_config_idx {0}
ExtruderColors m_extruder_colors
ExtruderTemps m_extruder_temps
bool m_is_XL_printer = false
int m_highest_bed_temp
float m_extruded_last_z
float m_first_layer_height
float m_zero_layer_height
bool m_processing_start_custom_gcode
bool m_in_config_block
unsigned int m_g1_line_id
unsigned int m_layer_id
CpColor m_cp_color
SeamsDetector m_seams_detector
OptionsZCorrector m_options_z_corrector
size_t m_last_default_color_id
bool m_detect_layer_based_on_tag {false}
int m_seams_count
bool m_measure_g29_time {false}
bool m_g29_time_added {false}
bool m_single_extruder_multi_material
float m_preheat_time
int m_preheat_steps
bool m_disable_m73
std::string m_printer_model
EProducer m_producer
TimeProcessor m_time_processor
std::vector< std::pair< unsigned int, unsigned int > > m_actual_speed_id_map
UsedFilaments m_used_filaments
Print * m_print { nullptr }
GCodeProcessorResult m_result

Static Private Attributes

static const std::vector< std::string > Reserved_Tags
static const std::vector< std::string > Reserved_Tags_compatible
static const std::string Flush_Start_Tag = " FLUSH_START"
static const std::string Flush_End_Tag = " FLUSH_END"
static const std::string VFlush_Start_Tag = " VFLUSH_START"
static const std::string VFlush_End_Tag = " VFLUSH_END"
static const std::string External_Purge_Tag = " EXTERNAL_PURGE"
static const std::vector< std::pair< GCodeProcessor::EProducer, std::string > > Producers
static unsigned int s_result_id = 0

Friends

class ExportLines

Detailed Description


Class Documentation

◆ Slic3r::GCodeProcessor::FeedrateProfile

struct Slic3r::GCodeProcessor::FeedrateProfile
Class Members
float cruise { 0.0f }
float entry { 0.0f }
float exit { 0.0f }

◆ Slic3r::GCodeProcessor::MassLocation

struct Slic3r::GCodeProcessor::MassLocation
Class Members
int body { -1 }
int object { -1 }

Member Typedef Documentation

◆ AxisCoords

using Slic3r::GCodeProcessor::AxisCoords = std::array<double, 4>
private

◆ ExtruderColors

using Slic3r::GCodeProcessor::ExtruderColors = std::vector<unsigned char>
private

◆ ExtruderTemps

using Slic3r::GCodeProcessor::ExtruderTemps = std::vector<float>
private

◆ MassLocator

using Slic3r::GCodeProcessor::MassLocator = std::function<MassLocation(const Vec3d &point, bool support)>

Member Enumeration Documentation

◆ EPositioningType

enum class Slic3r::GCodeProcessor::EPositioningType : unsigned char
strongprivate
Enumerator
Absolute 
Relative 
664 {
665 Absolute,
666 Relative
667 };

◆ EProducer

enum class Slic3r::GCodeProcessor::EProducer
strongprivate
Enumerator
Unknown 
OrcaSlicer 
Slic3rPE 
Slic3r 
SuperSlicer 
Cura 
Simplify3D 
CraftWare 
ideaMaker 
KissSlicer 
1357 {
1358 Unknown,
1359 OrcaSlicer,
1360 Slic3rPE,
1361 Slic3r,
1362 SuperSlicer,
1363 Cura,
1364 Simplify3D,
1365 CraftWare,
1366 ideaMaker,
1367 KissSlicer
1368 };
@ Unknown
Definition PresetBundle.hpp:42

◆ ETags

enum class Slic3r::GCodeProcessor::ETags : unsigned char
strong
Enumerator
Role 
Wipe_Start 
Wipe_End 
Height 
Width 
Layer_Change 
Color_Change 
Pause_Print 
Custom_Code 
First_Line_M73_Placeholder 
Last_Line_M73_Placeholder 
Estimated_Printing_Time_Placeholder 
Total_Layer_Number_Placeholder 
Manual_Tool_Change 
During_Print_Exhaust_Fan 
Wipe_Tower_Start 
Wipe_Tower_End 
PA_Change 
Print_Time_Total_Sec_Placeholder 
Print_Time_Day_Placeholder 
Print_Time_Hour_Placeholder 
Print_Time_Minute_Placeholder 
Print_Time_Sec_Placeholder 
Used_Filament_Length_Placeholder 
Normal_Print_Time_Placeholder 
Silent_Print_Time_Placeholder 
Total_Weight_Placeholder 
Total_Cost_Placeholder 
Total_Wipe_Tower_Cost_Placeholder 
Total_Wipe_Tower_Filament_Placeholder 
603 {
604 Role,
605 Wipe_Start,
606 Wipe_End,
607 Height,
608 Width,
609 Layer_Change,
610 Color_Change,
612 Custom_Code,
613 First_Line_M73_Placeholder,
614 Last_Line_M73_Placeholder,
615 Estimated_Printing_Time_Placeholder,
616 Total_Layer_Number_Placeholder,
617 Manual_Tool_Change,
618 During_Print_Exhaust_Fan,
619 Wipe_Tower_Start,
620 Wipe_Tower_End,
621 PA_Change,
622 Print_Time_Total_Sec_Placeholder,
623 Print_Time_Day_Placeholder,
624 Print_Time_Hour_Placeholder,
625 Print_Time_Minute_Placeholder,
626 Print_Time_Sec_Placeholder,
627 Used_Filament_Length_Placeholder,
628 Normal_Print_Time_Placeholder,
629 Silent_Print_Time_Placeholder,
630 Total_Weight_Placeholder,
631 Total_Cost_Placeholder,
632 Total_Wipe_Tower_Cost_Placeholder,
633 Total_Wipe_Tower_Filament_Placeholder,
634 };
@ Pause_Print
Definition GCodeProcessor.hpp:60
SketchPointRole Role
Definition SketchSolver.cpp:20
@ Width
Definition Types.hpp:98
@ Height
Definition Types.hpp:97

◆ EUnits

enum class Slic3r::GCodeProcessor::EUnits : unsigned char
strongprivate
Enumerator
Millimeters 
Inches 
658 {
659 Millimeters,
660 Inches
661 };

◆ G1DiscretizationOrigin

Enumerator
G1 
G2G3 
1489 {
1490 G1,
1491 G2G3,
1492 };

Constructor & Destructor Documentation

◆ GCodeProcessor()

Slic3r::GCodeProcessor::GCodeProcessor ( )
2821{
2822 reset();
2823 m_time_processor.machines[static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Normal)].line_m73_main_mask = "M73 P%s R%s\n";
2824 m_time_processor.machines[static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Normal)].line_m73_stop_mask = "M73 C%s\n";
2825 m_time_processor.machines[static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Stealth)].line_m73_main_mask = "M73 Q%s S%s\n";
2826 m_time_processor.machines[static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Stealth)].line_m73_stop_mask = "M73 D%s\n";
2827
2829}
void register_commands()
Definition GCodeProcessor.cpp:2831
TimeProcessor m_time_processor
Definition GCodeProcessor.hpp:1373
void reset()
Definition GCodeProcessor.cpp:3702
GCodeProcessorResult m_result
Definition GCodeProcessor.hpp:1381
OptionsZCorrector m_options_z_corrector
Definition GCodeProcessor.hpp:1344
@ Stealth
Definition GCodeProcessor.hpp:90
@ Normal
Definition GCodeProcessor.hpp:89

References m_options_z_corrector, m_result, m_time_processor, Slic3r::PrintEstimatedStatistics::Normal, register_commands(), reset(), and Slic3r::PrintEstimatedStatistics::Stealth.

Here is the call graph for this function:

Member Function Documentation

◆ add_object_mass()

void Slic3r::GCodeProcessor::add_object_mass ( int filament_id,
float volume )
private
7608{
7609 // Skirt, prime tower and custom G-code belong to no object.
7610 const ExtrusionRole role = m_extrusion_role;
7611 if (volume <= 0.f || role == erNone || role == erSkirt || role == erWipeTower || role == erCustom || role == erMixed)
7612 return;
7613
7614 const bool has_density = size_t(filament_id) < m_result.filament_densities.size() && m_result.filament_densities[filament_id] > 0.f;
7615 const double mass = double(volume) * (has_density ? m_result.filament_densities[filament_id] : DEFAULT_FILAMENT_DENSITY);
7616 // In the frame of the stored moves, the bead's center half its height below the nozzle, from the move's start to its end.
7617 const Vec3d half_height = 0.5 * double(m_height) * Vec3d::UnitZ();
7618 const Vec3d offset = Vec3d(m_x_offset, m_y_offset, -m_z_offset) - half_height + m_extruder_offsets[filament_id].cast<double>();
7621 // The second moments of a uniform segment.
7622 const GCodeProcessorResult::ObjectMass::Sum sum{ mass, double(volume), 0.5 * mass * (start + end),
7623 mass / 3. * (start.cwiseProduct(start) + start.cwiseProduct(end) + end.cwiseProduct(end)) };
7624 // Of the bead's center line and its height, as its width is only estimated. Merged, as a wall along an axis is flat.
7625 BoundingBoxf3 extent;
7626 extent.merge(start.cwiseMin(end) - half_height);
7627 extent.merge(start.cwiseMax(end) + half_height);
7628 const bool part = role != erBrim && !is_support(role);
7629 const size_t layer = std::max<unsigned int>(1, m_layer_id) - 1;
7630
7631 m_result.plate_mass.add(sum, extent, layer);
7632 // The brim belongs to the plate alone.
7633 if (role == erBrim || !m_mass_locator)
7634 return;
7635 const auto add = [&sum, &extent, layer](std::vector<GCodeProcessorResult::ObjectMass> &masses, int index) {
7636 if (index < 0)
7637 return;
7638 if (masses.size() <= size_t(index))
7639 masses.resize(index + 1);
7640 masses[index].add(sum, extent, layer);
7641 };
7642 // At the nozzle's height, which the layers print at.
7643 const MassLocation location = m_mass_locator(0.5 * (start + end) + half_height, !part);
7644 if (part) {
7645 add(m_result.object_masses, location.object);
7646 add(m_result.body_masses, location.body);
7647 } else
7648 add(m_result.support_masses, location.object);
7649}
MassLocator m_mass_locator
Definition GCodeProcessor.hpp:1247
unsigned int m_layer_id
Definition GCodeProcessor.hpp:1341
float m_z_offset
Definition GCodeProcessor.hpp:1320
AxisCoords m_start_position
Definition GCodeProcessor.hpp:1229
ExtrusionRole m_extrusion_role
Definition GCodeProcessor.hpp:1323
std::vector< Vec3f > m_extruder_offsets
Definition GCodeProcessor.hpp:1226
double m_y_offset
Definition GCodeProcessor.hpp:1301
AxisCoords m_end_position
Definition GCodeProcessor.hpp:1230
double m_x_offset
Definition GCodeProcessor.hpp:1300
float m_height
Definition GCodeProcessor.hpp:1314
Definition GCodeProcessor.hpp:1209
T * end(Slic3r::Mat< N, M, T > &mat)
Definition Point.hpp:841
SpiralVase::SpiralPoint add(SpiralVase::SpiralPoint a, SpiralVase::SpiralPoint b)
Definition SpiralVase.cpp:26
Eigen::Matrix< double, 3, 1, Eigen::DontAlign > Vec3d
Definition Point.hpp:68
constexpr float DEFAULT_FILAMENT_DENSITY
Definition GCodeProcessor.hpp:42
ExtrusionRole
Definition ExtrusionEntity.hpp:26
@ erMixed
Definition ExtrusionEntity.hpp:47
@ erCustom
Definition ExtrusionEntity.hpp:45
@ erWipeTower
Definition ExtrusionEntity.hpp:44
@ erBrim
Definition ExtrusionEntity.hpp:40
@ erSkirt
Definition ExtrusionEntity.hpp:39
@ erNone
Definition ExtrusionEntity.hpp:27
Slic3r::Polygons offset(const Slic3r::Polygon &polygon, const float delta, JoinType joinType, double miterLimit)
Definition ClipperUtils.cpp:582
bool is_support(ExtrusionRole role)
Definition ExtrusionEntity.hpp:113
@ Y
Definition libslic3r.h:142
@ Z
Definition libslic3r.h:143
@ X
Definition libslic3r.h:141

References Slic3r::GCodeProcessor::MassLocation::body, Slic3r::DEFAULT_FILAMENT_DENSITY, Slic3r::erBrim, Slic3r::erCustom, Slic3r::erMixed, Slic3r::erNone, Slic3r::erSkirt, Slic3r::erWipeTower, Slic3r::is_support(), m_end_position, m_extruder_offsets, m_extrusion_role, m_height, m_layer_id, m_mass_locator, m_result, m_start_position, m_x_offset, m_y_offset, m_z_offset, Slic3r::BoundingBox3Base< PointType >::merge(), Slic3r::GCodeProcessor::MassLocation::object, Slic3r::offset(), Slic3r::X, Slic3r::Y, and Slic3r::Z.

Referenced by process_G1().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ apply_config() [1/2]

void Slic3r::GCodeProcessor::apply_config ( const DynamicPrintConfig & config)
private
3280{
3281 m_parser.apply_config(config);
3282
3283 // Belt printer: remember the file's belt keys for export_config_for_render(). The
3284 // config block lists belt_printer for every printer, so a non-belt file loaded while
3285 // a belt printer is selected switches the preview's belt view off, and a belt file
3286 // loaded on another printer brings its own tilt, remaps and bed along.
3287 m_belt_render_config.clear();
3288 {
3289 const auto *belt = config.option<ConfigOptionBool>("belt_printer");
3290 if (belt != nullptr) {
3291 static const char *belt_keys[] = {
3292 "belt_printer", "belt_slice_rotation", "belt_slice_rotation_angle",
3293 "gcode_remap_x", "gcode_remap_y", "gcode_remap_z",
3294 "belt_frame_tilt_decouple", "belt_frame_tilt_angle",
3295 };
3296 for (const char *key : belt_keys)
3297 if (const ConfigOption *opt = config.option(key); opt != nullptr)
3298 m_belt_render_config.set_key_value(key, opt->clone());
3299 // The Rev remaps mirror inside the build volume, so the designed view needs
3300 // the bed the file was sliced for. Only a belt file may override it.
3301 static const char *bed_keys[] = { "printable_area", "printable_height" };
3302 if (belt->value)
3303 for (const char *key : bed_keys)
3304 if (const ConfigOption *opt = config.option(key); opt != nullptr)
3305 m_belt_render_config.set_key_value(key, opt->clone());
3306 }
3307 }
3308
3309 //BBS
3310 const ConfigOptionFloatsNullable* nozzle_volume = config.option<ConfigOptionFloatsNullable>("nozzle_volume");
3311 if (nozzle_volume != nullptr) {
3312 m_nozzle_volume.resize(nozzle_volume->size(), 0);
3313 for (size_t idx = 0; idx < nozzle_volume->size(); ++idx)
3314 m_nozzle_volume[idx] = nozzle_volume->values[idx];
3315 }
3316
3317 const ConfigOptionInt *nozzle_HRC = config.option<ConfigOptionInt>("nozzle_hrc");
3318 if (nozzle_HRC != nullptr) m_result.nozzle_hrc = nozzle_HRC->value;
3319
3320 const ConfigOptionInts* physical_extruder_map = config.option<ConfigOptionInts>("physical_extruder_map");
3321 if (physical_extruder_map != nullptr) {
3323 }
3324
3325 // Multi-nozzle context state, consumed by the multi-nozzle time model and pre-heat injector.
3326 const ConfigOptionIntsNullable* extruder_max_nozzle_count = config.option<ConfigOptionIntsNullable>("extruder_max_nozzle_count");
3327 if (extruder_max_nozzle_count != nullptr) {
3329 }
3330
3331 // Pre-heat / pre-cool injector estimator inputs. Gated on enable_pre_heating; consumed later by the
3332 // injector side-pass. handle_hotend_as_extruder is read only in this overload; nozzle_diameter uses
3333 // the non-nullable ConfigOptionFloats type.
3334 const ConfigOptionFloatsNullable* hotend_cooling_rate = config.option<ConfigOptionFloatsNullable>("hotend_cooling_rate");
3335 if (hotend_cooling_rate != nullptr)
3337
3338 const ConfigOptionFloatsNullable* hotend_heating_rate = config.option<ConfigOptionFloatsNullable>("hotend_heating_rate");
3339 if (hotend_heating_rate != nullptr)
3340 m_hotend_heating_rate = hotend_heating_rate->values;
3341
3342 const ConfigOptionIntsNullable* filament_pre_cooling_temperature = config.option<ConfigOptionIntsNullable>("filament_pre_cooling_temperature");
3343 if (filament_pre_cooling_temperature != nullptr)
3345
3346 const ConfigOptionFloatsNullable* filament_preheat_temperature_delta = config.option<ConfigOptionFloatsNullable>("filament_preheat_temperature_delta");
3347 if (filament_preheat_temperature_delta != nullptr)
3348 m_filament_preheat_temperature_delta = filament_preheat_temperature_delta->values;
3349
3350 const ConfigOptionBool* enable_pre_heating = config.option<ConfigOptionBool>("enable_pre_heating");
3351 if (enable_pre_heating != nullptr)
3352 m_enable_pre_heating = enable_pre_heating->value;
3353
3354 const ConfigOptionBool* handle_hotend_as_extruder = config.option<ConfigOptionBool>("handle_hotend_as_extruder");
3355 if (handle_hotend_as_extruder != nullptr)
3356 m_handle_hotend_as_extruder = handle_hotend_as_extruder->value;
3357
3358 const ConfigOptionBool* has_filament_switcher = config.option<ConfigOptionBool>("has_filament_switcher");
3359 if (has_filament_switcher != nullptr)
3360 m_has_filament_switcher = has_filament_switcher->value;
3361
3362 const ConfigOptionFloats* nozzle_diameter = config.option<ConfigOptionFloats>("nozzle_diameter");
3363 if (nozzle_diameter != nullptr)
3365
3366 const ConfigOptionStrings* filament_type = config.option<ConfigOptionStrings>("filament_type");
3367 if (filament_type != nullptr) {
3368 m_filament_types.resize(filament_type->size());
3369 for (size_t idx = 0; idx < filament_type->size(); ++idx)
3370 m_filament_types[idx] = filament_type->get_at(idx);
3371 }
3372
3373 const ConfigOptionEnumsGeneric* extruder_type = config.option<ConfigOptionEnumsGeneric>("extruder_type");
3374 if (extruder_type != nullptr) {
3375 m_result.extruder_types.resize(extruder_type->values.size());
3376 for (size_t idx = 0; idx < extruder_type->values.size(); ++idx)
3377 m_result.extruder_types[idx] = static_cast<ExtruderType>(extruder_type->values[idx]);
3378 }
3379
3380 if (const ConfigOptionStrings* pe_variant = config.option<ConfigOptionStrings>("printer_extruder_variant"))
3381 m_result.printer_extruder_variant = pe_variant->values;
3382 if (const ConfigOptionInts* pe_id = config.option<ConfigOptionInts>("printer_extruder_id"))
3383 m_result.printer_extruder_id = pe_id->values;
3384
3386 if (nozzle_type != nullptr) {
3387 m_result.nozzle_type.resize(nozzle_type->size());
3388 for (size_t idx = 0; idx < nozzle_type->values.size(); ++idx) {
3389 m_result.nozzle_type[idx] = NozzleType(nozzle_type->values[idx]);
3390 }
3391 }
3392
3393 const ConfigOptionEnum<GCodeFlavor>* gcode_flavor = config.option<ConfigOptionEnum<GCodeFlavor>>("gcode_flavor");
3394 if (gcode_flavor != nullptr)
3395 m_flavor = gcode_flavor->value;
3396
3397 const ConfigOptionPoints* printable_area = config.option<ConfigOptionPoints>("printable_area");
3398 if (printable_area != nullptr)
3399 m_result.printable_area = make_counter_clockwise(printable_area->values);
3400
3401 //BBS: add bed_exclude_area
3402 const ConfigOptionPoints* bed_exclude_area = config.option<ConfigOptionPoints>("bed_exclude_area");
3403 if (bed_exclude_area != nullptr)
3404 m_result.bed_exclude_area = bed_exclude_area->values;
3405
3406 const ConfigOptionPoints* wrapping_exclude_area = config.option<ConfigOptionPoints>("wrapping_exclude_area");
3407 if (wrapping_exclude_area != nullptr)
3408 m_result.wrapping_exclude_area = wrapping_exclude_area->values;
3409
3410 const ConfigOptionString* print_settings_id = config.option<ConfigOptionString>("print_settings_id");
3411 if (print_settings_id != nullptr)
3412 m_result.settings_ids.print = print_settings_id->value;
3413
3414 const ConfigOptionStrings* filament_settings_id = config.option<ConfigOptionStrings>("filament_settings_id");
3415 if (filament_settings_id != nullptr)
3416 m_result.settings_ids.filament = filament_settings_id->values;
3417
3418 const ConfigOptionString* printer_settings_id = config.option<ConfigOptionString>("printer_settings_id");
3419 if (printer_settings_id != nullptr)
3420 m_result.settings_ids.printer = printer_settings_id->value;
3421
3422 const ConfigOptionString* printer_model = config.option<ConfigOptionString>("printer_model");
3423 if (printer_model != nullptr)
3424 m_printer_model = printer_model->value;
3425
3426 // BBS
3427 m_result.filaments_count = config.option<ConfigOptionFloats>("filament_diameter")->values.size();
3428
3429 const ConfigOptionFloats* filament_diameters = config.option<ConfigOptionFloats>("filament_diameter");
3430 if (filament_diameters != nullptr) {
3431 m_result.filament_diameters.clear();
3432 m_result.filament_diameters.resize(filament_diameters->values.size());
3433 for (size_t i = 0; i < filament_diameters->values.size(); ++i) {
3434 m_result.filament_diameters[i] = static_cast<float>(filament_diameters->values[i]);
3435 }
3436 }
3437
3438 if (m_result.filament_diameters.size() < m_result.filaments_count) {
3439 for (size_t i = m_result.filament_diameters.size(); i < m_result.filaments_count; ++i) {
3440 m_result.filament_diameters.emplace_back(DEFAULT_FILAMENT_DIAMETER);
3441 }
3442 }
3443
3444 const ConfigOptionInts *filament_HRC = config.option<ConfigOptionInts>("required_nozzle_HRC");
3445 if (filament_HRC != nullptr) {
3446 m_result.required_nozzle_HRC.clear();
3447 m_result.required_nozzle_HRC.resize(filament_HRC->values.size());
3448 for (size_t i = 0; i < filament_HRC->values.size(); ++i) { m_result.required_nozzle_HRC[i] = static_cast<float>(filament_HRC->values[i]); }
3449 }
3450
3451 if (m_result.required_nozzle_HRC.size() < m_result.filaments_count) {
3452 for (size_t i = m_result.required_nozzle_HRC.size(); i < m_result.filaments_count; ++i) { m_result.required_nozzle_HRC.emplace_back(DEFAULT_FILAMENT_HRC);
3453 }
3454 }
3455
3456 const ConfigOptionFloats* filament_densities = config.option<ConfigOptionFloats>("filament_density");
3457 if (filament_densities != nullptr) {
3458 m_result.filament_densities.clear();
3459 m_result.filament_densities.resize(filament_densities->values.size());
3460 for (size_t i = 0; i < filament_densities->values.size(); ++i) {
3461 m_result.filament_densities[i] = static_cast<float>(filament_densities->values[i]);
3462 }
3463 }
3464
3465 if (m_result.filament_densities.size() < m_result.filaments_count) {
3466 for (size_t i = m_result.filament_densities.size(); i < m_result.filaments_count; ++i) {
3467 m_result.filament_densities.emplace_back(DEFAULT_FILAMENT_DENSITY);
3468 }
3469 }
3470
3471 auto filament_maps = config.option<ConfigOptionInts>("filament_map");
3472 if (filament_maps != nullptr) {
3473 m_filament_maps = filament_maps->values;
3474 std::transform(m_filament_maps.begin(), m_filament_maps.end(), m_filament_maps.begin(), [](int value) {return value - 1; });
3475 }
3476
3477 //BBS
3478 const ConfigOptionFloats* filament_costs = config.option<ConfigOptionFloats>("filament_cost");
3479 if (filament_costs != nullptr) {
3480 m_result.filament_costs.clear();
3481 m_result.filament_costs.resize(filament_costs->values.size());
3482 for (size_t i = 0; i < filament_costs->values.size(); ++i)
3483 m_result.filament_costs[i]=static_cast<float>(filament_costs->values[i]);
3484 }
3485 for (size_t i = m_result.filament_costs.size(); i < m_result.filaments_count; ++i) {
3486 m_result.filament_costs.emplace_back(DEFAULT_FILAMENT_COST);
3487 }
3488
3489 //BBS
3490 const ConfigOptionInts* filament_vitrification_temperature = config.option<ConfigOptionInts>("temperature_vitrification");
3491 if (filament_vitrification_temperature != nullptr) {
3492 m_result.filament_vitrification_temperature.clear();
3493 m_result.filament_vitrification_temperature.resize(filament_vitrification_temperature->values.size());
3494 for (size_t i = 0; i < filament_vitrification_temperature->values.size(); ++i) {
3495 m_result.filament_vitrification_temperature[i] = static_cast<int>(filament_vitrification_temperature->values[i]);
3496 }
3497 }
3498 if (m_result.filament_vitrification_temperature.size() < m_result.filaments_count) {
3499 for (size_t i = m_result.filament_vitrification_temperature.size(); i < m_result.filaments_count; ++i) {
3500 m_result.filament_vitrification_temperature.emplace_back(DEFAULT_FILAMENT_VITRIFICATION_TEMPERATURE);
3501 }
3502 }
3503
3504 const ConfigOptionPoints* extruder_offset = config.option<ConfigOptionPoints>("extruder_offset");
3505 const ConfigOptionBool* single_extruder_multi_material = config.option<ConfigOptionBool>("single_extruder_multi_material");
3506 if (extruder_offset != nullptr) {
3507 //BBS: for single extruder multi material, only use the offset of first extruder
3509 Vec2f offset = extruder_offset->values[0].cast<float>();
3510 m_extruder_offsets.resize(m_result.filaments_count);
3511 for (size_t i = 0; i < m_result.filaments_count; ++i) {
3512 m_extruder_offsets[i] = { offset(0), offset(1), 0.0f };
3513 }
3514 }
3515 else {
3516 m_extruder_offsets.resize(extruder_offset->values.size());
3517 for (size_t i = 0; i < extruder_offset->values.size(); ++i) {
3518 Vec2f offset = extruder_offset->values[i].cast<float>();
3519 m_extruder_offsets[i] = { offset(0), offset(1), 0.0f };
3520 }
3521 }
3522 }
3523
3524 if (m_extruder_offsets.size() < m_result.filaments_count) {
3525 for (size_t i = m_extruder_offsets.size(); i < m_result.filaments_count; ++i) {
3527 }
3528 }
3529
3530 // BBS
3531 const ConfigOptionStrings* filament_colour = config.option<ConfigOptionStrings>("filament_colour");
3532 if (filament_colour != nullptr && filament_colour->values.size() == m_result.extruder_colors.size()) {
3533 for (size_t i = 0; i < m_result.extruder_colors.size(); ++i) {
3534 if (m_result.extruder_colors[i].empty())
3535 m_result.extruder_colors[i] = filament_colour->values[i];
3536 }
3537 }
3538
3539 if (m_result.extruder_colors.size() < m_result.filaments_count) {
3540 for (size_t i = m_result.extruder_colors.size(); i < m_result.filaments_count; ++i) {
3541 m_result.extruder_colors.emplace_back(std::string());
3542 }
3543 }
3544
3545 // replace missing values with default
3546 for (size_t i = 0; i < m_result.extruder_colors.size(); ++i) {
3547 if (m_result.extruder_colors[i].empty())
3548 m_result.extruder_colors[i] = "#FF8000";
3549 }
3550
3551 m_extruder_colors.resize(m_result.extruder_colors.size());
3552 for (size_t i = 0; i < m_result.extruder_colors.size(); ++i) {
3553 m_extruder_colors[i] = static_cast<unsigned char>(i);
3554 }
3555
3556 m_extruder_temps.resize(m_result.filaments_count);
3557
3558 const ConfigOptionFloat* machine_load_filament_time = config.option<ConfigOptionFloat>("machine_load_filament_time");
3559 if (machine_load_filament_time != nullptr)
3560 m_time_processor.filament_load_times = static_cast<float>(machine_load_filament_time->value);
3561
3562 const ConfigOptionFloat* machine_unload_filament_time = config.option<ConfigOptionFloat>("machine_unload_filament_time");
3563 if (machine_unload_filament_time != nullptr)
3564 m_time_processor.filament_unload_times = static_cast<float>(machine_unload_filament_time->value);
3565
3566 const ConfigOptionFloat* machine_tool_change_time = config.option<ConfigOptionFloat>("machine_tool_change_time");
3567 if (machine_tool_change_time != nullptr)
3568 m_time_processor.machine_tool_change_time = static_cast<float>(machine_tool_change_time->value);
3569
3571 const ConfigOptionFloats* machine_max_acceleration_x = config.option<ConfigOptionFloats>("machine_max_acceleration_x");
3572 if (machine_max_acceleration_x != nullptr)
3573 m_time_processor.machine_limits.machine_max_acceleration_x.values = machine_max_acceleration_x->values;
3574
3575 const ConfigOptionFloats* machine_max_acceleration_y = config.option<ConfigOptionFloats>("machine_max_acceleration_y");
3576 if (machine_max_acceleration_y != nullptr)
3577 m_time_processor.machine_limits.machine_max_acceleration_y.values = machine_max_acceleration_y->values;
3578
3579 const ConfigOptionFloats* machine_max_acceleration_z = config.option<ConfigOptionFloats>("machine_max_acceleration_z");
3580 if (machine_max_acceleration_z != nullptr)
3581 m_time_processor.machine_limits.machine_max_acceleration_z.values = machine_max_acceleration_z->values;
3582
3583 const ConfigOptionFloats* machine_max_acceleration_e = config.option<ConfigOptionFloats>("machine_max_acceleration_e");
3584 if (machine_max_acceleration_e != nullptr)
3585 m_time_processor.machine_limits.machine_max_acceleration_e.values = machine_max_acceleration_e->values;
3586
3587 const ConfigOptionFloats* machine_max_speed_x = config.option<ConfigOptionFloats>("machine_max_speed_x");
3588 if (machine_max_speed_x != nullptr)
3589 m_time_processor.machine_limits.machine_max_speed_x.values = machine_max_speed_x->values;
3590
3591 const ConfigOptionFloats* machine_max_speed_y = config.option<ConfigOptionFloats>("machine_max_speed_y");
3592 if (machine_max_speed_y != nullptr)
3593 m_time_processor.machine_limits.machine_max_speed_y.values = machine_max_speed_y->values;
3594
3595 const ConfigOptionFloats* machine_max_speed_z = config.option<ConfigOptionFloats>("machine_max_speed_z");
3596 if (machine_max_speed_z != nullptr)
3597 m_time_processor.machine_limits.machine_max_speed_z.values = machine_max_speed_z->values;
3598
3599 const ConfigOptionFloats* machine_max_speed_e = config.option<ConfigOptionFloats>("machine_max_speed_e");
3600 if (machine_max_speed_e != nullptr)
3601 m_time_processor.machine_limits.machine_max_speed_e.values = machine_max_speed_e->values;
3602
3603 const ConfigOptionFloats* machine_max_jerk_x = config.option<ConfigOptionFloats>("machine_max_jerk_x");
3604 if (machine_max_jerk_x != nullptr)
3605 m_time_processor.machine_limits.machine_max_jerk_x.values = machine_max_jerk_x->values;
3606
3607 const ConfigOptionFloats* machine_max_jerk_y = config.option<ConfigOptionFloats>("machine_max_jerk_y");
3608 if (machine_max_jerk_y != nullptr)
3609 m_time_processor.machine_limits.machine_max_jerk_y.values = machine_max_jerk_y->values;
3610
3611 const ConfigOptionFloats* machine_max_jerk_z = config.option<ConfigOptionFloats>("machine_max_jerk_z");
3612 if (machine_max_jerk_z != nullptr)
3613 m_time_processor.machine_limits.machine_max_jerk_z.values = machine_max_jerk_z->values;
3614
3615 const ConfigOptionFloats* machine_max_jerk_e = config.option<ConfigOptionFloats>("machine_max_jerk_e");
3616 if (machine_max_jerk_e != nullptr)
3617 m_time_processor.machine_limits.machine_max_jerk_e.values = machine_max_jerk_e->values;
3618
3619 const ConfigOptionFloats* machine_max_junction_deviation = config.option<ConfigOptionFloats>("machine_max_junction_deviation");
3620 if (machine_max_junction_deviation != nullptr)
3621 m_time_processor.machine_limits.machine_max_junction_deviation.values = machine_max_junction_deviation->values;
3622
3623 const ConfigOptionFloats* machine_max_acceleration_extruding = config.option<ConfigOptionFloats>("machine_max_acceleration_extruding");
3624 if (machine_max_acceleration_extruding != nullptr)
3625 m_time_processor.machine_limits.machine_max_acceleration_extruding.values = machine_max_acceleration_extruding->values;
3626
3627 const ConfigOptionFloats* machine_max_acceleration_retracting = config.option<ConfigOptionFloats>("machine_max_acceleration_retracting");
3628 if (machine_max_acceleration_retracting != nullptr)
3629 m_time_processor.machine_limits.machine_max_acceleration_retracting.values = machine_max_acceleration_retracting->values;
3630
3631
3632 // Legacy Marlin does not have separate travel acceleration, it uses the 'extruding' value instead.
3633 const ConfigOptionFloats* machine_max_acceleration_travel = config.option<ConfigOptionFloats>(m_flavor == gcfMarlinLegacy || m_flavor == gcfKlipper
3634 ? "machine_max_acceleration_extruding"
3635 : "machine_max_acceleration_travel");
3636 if (machine_max_acceleration_travel != nullptr)
3637 m_time_processor.machine_limits.machine_max_acceleration_travel.values = machine_max_acceleration_travel->values;
3638
3639
3640 const ConfigOptionFloats* machine_min_extruding_rate = config.option<ConfigOptionFloats>("machine_min_extruding_rate");
3641 if (machine_min_extruding_rate != nullptr)
3642 m_time_processor.machine_limits.machine_min_extruding_rate.values = machine_min_extruding_rate->values;
3643
3644 const ConfigOptionFloats* machine_min_travel_rate = config.option<ConfigOptionFloats>("machine_min_travel_rate");
3645 if (machine_min_travel_rate != nullptr)
3646 m_time_processor.machine_limits.machine_min_travel_rate.values = machine_min_travel_rate->values;
3647 }
3648
3649 for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
3650 float max_acceleration = get_option_value(m_time_processor.machine_limits.machine_max_acceleration_extruding, i);
3651 m_time_processor.machines[i].max_acceleration = max_acceleration;
3652 m_time_processor.machines[i].acceleration = (max_acceleration > 0.0f) ? max_acceleration : DEFAULT_ACCELERATION;
3653 float max_retract_acceleration = get_option_value(m_time_processor.machine_limits.machine_max_acceleration_retracting, i);
3654 m_time_processor.machines[i].max_retract_acceleration = max_retract_acceleration;
3655 m_time_processor.machines[i].retract_acceleration = (max_retract_acceleration > 0.0f) ? max_retract_acceleration :
3657 float max_travel_acceleration = get_option_value(m_time_processor.machine_limits.machine_max_acceleration_travel, i);
3658 m_time_processor.machines[i].max_travel_acceleration = max_travel_acceleration;
3659 m_time_processor.machines[i].travel_acceleration = (max_travel_acceleration > 0.0f) ? max_travel_acceleration :
3661 }
3662
3663 const ConfigOptionFloat* initial_layer_print_height = config.option<ConfigOptionFloat>("initial_layer_print_height");
3664 if (initial_layer_print_height != nullptr)
3666
3667 const ConfigOptionFloat* printable_height = config.option<ConfigOptionFloat>("printable_height");
3668 if (printable_height != nullptr)
3669 m_result.printable_height = printable_height->value;
3670
3671 const ConfigOptionBool* spiral_vase = config.option<ConfigOptionBool>("spiral_mode");
3672 if (spiral_vase != nullptr) {
3673 m_detect_layer_based_on_tag = spiral_vase->value;
3674 m_result.spiral_vase_mode = spiral_vase->value;
3675 }
3676
3677 const ConfigOptionBool* has_scarf_joint_seam = config.option<ConfigOptionBool>("has_scarf_joint_seam");
3678 if (has_scarf_joint_seam != nullptr)
3680
3681 const ConfigOptionBool* manual_filament_change = config.option<ConfigOptionBool>("manual_filament_change");
3682 if (manual_filament_change != nullptr)
3683 m_manual_filament_change = manual_filament_change->value;
3684
3685 const ConfigOptionEnumGeneric *bed_type = config.option<ConfigOptionEnumGeneric>("curr_bed_type");
3686 if (bed_type != nullptr)
3687 m_result.bed_type = (BedType)bed_type->value;
3688
3689
3690 const ConfigOptionFloat* z_offset = config.option<ConfigOptionFloat>("z_offset");
3691 if (z_offset != nullptr)
3692 m_z_offset = z_offset->value;
3693
3694 // Reprocessing an existing g-code (from-previous reload / imported g-code) reaches apply_config
3695 // through this DynamicPrintConfig overload; rebuild the per-filament nozzle grouping onto the
3696 // result so the multi-nozzle device GUI can map filaments to physical nozzles. The normal
3697 // streaming export uses the PrintConfig overload and hands the live grouping over separately, so
3698 // it is intentionally not touched here.
3699 ensure_nozzle_group_result(static_cast<int>(m_result.filaments_count));
3700}
static const float DEFAULT_TRAVEL_ACCELERATION
Definition GCodeProcessor.cpp:90
static const int DEFAULT_FILAMENT_VITRIFICATION_TEMPERATURE
Definition GCodeProcessor.cpp:96
static const float DEFAULT_FILAMENT_DIAMETER
Definition GCodeProcessor.cpp:93
static const Slic3r::Vec3f DEFAULT_EXTRUDER_OFFSET
Definition GCodeProcessor.cpp:97
static const float DEFAULT_ACCELERATION
Definition GCodeProcessor.cpp:88
static const int DEFAULT_FILAMENT_HRC
Definition GCodeProcessor.cpp:94
static const float DEFAULT_FILAMENT_COST
Definition GCodeProcessor.cpp:95
static const float DEFAULT_RETRACT_ACCELERATION
Definition GCodeProcessor.cpp:89
size_t size() const override
Definition Config.hpp:722
std::vector< double > m_filament_preheat_temperature_delta
Definition GCodeProcessor.hpp:1265
bool m_detect_layer_based_on_tag
Definition GCodeProcessor.hpp:1346
void ensure_nozzle_group_result(int min_filament_count)
Definition GCodeProcessor.cpp:7147
std::vector< int > m_filament_pre_cooling_temp
Definition GCodeProcessor.hpp:1264
ExtruderColors m_extruder_colors
Definition GCodeProcessor.hpp:1331
std::vector< int > m_filament_maps
Definition GCodeProcessor.hpp:1324
GCodeReader m_parser
Definition GCodeProcessor.hpp:1218
float m_first_layer_height
Definition GCodeProcessor.hpp:1336
bool m_manual_filament_change
Definition GCodeProcessor.hpp:1297
std::vector< std::string > m_filament_types
Definition GCodeProcessor.hpp:1260
std::string m_printer_model
Definition GCodeProcessor.hpp:1354
bool m_handle_hotend_as_extruder
Definition GCodeProcessor.hpp:1267
ExtruderTemps m_extruder_temps
Definition GCodeProcessor.hpp:1332
bool m_has_filament_switcher
Definition GCodeProcessor.hpp:1268
std::vector< float > m_nozzle_volume
Definition GCodeProcessor.hpp:1228
std::vector< int > m_physical_extruder_map
Definition GCodeProcessor.hpp:1252
std::vector< int > m_extruder_max_nozzle_count
Definition GCodeProcessor.hpp:1256
GCodeFlavor m_flavor
Definition GCodeProcessor.hpp:1227
std::vector< double > m_hotend_heating_rate
Definition GCodeProcessor.hpp:1263
std::vector< double > m_hotend_cooling_rate
Definition GCodeProcessor.hpp:1262
std::vector< double > m_nozzle_diameter
Definition GCodeProcessor.hpp:1261
bool m_enable_pre_heating
Definition GCodeProcessor.hpp:1266
DynamicConfig m_belt_render_config
Definition GCodeProcessor.hpp:1222
@ gcfMarlinFirmware
Definition PrintConfig.hpp:56
@ gcfKlipper
Definition PrintConfig.hpp:53
@ gcfMarlinLegacy
Definition PrintConfig.hpp:52
zaa_minimize_perimeter_height ConfigOptionFloat
Definition PrintConfig.hpp:1954
zaa_minimize_perimeter_height printable_area((ConfigOptionPointsGroups, extruder_printable_area))((ConfigOptionBool
zaa_minimize_perimeter_height nozzle_diameter((ConfigOptionBool, reduce_infill_retraction))((ConfigOptionBool
zaa_minimize_perimeter_height single_extruder_multi_material((ConfigOptionBool, manual_filament_change))((ConfigOptionBool
zaa_minimize_perimeter_height physical_extruder_map((ConfigOptionIntsNullable, nozzle_flush_dataset))((ConfigOptionFloatsNullable
zaa_minimize_perimeter_height hotend_cooling_rate((ConfigOptionFloatsNullable, hotend_heating_rate))((ConfigOptionFloats
zaa_minimize_perimeter_height gcode_flavor((ConfigOptionBool, gcode_skip_config_block))((ConfigOptionFloat
zaa_minimize_perimeter_height filament_pre_cooling_temperature((ConfigOptionFloatsNullable, filament_ramming_volumetric_speed))((ConfigOptionFloatsNullable
ConfigOptionEnumsGenericTempl< false > ConfigOptionEnumsGeneric
Definition Config.hpp:2311
BedType
Definition PrintConfig.hpp:507
ConfigOptionIntsTempl< true > ConfigOptionIntsNullable
Definition Config.hpp:1155
zaa_minimize_perimeter_height filament_type((ConfigOptionBools, filament_soluble))((ConfigOptionStrings
Pointfs make_counter_clockwise(const Pointfs &pointfs)
Definition ClipperUtils.cpp:1568
zaa_minimize_perimeter_height initial_layer_print_height((ConfigOptionFloatsNullable, initial_layer_speed))((ConfigOptionFloatsNullable
ConfigOptionFloatsTempl< true > ConfigOptionFloatsNullable
Definition Config.hpp:1016
NozzleType
Definition CommonDefs.hpp:13
zaa_minimize_perimeter_height extruder_offset((ConfigOptionBools, reduce_fan_stop_start_freq))((ConfigOptionBools
ConfigOptionIntsTempl< false > ConfigOptionInts
Definition Config.hpp:1154
ExtruderType
Definition PrintConfig.hpp:612
zaa_minimize_perimeter_height printable_height((ConfigOptionFloatsNullable, extruder_printable_height))((ConfigOptionPoint
zaa_minimize_perimeter_height ConfigOptionString
Definition PrintConfig.hpp:1702
zaa_minimize_perimeter_height machine_load_filament_time((ConfigOptionFloat, machine_tool_change_time))((ConfigOptionFloat
ConfigOptionEnumsGenericTempl< true > ConfigOptionEnumsGenericNullable
Definition Config.hpp:2312
Eigen::Matrix< float, 2, 1, Eigen::DontAlign > Vec2f
Definition Point.hpp:64
zaa_minimize_perimeter_height has_scarf_joint_seam((ConfigOptionFloat, machine_hotend_change_time))((ConfigOptionFloat
zaa_minimize_perimeter_height machine_unload_filament_time((ConfigOptionFloats, filament_loading_speed))((ConfigOptionFloats
zaa_minimize_perimeter_height extruder_max_nozzle_count((ConfigOptionBool, support_fast_purge_mode))((ConfigOptionStrings
zaa_minimize_perimeter_height nozzle_type((ConfigOptionInt, nozzle_hrc))((ConfigOptionBool
ConfigOptionFloatsTempl< false > ConfigOptionFloats
Definition Config.hpp:1015
static float get_option_value(const ConfigOptionFloats &option, size_t id)
Definition GCodeProcessor.cpp:202
@ Count
Definition GCodeProcessor.hpp:91

References Slic3r::PrintEstimatedStatistics::Count, DEFAULT_ACCELERATION, DEFAULT_EXTRUDER_OFFSET, DEFAULT_FILAMENT_COST, Slic3r::DEFAULT_FILAMENT_DENSITY, DEFAULT_FILAMENT_DIAMETER, DEFAULT_FILAMENT_HRC, DEFAULT_FILAMENT_VITRIFICATION_TEMPERATURE, DEFAULT_RETRACT_ACCELERATION, DEFAULT_TRAVEL_ACCELERATION, ensure_nozzle_group_result(), Slic3r::extruder_max_nozzle_count(), Slic3r::extruder_offset(), Slic3r::filament_pre_cooling_temperature(), Slic3r::filament_type(), Slic3r::gcfKlipper, Slic3r::gcfMarlinFirmware, Slic3r::gcfMarlinLegacy, Slic3r::gcode_flavor(), Slic3r::get_option_value(), Slic3r::has_scarf_joint_seam(), Slic3r::hotend_cooling_rate(), Slic3r::initial_layer_print_height(), m_belt_render_config, m_detect_layer_based_on_tag, m_enable_pre_heating, m_extruder_colors, m_extruder_max_nozzle_count, m_extruder_offsets, m_extruder_temps, m_filament_maps, m_filament_pre_cooling_temp, m_filament_preheat_temperature_delta, m_filament_types, m_first_layer_height, m_flavor, m_handle_hotend_as_extruder, m_has_filament_switcher, m_hotend_cooling_rate, m_hotend_heating_rate, m_manual_filament_change, m_nozzle_diameter, m_nozzle_volume, m_parser, m_physical_extruder_map, m_printer_model, m_result, m_time_processor, m_z_offset, Slic3r::machine_load_filament_time(), Slic3r::machine_unload_filament_time(), Slic3r::make_counter_clockwise(), Slic3r::nozzle_diameter(), Slic3r::nozzle_type(), Slic3r::offset(), Slic3r::ConfigBase::option(), Slic3r::physical_extruder_map(), Slic3r::printable_area(), Slic3r::printable_height(), Slic3r::single_extruder_multi_material(), Slic3r::ConfigOptionVector< double >::size(), Slic3r::ConfigOptionSingle< T >::value, Slic3r::ConfigOptionVector< T >::values, Slic3r::ConfigOptionVector< double >::values, and Slic3r::ConfigOptionVector< int >::values.

Here is the call graph for this function:

◆ apply_config() [2/2]

void Slic3r::GCodeProcessor::apply_config ( const PrintConfig & config)
3114{
3115 m_parser.apply_config(config);
3116
3117 m_flavor = config.gcode_flavor;
3118 m_printer_model = config.printer_model.value;
3119
3120 m_single_extruder_multi_material = config.single_extruder_multi_material;
3121
3122 size_t filament_count = config.filament_diameter.values.size();
3123 m_result.filaments_count = filament_count;
3124
3125 // Orca:
3127 m_preheat_time = config.preheat_time;
3128 m_preheat_steps = config.preheat_steps;
3129 // sanity check
3130 if(m_preheat_steps < 1)
3131 m_preheat_steps = 1;
3132 m_result.backtrace_enabled = config.ooze_prevention && m_preheat_time > 0 && (m_is_XL_printer || (!m_single_extruder_multi_material && filament_count > 1));
3133
3134 assert(config.nozzle_volume.size() == config.nozzle_diameter.size());
3135 m_nozzle_volume.resize(config.nozzle_volume.size());
3136 for (size_t idx = 0; idx < config.nozzle_volume.size(); ++idx)
3137 m_nozzle_volume[idx] = config.nozzle_volume.values[idx];
3138
3139 m_physical_extruder_map = config.physical_extruder_map.values;
3140 // Multi-nozzle context state, consumed by the multi-nozzle time model and pre-heat injector.
3141 m_extruder_max_nozzle_count = config.extruder_max_nozzle_count.values;
3142
3143 // Pre-heat / pre-cool injector estimator inputs. Gated on enable_pre_heating; the injector
3144 // side-pass that consumes them runs later in run_second_pass_injection. has_filament_switcher is
3145 // read defensively because it is registered as a ConfigDef only, not a static PrintConfig member.
3146 m_filament_types.resize(filament_count);
3147 for (size_t idx = 0; idx < filament_count; ++idx)
3148 m_filament_types[idx] = config.filament_type.get_at(idx);
3149 m_nozzle_diameter = config.nozzle_diameter.values;
3150 m_hotend_cooling_rate = config.hotend_cooling_rate.values;
3151 m_hotend_heating_rate = config.hotend_heating_rate.values;
3152 m_filament_pre_cooling_temp = config.filament_pre_cooling_temperature.values;
3153 m_filament_preheat_temperature_delta = config.filament_preheat_temperature_delta.values;
3154 m_enable_pre_heating = config.enable_pre_heating.value;
3155 if (const ConfigOptionBool* has_switcher = config.option<ConfigOptionBool>("has_filament_switcher"))
3156 m_has_filament_switcher = has_switcher->value;
3157 m_result.extruder_types.resize(config.extruder_type.values.size());
3158 for (size_t idx = 0; idx < config.extruder_type.values.size(); ++idx)
3159 m_result.extruder_types[idx] = static_cast<ExtruderType>(config.extruder_type.values[idx]);
3160 m_result.printer_extruder_variant = config.printer_extruder_variant.values;
3161 m_result.printer_extruder_id = config.printer_extruder_id.values;
3162
3163 m_extruder_offsets.resize(filament_count);
3164 m_extruder_colors.resize(filament_count);
3165 m_result.filament_diameters.resize(filament_count);
3166 m_result.required_nozzle_HRC.resize(filament_count);
3167 m_result.filament_densities.resize(filament_count);
3168 m_result.filament_vitrification_temperature.resize(filament_count);
3169 m_result.filament_costs.resize(filament_count);
3170 m_extruder_temps.resize(filament_count);
3171 m_filament_nozzle_temp.resize(filament_count);
3172 m_filament_nozzle_temp_first_layer.resize(filament_count);
3173 m_result.nozzle_hrc = static_cast<int>(config.nozzle_hrc.getInt());
3174 std::vector<NozzleType>(config.nozzle_type.size()).swap(m_result.nozzle_type);
3175 for (size_t idx = 0; idx < m_result.nozzle_type.size(); ++idx) {
3176 m_result.nozzle_type[idx] = NozzleType(config.nozzle_type.values[idx]);
3177 }
3178
3179 std::vector<int> filament_map = config.filament_map.values; // 1 based idxs
3180 // if filament map has wrong length, set filament to master extruder_id
3181 filament_map.resize(filament_count, config.master_extruder_id.value);
3182
3183 for (size_t i = 0; i < filament_count; ++ i) {
3184 m_extruder_offsets[i] = to_3d(config.extruder_offset.get_at(filament_map[i] - 1).cast<float>().eval(), 0.f);
3185 m_extruder_colors[i] = static_cast<unsigned char>(i);
3186 // Orca: pre-heat bookkeeping reads the filament's first per-variant column by design;
3187 // it feeds estimation-side heat-up modelling only, never the emitted commands.
3188 m_filament_nozzle_temp_first_layer[i] = static_cast<int>(config.nozzle_temperature_initial_layer.get_at(i));
3189 m_filament_nozzle_temp[i] = static_cast<int>(config.nozzle_temperature.get_at(i));
3190 if (m_filament_nozzle_temp[i] == 0) {
3191 // This means the value should be ignored and first layer temp should be used.
3193 }
3194 m_result.filament_diameters[i] = static_cast<float>(config.filament_diameter.get_at(i));
3195 m_result.required_nozzle_HRC[i] = static_cast<int>(config.required_nozzle_HRC.get_at(i));
3196 m_result.filament_densities[i] = static_cast<float>(config.filament_density.get_at(i));
3197 m_result.filament_vitrification_temperature[i] = static_cast<float>(config.temperature_vitrification.get_at(i));
3198 m_result.filament_costs[i] = static_cast<float>(config.filament_cost.get_at(i));
3199 }
3200
3202 m_time_processor.machine_limits = reinterpret_cast<const MachineEnvelopeConfig&>(config);
3204 // Legacy Marlin does not have separate travel acceleration, it uses the 'extruding' value instead.
3205 m_time_processor.machine_limits.machine_max_acceleration_travel = m_time_processor.machine_limits.machine_max_acceleration_extruding;
3206 }
3207 if (m_flavor == gcfRepRapFirmware) {
3208 // RRF does not support setting min feedrates. Set them to zero.
3209 m_time_processor.machine_limits.machine_min_travel_rate.values.assign(m_time_processor.machine_limits.machine_min_travel_rate.size(), 0.);
3210 m_time_processor.machine_limits.machine_min_extruding_rate.values.assign(m_time_processor.machine_limits.machine_min_extruding_rate.size(), 0.);
3211 }
3212 }
3213
3214 // Filament load / unload times are not specific to a firmware flavor. Let anybody use it if they find it useful.
3215 // As of now the fields are shown at the UI dialog in the same combo box as the ramming values, so they
3216 // are considered to be active for the single extruder multi-material printers only.
3217 m_time_processor.filament_load_times = static_cast<float>(config.machine_load_filament_time.value);
3218 m_time_processor.filament_unload_times = static_cast<float>(config.machine_unload_filament_time.value);
3219 m_time_processor.machine_tool_change_time = static_cast<float>(config.machine_tool_change_time.value);
3220
3221 for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
3222 float max_acceleration = get_option_value(m_time_processor.machine_limits.machine_max_acceleration_extruding, i);
3223 m_time_processor.machines[i].max_acceleration = max_acceleration;
3224 m_time_processor.machines[i].acceleration = (max_acceleration > 0.0f) ? max_acceleration : DEFAULT_ACCELERATION;
3225 float max_retract_acceleration = get_option_value(m_time_processor.machine_limits.machine_max_acceleration_retracting, i);
3226 m_time_processor.machines[i].max_retract_acceleration = max_retract_acceleration;
3227 m_time_processor.machines[i].retract_acceleration = (max_retract_acceleration > 0.0f) ? max_retract_acceleration :
3229 float max_travel_acceleration = get_option_value(m_time_processor.machine_limits.machine_max_acceleration_travel, i);
3230 if (!GCodeWriter::supports_separate_travel_acceleration(config.gcode_flavor.value)){
3231 max_travel_acceleration = 0;
3232 }
3233 m_time_processor.machines[i].max_travel_acceleration = max_travel_acceleration;
3234 m_time_processor.machines[i].travel_acceleration = (max_travel_acceleration > 0.0f) ? max_travel_acceleration :
3236 }
3237
3238 m_disable_m73 = config.disable_m73;
3239
3240 const ConfigOptionFloat* initial_layer_print_height = config.option<ConfigOptionFloat>("initial_layer_print_height");
3241 if (initial_layer_print_height != nullptr)
3243
3244 m_result.printable_height = config.printable_height;
3245
3246 // Belt printer: cache the post-gcode machine-frame transform so the
3247 // multi-extruder validator can undo it and compare against build-volume
3248 // bounds rather than machine-frame positions.
3249 m_machine_frame_transform.init_from_config(config);
3250 m_result.machine_frame_transform_active = m_machine_frame_transform.is_active();
3251 m_belt_printer = config.belt_printer.value;
3252
3253 auto filament_maps = config.option<ConfigOptionInts>("filament_map");
3254 if (filament_maps != nullptr) {
3255 m_filament_maps = filament_maps->values;
3256 std::transform(m_filament_maps.begin(), m_filament_maps.end(), m_filament_maps.begin(), [](int value) {return value - 1; });
3257 }
3258
3259 const ConfigOptionBool* spiral_vase = config.option<ConfigOptionBool>("spiral_mode");
3260 if (spiral_vase != nullptr) {
3261 m_detect_layer_based_on_tag = spiral_vase->value;
3262 m_result.spiral_vase_mode = spiral_vase->value;
3263 }
3264
3265 const ConfigOptionBool* has_scarf_joint_seam = config.option<ConfigOptionBool>("has_scarf_joint_seam");
3266 if (has_scarf_joint_seam != nullptr)
3268
3269 const ConfigOptionBool* manual_filament_change = config.option<ConfigOptionBool>("manual_filament_change");
3270 if (manual_filament_change != nullptr)
3271 m_manual_filament_change = manual_filament_change->value;
3272
3273 const ConfigOptionFloat* z_offset = config.option<ConfigOptionFloat>("z_offset");
3274 if (z_offset != nullptr)
3275 m_z_offset = z_offset->value;
3276
3277}
bool m_belt_printer
Definition GCodeProcessor.hpp:1308
float m_preheat_time
Definition GCodeProcessor.hpp:1351
bool m_disable_m73
Definition GCodeProcessor.hpp:1353
bool m_single_extruder_multi_material
Definition GCodeProcessor.hpp:1350
int m_preheat_steps
Definition GCodeProcessor.hpp:1352
ExtruderTemps m_filament_nozzle_temp_first_layer
Definition GCodeProcessor.hpp:1251
ExtruderTemps m_filament_nozzle_temp
Definition GCodeProcessor.hpp:1250
MachineFrameTransform m_machine_frame_transform
Definition GCodeProcessor.hpp:1307
bool m_is_XL_printer
Definition GCodeProcessor.hpp:1333
static bool supports_separate_travel_acceleration(GCodeFlavor flavor)
Definition GCodeWriter.cpp:100
@ gcfRepRapFirmware
Definition PrintConfig.hpp:54
Eigen::Matrix< typename Derived::Scalar, 3, 1, Eigen::DontAlign > to_3d(const Eigen::MatrixBase< Derived > &pt, const typename Derived::Scalar z)
Definition Point.hpp:153
static bool is_XL_printer(const std::string &printer_notes)
Definition PrintConfig.cpp:14440
zaa_minimize_perimeter_height filament_map((ConfigOptionInts, filament_volume_map))((ConfigOptionInts
zaa_minimize_perimeter_height MachineEnvelopeConfig
Definition PrintConfig.hpp:1951

References Slic3r::PrintEstimatedStatistics::Count, DEFAULT_ACCELERATION, DEFAULT_RETRACT_ACCELERATION, DEFAULT_TRAVEL_ACCELERATION, Slic3r::filament_map(), Slic3r::gcfKlipper, Slic3r::gcfMarlinFirmware, Slic3r::gcfMarlinLegacy, Slic3r::gcfRepRapFirmware, Slic3r::get_option_value(), Slic3r::has_scarf_joint_seam(), Slic3r::initial_layer_print_height(), Slic3r::is_XL_printer(), m_belt_printer, m_detect_layer_based_on_tag, m_disable_m73, m_enable_pre_heating, m_extruder_colors, m_extruder_max_nozzle_count, m_extruder_offsets, m_extruder_temps, m_filament_maps, m_filament_nozzle_temp, m_filament_nozzle_temp_first_layer, m_filament_pre_cooling_temp, m_filament_preheat_temperature_delta, m_filament_types, m_first_layer_height, m_flavor, m_has_filament_switcher, m_hotend_cooling_rate, m_hotend_heating_rate, m_is_XL_printer, m_machine_frame_transform, m_manual_filament_change, m_nozzle_diameter, m_nozzle_volume, m_parser, m_physical_extruder_map, m_preheat_steps, m_preheat_time, m_printer_model, m_result, m_single_extruder_multi_material, m_time_processor, m_z_offset, Slic3r::MachineEnvelopeConfig, Slic3r::GCodeWriter::supports_separate_travel_acceleration(), Slic3r::to_3d(), and Slic3r::ConfigOptionSingle< T >::value.

Referenced by apply_config_superslicer(), Slic3r::DoExport::init_gcode_processor(), and process_file().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ apply_config_simplify3d()

void Slic3r::GCodeProcessor::apply_config_simplify3d ( const std::string & filename)
private
4080{
4081 struct BedSize
4082 {
4083 double x{ 0.0 };
4084 double y{ 0.0 };
4085
4086 bool is_defined() const { return x > 0.0 && y > 0.0; }
4087 };
4088
4089 BedSize bed_size;
4090 bool producer_detected = false;
4091
4092 m_parser.parse_file_raw(filename, [this, &bed_size, &producer_detected](GCodeReader& reader, const char* begin, const char* end) {
4093
4094 auto extract_double = [](const std::string_view cmt, const std::string& key, double& out) {
4095 size_t pos = cmt.find(key);
4096 if (pos != cmt.npos) {
4097 pos = cmt.find(',', pos);
4098 if (pos != cmt.npos) {
4099 out = string_to_double_decimal_point(cmt.substr(pos+1));
4100 return true;
4101 }
4102 }
4103 return false;
4104 };
4105
4106 auto extract_floats = [](const std::string_view cmt, const std::string& key, std::vector<float>& out) {
4107 size_t pos = cmt.find(key);
4108 if (pos != cmt.npos) {
4109 pos = cmt.find(',', pos);
4110 if (pos != cmt.npos) {
4111 const std::string_view data_str = cmt.substr(pos + 1);
4112 std::vector<std::string> values_str;
4113 boost::split(values_str, data_str, boost::is_any_of("|,"), boost::token_compress_on);
4114 for (const std::string& s : values_str) {
4115 out.emplace_back(static_cast<float>(string_to_double_decimal_point(s)));
4116 }
4117 return true;
4118 }
4119 }
4120 return false;
4121 };
4122
4123 begin = skip_whitespaces(begin, end);
4124 end = remove_eols(begin, end);
4125 if (begin != end) {
4126 if (*begin == ';') {
4127 // Comment.
4128 begin = skip_whitespaces(++ begin, end);
4129 if (begin != end) {
4130 std::string_view comment(begin, end - begin);
4131 if (producer_detected) {
4132 if (bed_size.x == 0.0 && comment.find("strokeXoverride") != comment.npos)
4133 extract_double(comment, "strokeXoverride", bed_size.x);
4134 else if (bed_size.y == 0.0 && comment.find("strokeYoverride") != comment.npos)
4135 extract_double(comment, "strokeYoverride", bed_size.y);
4136 else if (comment.find("filamentDiameters") != comment.npos) {
4137 m_result.filament_diameters.clear();
4138 extract_floats(comment, "filamentDiameters", m_result.filament_diameters);
4139 } else if (comment.find("filamentDensities") != comment.npos) {
4140 m_result.filament_densities.clear();
4141 extract_floats(comment, "filamentDensities", m_result.filament_densities);
4142 } else if (comment.find("extruderDiameter") != comment.npos) {
4143 std::vector<float> extruder_diameters;
4144 extract_floats(comment, "extruderDiameter", extruder_diameters);
4145 m_result.filaments_count = extruder_diameters.size();
4146 }
4147 } else if (boost::starts_with(comment, "G-Code generated by Simplify3D(R)"))
4148 producer_detected = true;
4149 }
4150 } else {
4151 // Some non-empty G-code line detected, stop parsing config comments.
4152 reader.quit_parsing();
4153 }
4154 }
4155 });
4156
4157 if (m_result.filaments_count == 0)
4158 m_result.filaments_count = std::max<size_t>(1, std::min(m_result.filament_diameters.size(), m_result.filament_densities.size()));
4159
4160 if (bed_size.is_defined()) {
4161 m_result.printable_area = {
4162 { 0.0, 0.0 },
4163 { bed_size.x, 0.0 },
4164 { bed_size.x, bed_size.y },
4165 { 0.0, bed_size.y }
4166 };
4167 }
4168}
T * begin(Slic3r::Mat< N, M, T > &mat)
Definition Point.hpp:838
Vec3d pos(const Pt &p)
Definition ReprojectPointsOnMesh.hpp:16
static const char * skip_whitespaces(const char *c)
Definition Config.cpp:1257
static const char * remove_eols(const char *begin, const char *end)
Definition GCodeProcessor.cpp:3818
double string_to_double_decimal_point(const std::string_view str, size_t *pos)
Definition LocalesUtils.cpp:86

References m_parser, m_result, Slic3r::GCodeReader::quit_parsing(), Slic3r::remove_eols(), Slic3r::skip_whitespaces(), and Slic3r::string_to_double_decimal_point().

Referenced by process_file().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ apply_config_superslicer()

void Slic3r::GCodeProcessor::apply_config_superslicer ( const std::string & filename)
private
4067{
4068 DynamicPrintConfig config;
4069 config.apply(FullPrintConfig::defaults());
4071 apply_config(config);
4072}
void apply_config(const PrintConfig &config)
Definition GCodeProcessor.cpp:3113
@ EnableSilent
Definition Config.hpp:247
ConfigSubstitutions load_from_superslicer_gcode_file(const std::string &filename, DynamicPrintConfig &config, ForwardCompatibilitySubstitutionRule compatibility_rule)
Definition GCodeProcessor.cpp:4041

References Slic3r::ConfigBase::apply(), apply_config(), Slic3r::EnableSilent, and Slic3r::load_from_superslicer_gcode_file().

Referenced by process_file().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ calc_junction_acceleration()

float Slic3r::GCodeProcessor::calc_junction_acceleration ( const TimeBlock & block,
const Vec4f & junction_unit_vec,
PrintEstimatedStatistics::ETimeMode mode ) const
private
7811{
7812 float junction_acceleration = block.acceleration;
7813 for (unsigned char a = X; a <= E; ++a) {
7814 if (junction_unit_vec[a] == 0.0f)
7815 continue;
7816 const float axis_max_acceleration = get_axis_max_acceleration(mode, static_cast<Axis>(a), m_machine_config_idx);
7817 if (axis_max_acceleration > 0.0f)
7818 junction_acceleration = std::min(junction_acceleration, std::abs(axis_max_acceleration / junction_unit_vec[a]));
7819 }
7820 return junction_acceleration;
7821}
int m_machine_config_idx
Definition GCodeProcessor.hpp:1330
float get_axis_max_acceleration(PrintEstimatedStatistics::ETimeMode mode, Axis axis) const
Definition GCodeProcessor.cpp:7742
Axis
Definition libslic3r.h:140
@ E
Definition libslic3r.h:144

References Slic3r::GCodeProcessor::TimeBlock::acceleration, Slic3r::E, get_axis_max_acceleration(), m_machine_config_idx, and Slic3r::X.

Referenced by calc_vmax_junction_deviation().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ calc_vmax_junction_deviation()

float Slic3r::GCodeProcessor::calc_vmax_junction_deviation ( const TimeBlock & block,
const TimeMachine::State & prev,
const TimeMachine::State & curr,
bool has_prev_move,
PrintEstimatedStatistics::ETimeMode mode ) const
private
7827{
7828 if (m_flavor == gcfKlipper) {
7829 if (!has_prev_move || curr.enter_direction.isZero() || prev.exit_direction.isZero())
7830 return 0.0f;
7831 const TimeBlock& previous = m_time_processor.machines[static_cast<size_t>(mode)].blocks.back();
7832 double limit = std::min(sqr(double(block.feedrate_profile.cruise)), sqr(double(prev.feedrate)));
7833 const double extrude_ratio_change = std::abs(curr.axis_feedrate[E] / curr.feedrate -
7834 prev.axis_feedrate[E] / prev.feedrate);
7835 // Klipper's instantaneous_corner_velocity defaults to 1 mm/s.
7836 // It is independent of machine_max_jerk_e; custom firmware values
7837 // cannot be inferred from the slicer's jerk setting.
7838 if (extrude_ratio_change > 0.0f)
7839 limit = std::min(limit, sqr(1.0 / extrude_ratio_change));
7840 // Recover directions from the double-precision axis velocities: float
7841 // unit vectors lose the angle between nearly collinear short segments.
7842 const Vec3d prev_direction = Vec3d(prev.axis_feedrate[X], prev.axis_feedrate[Y], prev.axis_feedrate[Z]).normalized();
7843 const Vec3d curr_direction = Vec3d(curr.axis_feedrate[X], curr.axis_feedrate[Y], curr.axis_feedrate[Z]).normalized();
7844 const double cosine = std::clamp(-prev_direction.dot(curr_direction), -1.0, 1.0);
7845 const double sin_half = std::sqrt(0.5 * (1.0 - cosine));
7846 const double cos_half = std::sqrt(0.5 * (1.0 + cosine));
7847 if (sin_half < 1.0 && cos_half > 0.0) {
7848 const double radius = sin_half / (1.0 - sin_half);
7849 const double half_tan = 0.5 * sin_half / cos_half;
7850 limit = std::min({limit,
7851 radius * block.junction_deviation * block.acceleration,
7852 radius * previous.junction_deviation * previous.acceleration,
7853 half_tan * block.distance * block.acceleration,
7854 half_tan * previous.distance * previous.acceleration});
7855 }
7856 return std::sqrt(limit);
7857 }
7858 const float junction_deviation = get_junction_deviation(mode, block.acceleration);
7859 if (junction_deviation <= 0.0f)
7860 return -1.0f; // classic jerk machine, the caller keeps its own computation
7861 if (!has_prev_move)
7862 return 0.0f; // starts from rest, the planner raises this on the reverse pass
7863
7864 // Unit vectors over XYZE keep this a cosine. Scaling by 1 / XYZ distance
7865 // leaves an E term that makes extruding corners appear straighter.
7866 // Marlin normalizes over XYZE; the Klipper branch above uses XYZ only.
7867 float junction_cos_theta = (-prev.jd_unit_vec).dot(curr.jd_unit_vec);
7868 if (junction_cos_theta > 0.999999f)
7869 return 0.0f; // the path doubles back, the machine has to stop
7870 junction_cos_theta = std::max(junction_cos_theta, -0.999999f); // guards the division below
7871
7872 const float sin_theta_d2 = std::sqrt(0.5f * (1.0f - junction_cos_theta)); // always positive
7873 const Vec4f junction_vec = curr.jd_unit_vec - prev.jd_unit_vec;
7874 const float junction_vec_norm = junction_vec.norm();
7875 const Vec4f junction_unit_vec = (junction_vec_norm > 0.0f) ? Vec4f(junction_vec / junction_vec_norm)
7876 : Vec4f(0.0f, 0.0f, 0.0f, 0.0f);
7877 const float junction_acceleration = calc_junction_acceleration(block, junction_unit_vec, mode);
7878
7879 float vmax_junction_sqr = (junction_acceleration * junction_deviation * sin_theta_d2) / (1.0f - sin_theta_d2);
7880
7881 // Marlin's JD_HANDLE_SMALL_SEGMENTS: a short move through a shallow corner is treated as an arc and
7882 // capped by the centripetal acceleration it needs.
7883 if (block.distance < 1.0f && junction_cos_theta < -0.7071067812f) {
7884 // Fast acos(-t), max. error +-0.033rad. MinMax polynomial by W. Randolph Franklin:
7885 // https://wrf.ecse.rpi.edu/Research/Short_Notes/arcsin/onlyelem.html
7886 const float neg = junction_cos_theta < 0.0f ? -1.0f : 1.0f;
7887 const float t = neg * junction_cos_theta;
7888 const float asinx = 0.032843707f + t * (-1.451838349f + t * (29.66153956f + t * (-131.1123477f +
7889 t * (262.8130562f + t * (-242.7199627f + t * (84.31466202f))))));
7890 const float junction_theta = float(0.5 * M_PI) + neg * asinx; // acos(-t), bottoms out at 0.033
7891 vmax_junction_sqr = std::min(vmax_junction_sqr, (block.distance * junction_acceleration) / junction_theta);
7892 }
7893
7894 // Never faster than either of the two moves the junction joins.
7895 vmax_junction_sqr = std::min(vmax_junction_sqr, std::min(sqr(block.feedrate_profile.cruise), sqr(prev.feedrate)));
7896 return std::sqrt(vmax_junction_sqr);
7897}
#define M_PI
Definition ExtrusionSimulator.cpp:31
float get_junction_deviation(PrintEstimatedStatistics::ETimeMode mode, float acceleration) const
Definition GCodeProcessor.cpp:7787
float calc_junction_acceleration(const TimeBlock &block, const Vec4f &junction_unit_vec, PrintEstimatedStatistics::ETimeMode mode) const
Definition GCodeProcessor.cpp:7809
Eigen::Matrix< float, 4, 1, Eigen::DontAlign > Vec4f
Definition Point.hpp:66
constexpr T sqr(T x)
Definition libslic3r.h:301
T dot(const boost::geometry::model::d2::point_xy< T > &v1, const boost::geometry::model::d2::point_xy< T > &v2)
Definition ExtrusionSimulator.cpp:154
Definition GCodeProcessor.hpp:709

References Slic3r::GCodeProcessor::TimeBlock::acceleration, Slic3r::GCodeProcessor::TimeMachine::State::axis_feedrate, calc_junction_acceleration(), Slic3r::GCodeProcessor::FeedrateProfile::cruise, Slic3r::GCodeProcessor::TimeBlock::distance, Slic3r::dot(), Slic3r::E, Slic3r::GCodeProcessor::TimeMachine::State::enter_direction, Slic3r::GCodeProcessor::TimeMachine::State::exit_direction, Slic3r::GCodeProcessor::TimeMachine::State::feedrate, Slic3r::GCodeProcessor::TimeBlock::feedrate_profile, Slic3r::gcfKlipper, get_junction_deviation(), Slic3r::GCodeProcessor::TimeMachine::State::jd_unit_vec, Slic3r::GCodeProcessor::TimeBlock::junction_deviation, m_flavor, M_PI, m_time_processor, Slic3r::sqr(), Slic3r::X, Slic3r::Y, and Slic3r::Z.

Referenced by process_G1(), and process_VG1().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ calculate_time()

void Slic3r::GCodeProcessor::calculate_time ( GCodeProcessorResult & result,
size_t keep_last_n_blocks = 0,
float additional_time = 0.0f,
EMoveType target_move_type = EMoveType::Noop,
bool is_final = false )
private
8053{
8054 // calculate times
8055 std::vector<TimeMachine::ActualSpeedMove> actual_speed_moves;
8056 for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
8057 TimeMachine& machine = m_time_processor.machines[i];
8058 machine.klipper = m_flavor == gcfKlipper;
8059 machine.calculate_time(m_result, static_cast<PrintEstimatedStatistics::ETimeMode>(i), keep_last_n_blocks, additional_time, target_move_type, is_final);
8061 actual_speed_moves = std::move(machine.actual_speed_moves);
8062 }
8063
8064 // actual_speed_moves holds, per block in move order, the moves to insert before the block's move and then an
8065 // entry without a position for that move; positioned entries after the last such entry are dropped.
8066 std::vector<GCodeProcessorResult::MoveVertex>& moves = result.moves;
8067 size_t inserted_actual_speed_moves_count = 0;
8068 size_t kept = 0;
8069 size_t group_start = 0;
8070 for (size_t i = 0; i < actual_speed_moves.size(); ++i) {
8071 if (actual_speed_moves[i].position.has_value())
8072 continue;
8073 const unsigned int move_id = actual_speed_moves[i].move_id;
8074 // A VG1 block has no move of its own, so its id can fall behind the previous block's or point past the list.
8075 if (move_id < moves.size() && (kept == 0 || move_id > actual_speed_moves[kept - 1].move_id)) {
8076 inserted_actual_speed_moves_count += i - group_start;
8077 moves[move_id].actual_feedrate = actual_speed_moves[i].actual_feedrate;
8078 // A seam vertex right after a block's move shares its actual speed.
8079 if (move_id + 1 < moves.size() && moves[move_id + 1].type == EMoveType::Seam)
8080 moves[move_id + 1].actual_feedrate = actual_speed_moves[i].actual_feedrate;
8081 for (size_t j = group_start; j <= i; ++j, ++kept)
8082 if (kept != j)
8083 actual_speed_moves[kept] = std::move(actual_speed_moves[j]);
8084 }
8085 group_start = i + 1;
8086 }
8087 actual_speed_moves.erase(actual_speed_moves.begin() + kept, actual_speed_moves.end());
8088
8089 // Walks the blocks back to front, so each shifted move is moved once, into its final slot.
8090 size_t read = moves.size(); // one past the last move not yet placed
8091 moves.resize(moves.size() + inserted_actual_speed_moves_count);
8092 size_t write = moves.size(); // one past the last free slot
8093 m_actual_speed_id_map.clear();
8094 size_t entry = actual_speed_moves.size();
8095 while (entry > 0) {
8096 const unsigned int block_id = actual_speed_moves[--entry].move_id;
8097 assert(block_id < read);
8098 while (read > block_id + 1)
8099 moves[--write] = moves[--read];
8100 const GCodeProcessorResult::MoveVertex block_move = moves[--read];
8101 moves[--write] = block_move;
8102 m_actual_speed_id_map.emplace_back(block_id, (unsigned int)write);
8103 for (; entry > 0 && actual_speed_moves[entry - 1].position.has_value(); --entry) {
8104 const TimeMachine::ActualSpeedMove& it = actual_speed_moves[entry - 1];
8105 GCodeProcessorResult::MoveVertex new_move = block_move;
8106 new_move.time = { 0.0f, 0.0f };
8107 new_move.position = *it.position;
8108 new_move.actual_feedrate = it.actual_feedrate;
8109 new_move.delta_extruder = *it.delta_extruder;
8110 new_move.feedrate = *it.feedrate;
8111 new_move.width = *it.width;
8112 new_move.height = *it.height;
8113 new_move.mm3_per_mm = *it.mm3_per_mm;
8114 new_move.fan_speed = *it.fan_speed;
8115 new_move.temperature = *it.temperature;
8116 new_move.internal_only = true;
8117 moves[--write] = new_move;
8118 }
8119 }
8120 assert(read == write);
8121
8122 // synchronize blocks' move_ids with after moves for actual speed insertion
8123 std::reverse(m_actual_speed_id_map.begin(), m_actual_speed_id_map.end());
8124 for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
8125 for (GCodeProcessor::TimeBlock& block : m_time_processor.machines[i].blocks) {
8126 auto it = std::lower_bound(m_actual_speed_id_map.begin(), m_actual_speed_id_map.end(), block.move_id,
8127 [](const std::pair<unsigned int, unsigned int>& entry, unsigned int id) { return entry.first < id; });
8128 block.move_id = (it != m_actual_speed_id_map.end() && it->first == block.move_id) ?
8129 it->second : block.move_id + (unsigned int)inserted_actual_speed_moves_count;
8130 }
8131 }
8133}
GCodeProcessorResult & result()
Definition GCodeProcessor.hpp:1435
std::vector< std::pair< unsigned int, unsigned int > > m_actual_speed_id_map
Definition GCodeProcessor.hpp:1376
void read(const nlohmann::json &j, const char *k, T &out)
Definition TextureDisplacement.cpp:5749
@ Seam
Definition GCodeProcessor.hpp:57
Definition GCodeProcessor.hpp:753
ETimeMode
Definition GCodeProcessor.hpp:88

References Slic3r::GCodeProcessor::TimeMachine::ActualSpeedMove::actual_feedrate, Slic3r::GCodeProcessorResult::MoveVertex::actual_feedrate, Slic3r::GCodeProcessor::TimeMachine::actual_speed_moves, Slic3r::GCodeProcessor::TimeMachine::calculate_time(), Slic3r::PrintEstimatedStatistics::Count, Slic3r::GCodeProcessor::TimeMachine::ActualSpeedMove::delta_extruder, Slic3r::GCodeProcessorResult::MoveVertex::delta_extruder, Slic3r::GCodeProcessor::TimeMachine::ActualSpeedMove::fan_speed, Slic3r::GCodeProcessorResult::MoveVertex::fan_speed, Slic3r::GCodeProcessor::TimeMachine::ActualSpeedMove::feedrate, Slic3r::GCodeProcessorResult::MoveVertex::feedrate, Slic3r::gcfKlipper, Slic3r::GCodeProcessor::TimeMachine::ActualSpeedMove::height, Slic3r::GCodeProcessorResult::MoveVertex::height, Slic3r::GCodeProcessorResult::MoveVertex::internal_only, Slic3r::GCodeProcessor::TimeMachine::klipper, m_actual_speed_id_map, m_flavor, m_options_z_corrector, m_result, m_time_processor, Slic3r::GCodeProcessor::TimeMachine::ActualSpeedMove::mm3_per_mm, Slic3r::GCodeProcessorResult::MoveVertex::mm3_per_mm, Slic3r::GCodeProcessorResult::moves, Slic3r::PrintEstimatedStatistics::Normal, Slic3r::GCodeProcessor::TimeMachine::ActualSpeedMove::position, Slic3r::GCodeProcessorResult::MoveVertex::position, result(), Slic3r::Seam, Slic3r::GCodeProcessor::TimeMachine::ActualSpeedMove::temperature, Slic3r::GCodeProcessorResult::MoveVertex::temperature, Slic3r::GCodeProcessorResult::MoveVertex::time, Slic3r::GCodeProcessor::TimeMachine::ActualSpeedMove::width, and Slic3r::GCodeProcessorResult::MoveVertex::width.

Referenced by finalize(), process_G1(), and simulate_st_synchronize().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ check_multi_extruder_gcode_valid()

bool Slic3r::GCodeProcessor::check_multi_extruder_gcode_valid ( const int extruder_size,
const Pointfs plate_printable_area,
const double plate_printable_height,
const Pointfs wrapping_exclude_area,
const std::vector< Polygons > & unprintable_areas,
const std::vector< double > & printable_heights,
const std::vector< int > & filament_map,
const std::vector< std::set< int > > & unprintable_filament_types )
2936{
2937 m_result.limit_filament_maps.clear();
2938 m_result.gcode_check_result.reset();// including both single extruder machine printable area check result and multi extruder result
2939 Polygon plate_printable_poly = Polygon::new_scale(plate_printable_area);
2940 Polygon wrapping_exclude_poly = Polygon::new_scale(wrapping_exclude_area);
2941
2942 m_result.limit_filament_maps.resize(filament_map.size(), 0);
2943
2944 auto to_2d = [](const Vec3d &pos) -> Point {
2945 Point ps(scale_(pos.x()), scale_(pos.y()));
2946 return ps;
2947 };
2948
2949 // Belt-printer post-gcode shear/scale/post_remap is applied as the final
2950 // step of BeltKinematics::to_machine, so MoveVertex.position is
2951 // in the printer's machine frame. Undo it here so the XY area check
2952 // operates in the build-volume frame that printable_area is defined in
2953 // (the height checks below are skipped on belt printers). For non-belt printers
2954 // (is_active() == false) apply_inverse is identity and behaviour is
2955 // unchanged from before.
2956 const bool machine_frame_active = m_machine_frame_transform.is_active();
2957 auto compare_pos = [&](const GCodeProcessorResult::MoveVertex &move) -> Vec3d {
2958 Vec3d pos = move.position.cast<double>();
2959 if (!machine_frame_active)
2960 return pos;
2961 Vec3d extruder_off = Vec3d::Zero();
2962 if (size_t(move.extruder_id) < m_extruder_offsets.size())
2963 extruder_off = m_extruder_offsets[move.extruder_id].cast<double>();
2964 // Strip plate + extruder offsets to recover the raw machine-frame
2965 // coordinate that was emitted into the G-code (see store_move_vertex).
2966 Vec3d machine(pos.x() - m_x_offset - extruder_off.x(),
2967 pos.y() - m_y_offset - extruder_off.y(),
2968 pos.z() - extruder_off.z() + m_z_offset);
2969 Vec3d build = m_machine_frame_transform.apply_inverse(machine);
2970 // Re-apply plate offset so the result matches plate_printable_poly,
2971 // which is translated by plate_offset below.
2972 return Vec3d(build.x() + m_x_offset, build.y() + m_y_offset, build.z());
2973 };
2974
2975 struct GCodePosInfo
2976 {
2977 Points pos;
2978 Points pos_custom;
2979 float max_print_z;
2980 float max_print_z_custom;
2981 };
2982 std::map<int, std::map<int, GCodePosInfo>> gcode_path_pos; // object_id, filament_id, pos
2983 for (const GCodeProcessorResult::MoveVertex &move : m_result.moves) {
2984 // sometimes, the start line extrude was outside the edge of plate a little, this is allowed, so do not include into the gcode_path_pos
2985 if (move.type == EMoveType::Extrude /* && move.extrusion_role != ExtrusionRole::erFlush || move.type == EMoveType::Travel*/) {
2986 const Vec3d cp = compare_pos(move);
2987 // For belt printers we read Z from the inverse-transformed position
2988 // (post-origin-snap, pre-machine-frame). Otherwise keep the
2989 // original print_z source (the slicer's layer-Z comment) so
2990 // non-belt behaviour is bit-for-bit unchanged.
2991 const float z_for_height = machine_frame_active ? float(cp.z()) : move.print_z;
2992 if (move.extrusion_role == ExtrusionRole::erCustom) {
2993 gcode_path_pos[move.object_label_id][int(move.extruder_id)].pos_custom.emplace_back(to_2d(cp));
2994 gcode_path_pos[move.object_label_id][int(move.extruder_id)].max_print_z_custom =
2995 std::max(gcode_path_pos[move.object_label_id][int(move.extruder_id)].max_print_z_custom, z_for_height);
2996 } else {
2997 gcode_path_pos[move.object_label_id][int(move.extruder_id)].pos.emplace_back(to_2d(cp));
2998 gcode_path_pos[move.object_label_id][int(move.extruder_id)].max_print_z = std::max(gcode_path_pos[move.object_label_id][int(move.extruder_id)].max_print_z,
2999 z_for_height);
3000 }
3001 }
3002 }
3003
3004 bool valid = true;
3005 Point plate_offset = Point(scale_(m_x_offset), scale_(m_y_offset));
3006 plate_printable_poly.translate(plate_offset);
3007 //wrapping_exclude_poly.translate(plate_offset);
3008 BoundingBox plate_printable_bbox = plate_printable_poly.bounding_box();
3009 if (plate_printable_poly.is_valid()) {
3010 plate_printable_bbox.offset(scale_(2.0)); // Expand the range to provide a tolerance
3011 } else
3012 plate_printable_bbox.defined = false; //when this is used, the printable area config was missing, something wrong
3013
3014 for (auto obj_iter = gcode_path_pos.begin(); obj_iter != gcode_path_pos.end(); ++obj_iter) {
3015 int object_label_id = obj_iter->first;
3016 const std::map<int, GCodePosInfo> &path_pos = obj_iter->second;
3017 for (auto iter = path_pos.begin(); iter != path_pos.end(); ++iter) {
3018 int extruder_id = filament_map[iter->first] - 1;
3019 Points iter_points;//temp points
3020 iter_points.insert(iter_points.end(), iter->second.pos.begin(), iter->second.pos.end());// put object/wipetower extrude position in
3021 Polygon path_poly(iter_points);
3022 if (path_poly.empty()) continue;
3023 BoundingBox bbox = path_poly.bounding_box();
3024 if (plate_printable_bbox.defined) {
3025 if (!plate_printable_bbox.contains(bbox)) { // out of the bed area
3026 m_result.gcode_check_result.error_code |= (1<<2);
3027 std::pair<int, int> filament_to_object_id;
3028 filament_to_object_id.first = iter->first;
3029 filament_to_object_id.second = object_label_id;
3030 m_result.gcode_check_result.print_area_error_infos[extruder_id].push_back(filament_to_object_id);
3031 valid = false;
3032 }
3033 }
3034 // Belt printers: the Z recorded here grows with belt travel (machine Z with the
3035 // frame transform, the slicing-frame Z without it), while printable_height is the
3036 // clearance above the belt; the two are not comparable, so the over-height check
3037 // is skipped, as the preview's ToolHeightOutside warning already is.
3038 // Print::validate() checks the object's height against the clearance.
3039 if ( !m_belt_printer && iter->second.max_print_z > plate_printable_height ) { //over height
3040 m_result.gcode_check_result.error_code |= (1 << 3);
3041 std::pair<int, int> filament_to_object_id;
3042 filament_to_object_id.first = iter->first;
3043 filament_to_object_id.second = object_label_id;
3044 m_result.gcode_check_result.print_height_error_infos[extruder_id].push_back(filament_to_object_id);
3045 valid = false;
3046 }
3047 // if (wrapping_exclude_poly.is_valid()) {
3048 // if (wrapping_exclude_poly.bounding_box().overlap(bbox)) { // get into the wrapping area
3049 // m_result.gcode_check_result.error_code |= (1 << 4);
3050 // std::pair<int, int> filament_to_object_id;
3051 // filament_to_object_id.first = iter->first;
3052 // filament_to_object_id.second = object_label_id;
3053 // m_result.gcode_check_result.print_area_error_infos[extruder_id].push_back(filament_to_object_id);
3054 // valid = false;
3055 // }
3056 // }
3057
3058 if (extruder_size > 1) {// in multi extruder condition
3059 /*//iter_points.insert(iter_points.end(), iter->second.pos_custom.begin(), iter->second.pos_custom.end()); // put custom extrude position in
3060 //Polygon path_poly_custom(iter_points);
3061 //BoundingBox bbox_custom = path_poly_custom.bounding_box();
3062 //bbox_custom.offset(-scale_(1.0)); // Narrow the range to provide a tolerance for the custom gcode
3063 //bbox.merge(bbox_custom); // merge the custom gcode pos with other pos*/
3064 // check printable area
3065 // Simplified use bounding_box, Accurate calculation is not efficient
3066 if ((extruder_id < unprintable_areas.size()) && !unprintable_areas[extruder_id].empty())
3067 for (Polygon poly : unprintable_areas[extruder_id]) {
3068 poly.translate(plate_offset);
3069 if (poly.bounding_box().overlap(bbox)) {
3070 m_result.gcode_check_result.error_code |= 1;
3071 std::pair<int, int> filament_to_object_id;
3072 filament_to_object_id.first = iter->first;
3073 filament_to_object_id.second = object_label_id;
3074 m_result.gcode_check_result.print_area_error_infos[extruder_id].push_back(filament_to_object_id);
3075 valid = false;
3076 }
3077 }
3078
3079 // check printable height
3080 if (!m_belt_printer && (extruder_id < printable_heights.size()) && (iter->second.max_print_z > printable_heights[extruder_id])) {
3081 m_result.gcode_check_result.error_code |= (1 << 1);
3082 std::pair<int, int> filament_to_object_id;
3083 filament_to_object_id.first = iter->first;
3084 filament_to_object_id.second = object_label_id;
3085 m_result.gcode_check_result.print_height_error_infos[extruder_id].push_back(filament_to_object_id);
3086 m_result.limit_filament_maps[iter->first] |= (1 << extruder_id);
3087 valid = false;
3088 }
3089
3090 for (int i = 0; i < unprintable_areas.size(); ++i) {
3091 for (Polygon poly : unprintable_areas[i]) {
3092 poly.translate(plate_offset);
3093 if (!poly.bounding_box().overlap(bbox)) continue;
3094
3095 m_result.limit_filament_maps[iter->first] |= (1 << i);
3096 }
3097 }
3098 }
3099 }
3100 }
3101
3102 // apply unprintable filament type result
3103 for (int extruder_id = 0; extruder_id < unprintable_filament_types.size(); ++extruder_id) {
3104 const std::set<int> &filament_ids = unprintable_filament_types[extruder_id];
3105 for (int filament_id : filament_ids) {
3106 m_result.limit_filament_maps[filament_id] |= (1 << extruder_id);
3107 }
3108 };
3109
3110 return valid;
3111}
static Polygon new_scale(const std::vector< Vec2d > &points)
Definition Polygon.hpp:38
#define scale_(val)
Definition libslic3r.h:106
void poly(std::vector< std::pair< Vec2d, Vec2d > > &out, std::initializer_list< Vec2d > p)
Definition DesignSketchTool.cpp:7751
Kernel::Point_3 Point
Definition MeshRepair.cpp:81
Eigen::Matrix< typename Derived::Scalar, 2, 1, Eigen::DontAlign > to_2d(const Eigen::MatrixBase< Derived > &ptN)
Definition Point.hpp:147
@ Extrude
Definition GCodeProcessor.hpp:64
std::vector< Point, PointsAllocator< Point > > Points
Definition Point.hpp:73
zaa_minimize_perimeter_height filament_ids((ConfigOptionStrings, filament_colour))((ConfigOptionStrings
Slic3r::Polygon Polygon
Definition Emboss.cpp:101

References Slic3r::MultiPoint::bounding_box(), Slic3r::BoundingBoxBase< PointType, APointsType >::contains(), Slic3r::BoundingBoxBase< PointType, APointsType >::defined, Slic3r::MultiPoint::empty(), Slic3r::erCustom, Slic3r::Extrude, Slic3r::GCodeProcessorResult::MoveVertex::extruder_id, Slic3r::GCodeProcessorResult::MoveVertex::extrusion_role, Slic3r::filament_ids(), Slic3r::filament_map(), Slic3r::Polygon::is_valid(), m_belt_printer, m_extruder_offsets, m_machine_frame_transform, m_result, m_x_offset, m_y_offset, m_z_offset, Slic3r::Polygon::new_scale(), Slic3r::GCodeProcessorResult::MoveVertex::object_label_id, Slic3r::BoundingBoxBase< PointType, APointsType >::offset(), Slic3r::GCodeProcessorResult::MoveVertex::print_z, scale_, Slic3r::to_2d(), Slic3r::MultiPoint::translate(), and Slic3r::GCodeProcessorResult::MoveVertex::type.

Here is the call graph for this function:

◆ configure_exclusion_volume_path_check()

void Slic3r::GCodeProcessor::configure_exclusion_volume_path_check ( const PrintConfig & config)
3933{
3934 m_exclusion_volume_path_checker.configure(config);
3935}
ExclusionVolumePathChecker m_exclusion_volume_path_checker
Definition GCodeProcessor.hpp:1235

References m_exclusion_volume_path_checker.

Referenced by Slic3r::Print::export_gcode_from_previous_file(), and Slic3r::DoExport::init_gcode_processor().

Here is the caller graph for this function:

◆ contains_reserved_tag()

bool Slic3r::GCodeProcessor::contains_reserved_tag ( const std::string & gcode,
std::string & found_tag )
static
2766{
2767 bool ret = false;
2768
2769 GCodeReader parser;
2771 parser.parse_buffer(gcode, [&ret, &found_tag, _tags](GCodeReader& parser, const GCodeReader::GCodeLine& line) {
2772 std::string comment = line.raw();
2773 if (comment.length() > 2 && comment.front() == ';') {
2774 comment = comment.substr(1);
2775 for (const std::string& s : _tags) {
2776 if (boost::starts_with(comment, s)) {
2777 ret = true;
2778 found_tag = comment;
2779 parser.quit_parsing();
2780 return;
2781 }
2782 }
2783 }
2784 });
2785
2786 return ret;
2787}
static const std::vector< std::string > Reserved_Tags_compatible
Definition GCodeProcessor.hpp:574
static bool s_IsBBLPrinter
Definition GCodeProcessor.hpp:650
static const std::vector< std::string > Reserved_Tags
Definition GCodeProcessor.hpp:573

References Slic3r::GCodeReader::parse_buffer(), Slic3r::GCodeReader::quit_parsing(), Slic3r::GCodeReader::GCodeLine::raw(), Reserved_Tags, Reserved_Tags_compatible, and s_IsBBLPrinter.

Here is the call graph for this function:

◆ contains_reserved_tags()

bool Slic3r::GCodeProcessor::contains_reserved_tags ( const std::string & gcode,
unsigned int max_count,
std::vector< std::string > & found_tag,
bool is_bbl_printer )
static
2790{
2791 max_count = std::max(max_count, 1U);
2792
2793 bool ret = false;
2794
2795 CNumericLocalesSetter locales_setter;
2796
2797 GCodeReader parser;
2798 auto& _tags = is_bbl_printer ? Reserved_Tags : Reserved_Tags_compatible;
2799 parser.parse_buffer(gcode, [&ret, &found_tag, max_count, _tags](GCodeReader& parser, const GCodeReader::GCodeLine& line) {
2800 std::string comment = line.raw();
2801 if (comment.length() > 2 && comment.front() == ';') {
2802 comment = comment.substr(1);
2803 for (const std::string& s : _tags) {
2804 if (boost::starts_with(comment, s)) {
2805 ret = true;
2806 found_tag.push_back(comment);
2807 if (found_tag.size() == max_count) {
2808 parser.quit_parsing();
2809 return;
2810 }
2811 }
2812 }
2813 }
2814 });
2815
2816 return ret;
2817}

References Slic3r::GCodeReader::parse_buffer(), Slic3r::GCodeReader::quit_parsing(), Slic3r::GCodeReader::GCodeLine::raw(), Reserved_Tags, and Reserved_Tags_compatible.

Referenced by Slic3r::DoExport::validate_custom_gcode(), and Slic3r::GUI::Tab::validate_custom_gcode().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ detect_layer_based_on_tag()

void Slic3r::GCodeProcessor::detect_layer_based_on_tag ( bool enabled)
inline

◆ detect_producer()

bool Slic3r::GCodeProcessor::detect_producer ( const std::string_view comment)
private
5144{
5145 for (const auto& [id, search_string] : Producers) {
5146 size_t pos = comment.find(search_string);
5147 if (pos != comment.npos) {
5148 m_producer = id;
5149 //BOOST_LOG_TRIVIAL(info) << "Detected gcode producer: " << search_string;
5150 return true;
5151 }
5152 }
5153 return false;
5154}
static const std::vector< std::pair< GCodeProcessor::EProducer, std::string > > Producers
Definition GCodeProcessor.hpp:1370
EProducer m_producer
Definition GCodeProcessor.hpp:1371

References m_producer, and Producers.

Referenced by process_file().

Here is the caller graph for this function:

◆ enable_machine_envelope_processing()

void Slic3r::GCodeProcessor::enable_machine_envelope_processing ( bool enabled)
inline
1431{ m_time_processor.machine_envelope_processing_enabled = enabled; }

References m_time_processor.

◆ ensure_nozzle_group_result()

void Slic3r::GCodeProcessor::ensure_nozzle_group_result ( int min_filament_count)
7148{
7150 // A grouping was already seeded from the reloaded result (initialize_from_context). Publish it
7151 // onto m_result so extract_result() carries it. (The reference relies on the streaming-export
7152 // handover for this and returns early here; the reprocess path has no such handover.)
7153 m_result.nozzle_group_result = m_nozzle_group_result;
7154 return;
7155 }
7156
7157 int filament_count = std::max(1, min_filament_count);
7158 filament_count = std::max(filament_count, static_cast<int>(m_filament_maps.size()));
7159
7160 std::vector<int> filament_map = m_filament_maps;
7161 if (filament_map.empty()) {
7162 filament_map.assign(filament_count, 0);
7163 } else if (static_cast<int>(filament_map.size()) < filament_count) {
7164 filament_map.resize(filament_count, filament_map.front());
7165 }
7166
7167 int min_value = *std::min_element(filament_map.begin(), filament_map.end());
7168 if (min_value >= 1) {
7169 for (int &value : filament_map) {
7170 value -= 1;
7171 }
7172 }
7173
7174 for (int &value : filament_map) {
7175 value = std::max(0, value);
7176 }
7177
7178 int max_extruder_id = *std::max_element(filament_map.begin(), filament_map.end());
7179 max_extruder_id = std::max(0, max_extruder_id);
7180
7182 std::vector<MultiNozzleUtils::NozzleInfo> nozzle_list;
7183 nozzle_list.reserve(static_cast<size_t>(max_extruder_id + 1));
7184 for (int extruder_id = 0; extruder_id <= max_extruder_id; ++extruder_id) {
7185 MultiNozzleUtils::NozzleInfo info;
7186 info.diameter = nozzle_diameter;
7187 info.volume_type = NozzleVolumeType::nvtStandard;
7188 info.extruder_id = extruder_id;
7189 info.group_id = extruder_id;
7190 nozzle_list.emplace_back(std::move(info));
7191 }
7192
7193 std::vector<int> filament_nozzle_map(filament_count, 0);
7194 for (int i = 0; i < filament_count; ++i) {
7196 }
7197
7198 std::vector<unsigned int> used_filaments;
7199 used_filaments.reserve(filament_count);
7200 for (int i = 0; i < filament_count; ++i) {
7201 used_filaments.push_back(static_cast<unsigned int>(i));
7202 }
7203
7205 if (result) {
7206 m_nozzle_group_result = std::make_shared<MultiNozzleUtils::LayeredNozzleGroupResult>(*result);
7207 m_result.nozzle_group_result = m_nozzle_group_result;
7208 }
7209}
static const float DEFAULT_TOOLPATH_WIDTH
Definition GCodeProcessor.cpp:81
std::shared_ptr< MultiNozzleUtils::NozzleGroupResultBase > m_nozzle_group_result
Definition GCodeProcessor.hpp:1296
static std::optional< LayeredNozzleGroupResult > create(const std::vector< int > &filament_nozzle_map, const std::vector< NozzleInfo > &nozzle_list, const std::vector< unsigned int > &used_filaments)
Definition MultiNozzleUtils.cpp:142
@ nvtStandard
Definition PrintConfig.hpp:619
zaa_minimize_perimeter_height filament_nozzle_map((ConfigOptionInts, filament_map_2))((ConfigOptionStrings
std::string format_diameter_to_str(double diameter, int precision)
Definition utils.cpp:1739

References Slic3r::MultiNozzleUtils::LayeredNozzleGroupResult::create(), DEFAULT_TOOLPATH_WIDTH, Slic3r::MultiNozzleUtils::NozzleInfo::diameter, Slic3r::MultiNozzleUtils::NozzleInfo::extruder_id, Slic3r::filament_map(), Slic3r::filament_nozzle_map(), Slic3r::format_diameter_to_str(), Slic3r::MultiNozzleUtils::NozzleInfo::group_id, m_filament_maps, m_nozzle_group_result, m_result, Slic3r::nozzle_diameter(), Slic3r::nvtStandard, result(), and Slic3r::MultiNozzleUtils::NozzleInfo::volume_type.

Referenced by apply_config().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ export_config_for_render()

DynamicConfig Slic3r::GCodeProcessor::export_config_for_render ( ) const
3824{
3825 DynamicConfig config;
3826 config.set_key_value("filament_colour", new ConfigOptionStrings(m_parser.get_config().filament_colour.values));
3827 config.set_key_value("filament_is_support", new ConfigOptionBools(m_parser.get_config().filament_is_support.values));
3828 config.set_key_value("filament_type", new ConfigOptionStrings(m_parser.get_config().filament_type.values));
3829 config.set_key_value("filament_map", new ConfigOptionInts(m_parser.get_config().filament_map.values));
3830 // The tool position readout shows coordinates with the precision the file was exported with.
3831 config.set_key_value("high_precision_gcode", new ConfigOptionBool(m_parser.get_config().high_precision_gcode.value));
3832 // += clones the options; apply() would need a definition this config does not have.
3833 config += m_belt_render_config;
3834 return config;
3835}
ConfigOptionBoolsTempl< false > ConfigOptionBools
Definition Config.hpp:2066

References m_belt_render_config, m_parser, and Slic3r::DynamicConfig::set_key_value().

Referenced by Slic3r::GUI::Plater::load_gcode().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ extract_absolute_position_on_axis()

double Slic3r::GCodeProcessor::extract_absolute_position_on_axis ( Axis axis,
const GCodeReader::GCodeLine & line,
double area_filament_cross_section )
private
8173{
8174 if (line.has(Slic3r::Axis(axis))) {
8176 if (axis == E)
8178
8179 const double lengthsScaleFactor = (m_units == EUnits::Inches) ? double(INCHES_TO_MM) : 1.0;
8180 double ret = line.precise_value(Slic3r::Axis(axis)) * lengthsScaleFactor;
8181 // if (axis == E && m_use_volumetric_e)
8182 // ret /= area_filament_cross_section;
8183 return is_relative ? m_start_position[axis] + ret : m_origin[axis] + ret;
8184 }
8185 else
8186 return m_start_position[axis];
8187}
static const float INCHES_TO_MM
Definition GCodeProcessor.cpp:84
AxisCoords m_origin
Definition GCodeProcessor.hpp:1231
EUnits m_units
Definition GCodeProcessor.hpp:1223
@ Inches
Definition GCodeProcessor.hpp:660
EPositioningType m_global_positioning_type
Definition GCodeProcessor.hpp:1224
@ Relative
Definition GCodeProcessor.hpp:666
EPositioningType m_e_local_positioning_type
Definition GCodeProcessor.hpp:1225

References Slic3r::E, Slic3r::GCodeReader::GCodeLine::has(), Inches, INCHES_TO_MM, m_e_local_positioning_type, m_global_positioning_type, m_origin, m_start_position, m_units, Slic3r::GCodeReader::GCodeLine::precise_value(), and Relative.

Referenced by process_G1(), and process_G2_G3().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ extract_result()

GCodeProcessorResult && Slic3r::GCodeProcessor::extract_result ( )
inline
1436{ return std::move(m_result); }

References m_result.

Referenced by Slic3r::Print::export_gcode_from_previous_file(), and Slic3r::GUI::Plater::load_gcode().

Here is the caller graph for this function:

◆ finalize()

void Slic3r::GCodeProcessor::finalize ( bool post_process)
3967{
3968 m_result.z_offset = m_z_offset;
3970
3971 // update width/height of wipe moves
3972 for (GCodeProcessorResult::MoveVertex& move : m_result.moves) {
3973 if (move.type == EMoveType::Wipe) {
3974 move.width = Wipe_Width;
3975 move.height = Wipe_Height;
3976 }
3977 }
3978
3979 // Orca: final pass -- also drains any filament-change delay still buffered because
3980 // calculate_time early-returns with fewer than two queued blocks (see calculate_time).
3981 calculate_time(m_result, 0, 0.0f, EMoveType::Noop, /*is_final=*/true);
3982
3983 // process the time blocks
3984 for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
3985 TimeMachine& machine = m_time_processor.machines[i];
3986 TimeMachine::CustomGCodeTime& gcode_time = machine.gcode_time;
3987 if (gcode_time.needed && gcode_time.cache != 0.0f)
3988 gcode_time.times.push_back({ CustomGCode::ColorChange, gcode_time.cache });
3989 }
3990
3991 m_used_filaments.process_caches(this);
3992
3994
3996
3997 if (post_process){
3999 // Additive pre-heat/pre-cool injection second pass. Gated on m_enable_pre_heating so the
4000 // byte-frozen fleet (X1/P1/A1/H2S) never enters it. When the injector produces no lines the
4001 // InsertedLinesMap is empty, so this is a byte-for-byte identity rewrite; it exercises the
4002 // merge/offset machinery on the multi-nozzle fleet (H2D/X2D/H2D-Pro/H2C).
4005 }
4007 //BBS: update slice warning
4009}
float get_first_layer_time(PrintEstimatedStatistics::ETimeMode mode) const
Definition GCodeProcessor.cpp:4074
void update_estimated_times_stats()
Definition GCodeProcessor.cpp:8148
void run_second_pass_injection()
Definition GCodeProcessor.cpp:1960
void update_slice_warnings()
Definition GCodeProcessor.cpp:8190
void calculate_time(GCodeProcessorResult &result, size_t keep_last_n_blocks=0, float additional_time=0.0f, EMoveType target_move_type=EMoveType::Noop, bool is_final=false)
Definition GCodeProcessor.cpp:8052
void update_exclusion_volume_path_check_result()
Definition GCodeProcessor.cpp:3945
static const float Wipe_Height
Definition GCodeProcessor.hpp:648
static const float Wipe_Width
Definition GCodeProcessor.hpp:647
void finalize_object_masses()
Definition GCodeProcessor.cpp:7651
void run_post_process()
Definition GCodeProcessor.cpp:1167
UsedFilaments m_used_filaments
Definition GCodeProcessor.hpp:1377
@ ColorChange
Definition CustomGCode.hpp:19
@ Noop
Definition GCodeProcessor.hpp:54
@ Wipe
Definition GCodeProcessor.hpp:63
zaa_minimize_perimeter_height post_process((ConfigOptionStrings, slicing_pipeline_plugin))((ConfigOptionString
std::vector< std::pair< CustomGCode::Type, float > > times
Definition GCodeProcessor.hpp:778

References Slic3r::GCodeProcessor::TimeMachine::CustomGCodeTime::cache, calculate_time(), Slic3r::CustomGCode::ColorChange, Slic3r::PrintEstimatedStatistics::Count, finalize_object_masses(), Slic3r::GCodeProcessor::TimeMachine::gcode_time, get_first_layer_time(), Slic3r::GCodeProcessorResult::MoveVertex::height, m_enable_pre_heating, m_result, m_time_processor, m_used_filaments, m_z_offset, Slic3r::GCodeProcessor::TimeMachine::CustomGCodeTime::needed, Slic3r::Noop, Slic3r::PrintEstimatedStatistics::Normal, Slic3r::post_process(), run_post_process(), run_second_pass_injection(), Slic3r::GCodeProcessor::TimeMachine::CustomGCodeTime::times, Slic3r::GCodeProcessorResult::MoveVertex::type, update_estimated_times_stats(), update_exclusion_volume_path_check_result(), update_slice_warnings(), Slic3r::GCodeProcessorResult::MoveVertex::width, Slic3r::Wipe, Wipe_Height, and Wipe_Width.

Referenced by process_file().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ finalize_object_masses()

void Slic3r::GCodeProcessor::finalize_object_masses ( )
private
7652{
7653 const auto accumulate = [](GCodeProcessorResult::ObjectMass &object) {
7654 for (size_t i = 1; i < object.printed_up_to_layer.size(); ++i)
7655 object.printed_up_to_layer[i].add(object.printed_up_to_layer[i - 1]);
7656 };
7657 accumulate(m_result.plate_mass);
7658 for (GCodeProcessorResult::ObjectMass &object : m_result.object_masses)
7659 accumulate(object);
7660 for (GCodeProcessorResult::ObjectMass &body : m_result.body_masses)
7661 accumulate(body);
7662 for (GCodeProcessorResult::ObjectMass &support : m_result.support_masses)
7663 accumulate(support);
7664}
T accumulate(const EP &ep, I from, I to, const T &init, AccessFn &&accessfn, size_t granularity=1)
Definition Execution.hpp:99

References m_result.

Referenced by finalize().

Here is the caller graph for this function:

◆ get_acceleration()

float Slic3r::GCodeProcessor::get_acceleration ( PrintEstimatedStatistics::ETimeMode mode) const
private
7960{
7961 size_t id = static_cast<size_t>(mode);
7962 return (id < m_time_processor.machines.size()) ? m_time_processor.machines[id].acceleration : DEFAULT_ACCELERATION;
7963}

References DEFAULT_ACCELERATION, Slic3r::GCodeProcessorResult::id, and m_time_processor.

Referenced by get_axis_max_jerk_with_jd(), get_axis_max_jerk_with_jd(), process_G1(), process_VG1(), and store_move_vertex().

Here is the caller graph for this function:

◆ get_axis_max_acceleration() [1/2]

float Slic3r::GCodeProcessor::get_axis_max_acceleration ( PrintEstimatedStatistics::ETimeMode mode,
Axis axis ) const
private
7743{
7744 return get_axis_max_acceleration(mode, axis, 0);
7745}

References get_axis_max_acceleration().

Referenced by calc_junction_acceleration(), get_axis_max_acceleration(), get_axis_max_jerk_with_jd(), process_G1(), and process_VG1().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_axis_max_acceleration() [2/2]

float Slic3r::GCodeProcessor::get_axis_max_acceleration ( PrintEstimatedStatistics::ETimeMode mode,
Axis axis,
int machine_idx ) const
private
7748{
7749 const size_t pos = static_cast<size_t>(machine_idx) * 2 + static_cast<size_t>(mode);
7750 switch (axis)
7751 {
7752 case X: { return get_option_value(m_time_processor.machine_limits.machine_max_acceleration_x, pos); }
7753 case Y: { return get_option_value(m_time_processor.machine_limits.machine_max_acceleration_y, pos); }
7754 case Z: { return get_option_value(m_time_processor.machine_limits.machine_max_acceleration_z, pos); }
7755 case E: { return get_option_value(m_time_processor.machine_limits.machine_max_acceleration_e, pos); }
7756 default: { return 0.0f; }
7757 }
7758}

References Slic3r::E, Slic3r::get_option_value(), m_time_processor, Slic3r::X, Slic3r::Y, and Slic3r::Z.

Here is the call graph for this function:

◆ get_axis_max_feedrate() [1/2]

float Slic3r::GCodeProcessor::get_axis_max_feedrate ( PrintEstimatedStatistics::ETimeMode mode,
Axis axis ) const
private
7725{
7726 return get_axis_max_feedrate(mode, axis, 0);
7727}
float get_axis_max_feedrate(PrintEstimatedStatistics::ETimeMode mode, Axis axis) const
Definition GCodeProcessor.cpp:7724

References get_axis_max_feedrate().

Referenced by get_axis_max_feedrate(), process_G1(), and process_VG1().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_axis_max_feedrate() [2/2]

float Slic3r::GCodeProcessor::get_axis_max_feedrate ( PrintEstimatedStatistics::ETimeMode mode,
Axis axis,
int machine_idx ) const
private
7730{
7731 const size_t pos = static_cast<size_t>(machine_idx) * 2 + static_cast<size_t>(mode);
7732 switch (axis)
7733 {
7734 case X: { return get_option_value(m_time_processor.machine_limits.machine_max_speed_x, pos); }
7735 case Y: { return get_option_value(m_time_processor.machine_limits.machine_max_speed_y, pos); }
7736 case Z: { return get_option_value(m_time_processor.machine_limits.machine_max_speed_z, pos); }
7737 case E: { return get_option_value(m_time_processor.machine_limits.machine_max_speed_e, pos); }
7738 default: { return 0.0f; }
7739 }
7740}

References Slic3r::E, Slic3r::get_option_value(), m_time_processor, Slic3r::X, Slic3r::Y, and Slic3r::Z.

Here is the call graph for this function:

◆ get_axis_max_jerk()

float Slic3r::GCodeProcessor::get_axis_max_jerk ( PrintEstimatedStatistics::ETimeMode mode,
Axis axis ) const
private
7900{
7901 const size_t id = static_cast<size_t>(mode);
7902 const float jd = get_option_value(m_time_processor.machine_limits.machine_max_junction_deviation, id);
7903 if (m_flavor == gcfMarlinFirmware && jd > 0.0f) {
7904 return get_axis_max_jerk_with_jd(mode, axis);
7905 }
7906
7907 switch (axis)
7908 {
7909 case X: { return get_option_value(m_time_processor.machine_limits.machine_max_jerk_x, id); }
7910 case Y: { return get_option_value(m_time_processor.machine_limits.machine_max_jerk_y, id); }
7911 case Z: { return get_option_value(m_time_processor.machine_limits.machine_max_jerk_z, id); }
7912 case E: { return get_option_value(m_time_processor.machine_limits.machine_max_jerk_e, id); }
7913 default: { return 0.0f; }
7914 }
7915}
float get_axis_max_jerk_with_jd(PrintEstimatedStatistics::ETimeMode mode, Axis axis, float acceleration) const
Definition GCodeProcessor.cpp:7760

References Slic3r::E, Slic3r::gcfMarlinFirmware, get_axis_max_jerk_with_jd(), Slic3r::get_option_value(), m_flavor, m_time_processor, Slic3r::X, Slic3r::Y, and Slic3r::Z.

Referenced by process_G1(), process_VG1(), and store_move_vertex().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_axis_max_jerk_with_jd() [1/2]

float Slic3r::GCodeProcessor::get_axis_max_jerk_with_jd ( PrintEstimatedStatistics::ETimeMode mode,
Axis axis ) const
private
7783{
7784 return get_axis_max_jerk_with_jd(mode, axis, get_acceleration(mode));
7785}
float get_acceleration(PrintEstimatedStatistics::ETimeMode mode) const
Definition GCodeProcessor.cpp:7959

References get_acceleration(), and get_axis_max_jerk_with_jd().

Here is the call graph for this function:

◆ get_axis_max_jerk_with_jd() [2/2]

float Slic3r::GCodeProcessor::get_axis_max_jerk_with_jd ( PrintEstimatedStatistics::ETimeMode mode,
Axis axis,
float acceleration ) const
private
7761{
7762 if (axis != X && axis != Y && axis != Z && axis != E)
7763 return 0.0f;
7764
7765 const size_t id = static_cast<size_t>(mode);
7766 const float jd = get_option_value(m_time_processor.machine_limits.machine_max_junction_deviation, id);
7767 if (jd <= 0.0f)
7768 return 0.0f;
7769
7770 const float axis_max_acc = get_axis_max_acceleration(mode, axis);
7771 float effective_acc = acceleration;
7772 if (effective_acc <= 0.0f)
7773 effective_acc = get_acceleration(mode);
7774 if (axis_max_acc > 0.0f)
7775 effective_acc = effective_acc > 0.0f ? std::min(effective_acc, axis_max_acc) : axis_max_acc;
7776 if (effective_acc <= 0.0f)
7777 return 0.0f;
7778
7779 return std::sqrt(jd * effective_acc * 2.5f);
7780}

References Slic3r::E, get_acceleration(), get_axis_max_acceleration(), Slic3r::get_option_value(), m_time_processor, Slic3r::X, Slic3r::Y, and Slic3r::Z.

Referenced by get_axis_max_jerk(), get_axis_max_jerk_with_jd(), get_xyz_max_jerk(), and store_move_vertex().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_current_position()

GCodeProcessor::PositionState Slic3r::GCodeProcessor::get_current_position ( ) const
3938{
3939 PositionState state;
3941 state.axis_known = m_axis_position_known;
3942 return state;
3943}
std::array< bool, 3 > m_axis_position_known
Definition GCodeProcessor.hpp:1232
Definition GCodeProcessor.hpp:1386
Vec3d position
Definition GCodeProcessor.hpp:1387

References Slic3r::GCodeProcessor::PositionState::axis_known, m_axis_position_known, m_end_position, Slic3r::GCodeProcessor::PositionState::position, Slic3r::X, Slic3r::Y, and Slic3r::Z.

◆ get_custom_gcode_times()

std::vector< std::pair< CustomGCode::Type, std::pair< float, float > > > Slic3r::GCodeProcessor::get_custom_gcode_times ( PrintEstimatedStatistics::ETimeMode mode,
bool include_remaining ) const
4027{
4028 std::vector<std::pair<CustomGCode::Type, std::pair<float, float>>> ret;
4030 const TimeMachine& machine = m_time_processor.machines[static_cast<size_t>(mode)];
4031 float total_time = 0.0f;
4032 for (const auto& [type, time] : machine.gcode_time.times) {
4033 float remaining = include_remaining ? machine.time - total_time : 0.0f;
4034 ret.push_back({ type, { time, remaining } });
4035 total_time += time;
4036 }
4037 }
4038 return ret;
4039}

References Slic3r::PrintEstimatedStatistics::Count, Slic3r::GCodeProcessor::TimeMachine::gcode_time, m_time_processor, Slic3r::GCodeProcessor::TimeMachine::time, and Slic3r::GCodeProcessor::TimeMachine::CustomGCodeTime::times.

Referenced by update_estimated_times_stats().

Here is the caller graph for this function:

◆ get_extruder_change_time()

float Slic3r::GCodeProcessor::get_extruder_change_time ( size_t extruder_id)
private
8004{
8005 //TODO: all extruder has the same value ?
8006 return m_time_processor.machine_tool_change_time;
8007}

References m_time_processor.

Referenced by process_filament_change(), and process_filament_change().

Here is the caller graph for this function:

◆ get_extruder_id()

int Slic3r::GCodeProcessor::get_extruder_id ( bool force_initialize = true) const
private
8320{
8321 if (m_extruder_id == (unsigned char)(-1))
8322 return force_initialize ? 0 : -1;
8323 return static_cast<int>(m_extruder_id);
8324}
unsigned char m_extruder_id
Definition GCodeProcessor.hpp:1327

References m_extruder_id.

Referenced by get_filament_id(), get_last_filament_id(), get_machine_config_idx(), process_filament_change(), process_filament_change(), process_filaments(), process_G1(), process_M1020(), process_T(), and process_VG1().

Here is the caller graph for this function:

◆ get_filament_id()

int Slic3r::GCodeProcessor::get_filament_id ( bool force_initialize = true) const
private
8296{
8297 int extruder_id = get_extruder_id(force_initialize);
8298 if (extruder_id == -1)
8299 return force_initialize ? 0 : -1;
8300
8301 if (m_filament_id[extruder_id] == (unsigned char)(-1))
8302 return force_initialize ? 0 : -1;
8303
8304 return static_cast<int>(m_filament_id[extruder_id]);
8305}
int get_extruder_id(bool force_initialize=true) const
Definition GCodeProcessor.cpp:8319
std::vector< unsigned char > m_filament_id
Definition GCodeProcessor.hpp:1326

References get_extruder_id(), and m_filament_id.

Referenced by process_elegoo_M6211(), process_filament_change(), process_filament_change(), process_G1(), process_G2_G3(), process_M1020(), process_M104(), process_M109(), process_M702(), Slic3r::GCodeProcessor::UsedFilaments::process_model_cache(), Slic3r::GCodeProcessor::UsedFilaments::process_role_cache(), Slic3r::GCodeProcessor::UsedFilaments::process_support_cache(), process_T(), process_tags(), Slic3r::GCodeProcessor::UsedFilaments::process_total_volume_cache(), process_VG1(), Slic3r::GCodeProcessor::UsedFilaments::process_wipe_tower_cache(), and store_move_vertex().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_filament_load_time()

float Slic3r::GCodeProcessor::get_filament_load_time ( size_t extruder_id)
private
7992{
7993 //BBS: change load time to machine config and all extruder has same value
7994 return m_time_processor.extruder_unloaded ? 0.0f : m_time_processor.filament_load_times;
7995}

References m_time_processor.

Referenced by process_filament_change(), and process_filament_change().

Here is the caller graph for this function:

◆ get_filament_unload_time()

float Slic3r::GCodeProcessor::get_filament_unload_time ( size_t extruder_id)
private
7998{
7999 //BBS: change unload time to machine config and all extruder has same value
8000 return m_time_processor.extruder_unloaded ? 0.0f : m_time_processor.filament_unload_times;
8001}

References m_time_processor.

Referenced by process_filament_change(), process_filament_change(), and process_M702().

Here is the caller graph for this function:

◆ get_filament_vitrification_temperature()

int Slic3r::GCodeProcessor::get_filament_vitrification_temperature ( size_t extrude_id)
private
8011{
8012 if (extrude_id < m_result.filament_vitrification_temperature.size())
8013 return m_result.filament_vitrification_temperature[extrude_id];
8014 else
8015 return 0;
8016}

References m_result.

Referenced by update_slice_warnings().

Here is the caller graph for this function:

◆ get_first_layer_time()

float Slic3r::GCodeProcessor::get_first_layer_time ( PrintEstimatedStatistics::ETimeMode mode) const
4075{
4076 return (mode < PrintEstimatedStatistics::ETimeMode::Count) ? m_time_processor.machines[static_cast<size_t>(mode)].first_layer_time : 0.0f;
4077}

References Slic3r::PrintEstimatedStatistics::Count, and m_time_processor.

Referenced by finalize().

Here is the caller graph for this function:

◆ get_gcode_last_filament()

int Slic3r::GCodeProcessor::get_gcode_last_filament ( const std::string & gcode_str)
static
4222{
4223 int str_size = gcode_str.size();
4224 int start_index = 0;
4225 int end_index = 0;
4226 int out_filament = -1;
4227 while (end_index < str_size) {
4228 if (gcode_str[end_index] != '\n') {
4229 end_index++;
4230 continue;
4231 }
4232
4233 if (end_index > start_index) {
4234 std::string line_str = gcode_str.substr(start_index, end_index - start_index);
4235 line_str.erase(0, line_str.find_first_not_of(" "));
4236 line_str.erase(line_str.find_last_not_of(" ") + 1);
4237 if (line_str.empty() || line_str[0] != 'T') {
4238 start_index = end_index + 1;
4239 end_index = start_index;
4240 continue;
4241 }
4242
4243 int out = -1;
4244 if (parse_number(line_str.substr(1), out) && out >= 0 && out < 255)
4245 out_filament = out;
4246 }
4247
4248 start_index = end_index + 1;
4249 end_index = start_index;
4250 }
4251
4252 return out_filament;
4253}
bool parse_number(const std::string_view sv, int &out)
Definition FanMover.cpp:263

References Slic3r::parse_number().

Referenced by Slic3r::GCode::_do_export().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_junction_deviation()

float Slic3r::GCodeProcessor::get_junction_deviation ( PrintEstimatedStatistics::ETimeMode mode,
float acceleration ) const
private
7788{
7789 const size_t id = static_cast<size_t>(mode);
7790
7791 // Klipper derives junction deviation from the live toolhead acceleration,
7792 // before a move is constrained by Z or extruder limits.
7793 if (m_flavor == gcfKlipper) {
7794 // machine_max_jerk_x holds the square corner velocity; process_SET_VELOCITY_LIMIT() writes it.
7795 const float scv = get_option_value(m_time_processor.machine_limits.machine_max_jerk_x, id);
7796 acceleration = m_time_processor.machines[id].acceleration;
7797 if (scv <= 0.0f || acceleration <= 0.0f)
7798 return 0.0f;
7799 return sqr(scv) * (std::sqrt(2.0f) - 1.0f) / acceleration;
7800 }
7801
7802 // Marlin 2 plans with junction deviation only when M205 J > 0; classic jerk leaves it at 0.
7804 return get_option_value(m_time_processor.machine_limits.machine_max_junction_deviation, id);
7805
7806 return 0.0f;
7807}

References Slic3r::gcfKlipper, Slic3r::gcfMarlinFirmware, Slic3r::get_option_value(), Slic3r::GCodeProcessorResult::id, m_flavor, m_time_processor, and Slic3r::sqr().

Referenced by calc_vmax_junction_deviation(), and process_G1().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_last_filament_id()

int Slic3r::GCodeProcessor::get_last_filament_id ( bool force_initialize = true) const
private
8308{
8309 int extruder_id = get_extruder_id(force_initialize);
8310 if (extruder_id == -1)
8311 return force_initialize ? 0 : -1;
8312
8313 if (m_last_filament_id[extruder_id] == (unsigned char)(-1))
8314 return force_initialize ? 0 : -1;
8315
8316 return static_cast<int>(m_last_filament_id[extruder_id]);
8317}
std::vector< unsigned char > m_last_filament_id
Definition GCodeProcessor.hpp:1325

References get_extruder_id(), and m_last_filament_id.

Referenced by process_G1(), and process_VG1().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_last_position_from_gcode()

bool Slic3r::GCodeProcessor::get_last_position_from_gcode ( const std::string & gcode_str,
Vec3f & pos )
static
4311{
4312 int str_size = gcode_str.size();
4313 int start_index = 0;
4314 int end_index = 0;
4315 bool is_z_changed = false;
4316 while (end_index < str_size) {
4317 // find a full line
4318 if (gcode_str[end_index] != '\n') {
4319 end_index++;
4320 continue;
4321 }
4322 // parse the line
4323 if (end_index > start_index) {
4324 std::string line_str = gcode_str.substr(start_index, end_index - start_index);
4325 line_str.erase(0, line_str.find_first_not_of(" "));
4326 line_str.erase(line_str.find_last_not_of(";") + 1);
4327 line_str.erase(line_str.find_last_not_of(" ") + 1);
4328
4329 // command which may have z movement
4330 if (line_str.size() > 5 && (line_str.find("G0 ") == 0 || line_str.find("G1 ") == 0 || line_str.find("G2 ") == 0 || line_str.find("G3 ") == 0)) {
4331 {
4332 float &x = pos.x();
4333 auto z_pos = line_str.find(" X");
4334 float temp_z = 0;
4335 if (z_pos != line_str.npos && z_pos + 2 < line_str.size()) {
4336 // Try to parse the numeric value.
4337 std::string z_sub = line_str.substr(z_pos + 2);
4338 char *c = &z_sub[0];
4339 char *end = c + sizeof(z_sub.c_str());
4340
4341 auto is_end_of_word = [](char c) { return c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == 0 || c == ';'; };
4342
4343 auto [pend, ec] = fast_float::from_chars(c, end, temp_z);
4344 if (pend != c && is_end_of_word(*pend)) {
4345 // The axis value has been parsed correctly.
4346 x = temp_z;
4347 is_z_changed = true;
4348 }
4349 }
4350 }
4351
4352 {
4353 float &y = pos.y();
4354 auto z_pos = line_str.find(" Y");
4355 float temp_z = 0;
4356 if (z_pos != line_str.npos && z_pos + 2 < line_str.size()) {
4357 // Try to parse the numeric value.
4358 std::string z_sub = line_str.substr(z_pos + 2);
4359 char *c = &z_sub[0];
4360 char *end = c + sizeof(z_sub.c_str());
4361
4362 auto is_end_of_word = [](char c) { return c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == 0 || c == ';'; };
4363
4364 auto [pend, ec] = fast_float::from_chars(c, end, temp_z);
4365 if (pend != c && is_end_of_word(*pend)) {
4366 // The axis value has been parsed correctly.
4367 y = temp_z;
4368 is_z_changed = true;
4369 }
4370 }
4371 }
4372
4373 {
4374 float &z = pos.z();
4375 auto z_pos = line_str.find(" Z");
4376 float temp_z = 0;
4377 if (z_pos != line_str.npos && z_pos + 2 < line_str.size()) {
4378 // Try to parse the numeric value.
4379 std::string z_sub = line_str.substr(z_pos + 2);
4380 char *c = &z_sub[0];
4381 char *end = c + sizeof(z_sub.c_str());
4382
4383 auto is_end_of_word = [](char c) { return c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == 0 || c == ';'; };
4384
4385 auto [pend, ec] = fast_float::from_chars(c, end, temp_z);
4386 if (pend != c && is_end_of_word(*pend)) {
4387 // The axis value has been parsed correctly.
4388 z = temp_z;
4389 is_z_changed = true;
4390 }
4391 }
4392 }
4393 }
4394 }
4395 // loop to handle next line
4396 start_index = end_index + 1;
4397 end_index = start_index;
4398 }
4399 return is_z_changed;
4400}
static bool is_end_of_word(char c)
Definition Config.cpp:1249

References Slic3r::is_end_of_word().

Referenced by Slic3r::WipeTowerIntegration::append_tcr(), and Slic3r::WipeTowerIntegration::append_tcr2().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_last_z_from_gcode()

bool Slic3r::GCodeProcessor::get_last_z_from_gcode ( const std::string & gcode_str,
double & z )
static
4257{
4258 int str_size = gcode_str.size();
4259 int start_index = 0;
4260 int end_index = 0;
4261 bool is_z_changed = false;
4262 while (end_index < str_size) {
4263 //find a full line
4264 if (gcode_str[end_index] != '\n') {
4265 end_index++;
4266 continue;
4267 }
4268 //parse the line
4269 if (end_index > start_index) {
4270 std::string line_str = gcode_str.substr(start_index, end_index - start_index);
4271 line_str.erase(0, line_str.find_first_not_of(" "));
4272 line_str.erase(line_str.find_last_not_of(";") + 1);
4273 line_str.erase(line_str.find_last_not_of(" ") + 1);
4274
4275 //command which may have z movement
4276 if (line_str.size() > 4 && (line_str.find("G0 ") == 0
4277 || line_str.find("G1 ") == 0
4278 || line_str.find("G2 ") == 0
4279 || line_str.find("G3 ") == 0))
4280 {
4281 auto z_pos = line_str.find(" Z");
4282 double temp_z = 0;
4283 if (z_pos != line_str.npos
4284 && z_pos + 2 < line_str.size()) {
4285 // Try to parse the numeric value.
4286 std::string z_sub = line_str.substr(z_pos + 2);
4287 char* c = &z_sub[0];
4288 char* end = c + sizeof(z_sub.c_str());
4289
4290 auto is_end_of_word = [](char c) {
4291 return c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == 0 || c == ';';
4292 };
4293
4294 auto [pend, ec] = fast_float::from_chars(c, end, temp_z);
4295 if (pend != c && is_end_of_word(*pend)) {
4296 // The axis value has been parsed correctly.
4297 z = temp_z;
4298 is_z_changed = true;
4299 }
4300 }
4301 }
4302 }
4303 //loop to handle next line
4304 start_index = end_index + 1;
4305 end_index = start_index;
4306 }
4307 return is_z_changed;
4308}

References Slic3r::is_end_of_word().

Referenced by Slic3r::WipeTowerIntegration::append_tcr(), Slic3r::GCode::generate_timelapse_gcode(), and Slic3r::GCode::set_extruder().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_machine_config_idx()

int Slic3r::GCodeProcessor::get_machine_config_idx ( ) const
private
7707{
7708 const int extruder_id = get_extruder_id(false);
7709 if (!m_nozzle_group_result || extruder_id < 0)
7710 return 0;
7711 const int nozzle_id = m_nozzle_status_recorder.get_nozzle_in_extruder(extruder_id);
7712 auto nozzle_info = m_nozzle_group_result->get_nozzle_from_id(nozzle_id);
7713 // Orca: bounds guard — a stale grouping context after a printer swap must not index OOB.
7714 if (!nozzle_info || extruder_id >= (int) m_result.extruder_types.size())
7715 return 0;
7716 return std::max(0, get_config_index_base(nozzle_info->volume_type, m_result.extruder_types[extruder_id],
7717 extruder_id + 1, m_result.printer_extruder_variant,
7718 m_result.printer_extruder_id));
7719}
MultiNozzleUtils::NozzleStatusRecorder m_nozzle_status_recorder
Definition GCodeProcessor.hpp:1291
int get_config_index_base(NozzleVolumeType volume_type, ExtruderType extruder_type, int variant_id_1based, const std::vector< std::string > &variant_list, const std::vector< int > &variant_ids_1based)
Definition PrintConfig.cpp:833

References Slic3r::get_config_index_base(), get_extruder_id(), m_nozzle_group_result, m_nozzle_status_recorder, and m_result.

Referenced by process_filament_change(), and process_filament_change().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_prepare_time()

float Slic3r::GCodeProcessor::get_prepare_time ( PrintEstimatedStatistics::ETimeMode mode) const
4017{
4018 return (mode < PrintEstimatedStatistics::ETimeMode::Count) ? m_time_processor.machines[static_cast<size_t>(mode)].prepare_time : 0.0f;
4019}

References Slic3r::PrintEstimatedStatistics::Count, and m_time_processor.

Referenced by update_estimated_times_stats().

Here is the caller graph for this function:

◆ get_result()

const GCodeProcessorResult & Slic3r::GCodeProcessor::get_result ( ) const
inline
1434{ return m_result; }

References m_result.

Referenced by Slic3r::DoExport::update_print_estimated_stats().

Here is the caller graph for this function:

◆ get_retract_acceleration()

float Slic3r::GCodeProcessor::get_retract_acceleration ( PrintEstimatedStatistics::ETimeMode mode) const
private
7944{
7945 size_t id = static_cast<size_t>(mode);
7946 return (id < m_time_processor.machines.size()) ? m_time_processor.machines[id].retract_acceleration : DEFAULT_RETRACT_ACCELERATION;
7947}

References DEFAULT_RETRACT_ACCELERATION, Slic3r::GCodeProcessorResult::id, and m_time_processor.

Referenced by process_G1(), process_VG1(), and store_move_vertex().

Here is the caller graph for this function:

◆ get_time()

double Slic3r::GCodeProcessor::get_time ( PrintEstimatedStatistics::ETimeMode mode) const
4012{
4013 return (mode < PrintEstimatedStatistics::ETimeMode::Count) ? m_time_processor.machines[static_cast<size_t>(mode)].time : 0.0;
4014}

References Slic3r::PrintEstimatedStatistics::Count, and m_time_processor.

Referenced by update_estimated_times_stats().

Here is the caller graph for this function:

◆ get_time_dhm()

std::string Slic3r::GCodeProcessor::get_time_dhm ( PrintEstimatedStatistics::ETimeMode mode) const
4022{
4023 return (mode < PrintEstimatedStatistics::ETimeMode::Count) ? short_time(get_time_dhms(float(m_time_processor.machines[static_cast<size_t>(mode)].time))) : std::string("N/A");
4024}
std::string short_time(const std::string &time)
Definition Utils.hpp:563
std::string get_time_dhms(float time_in_secs)
Definition Utils.hpp:609

References Slic3r::PrintEstimatedStatistics::Count, Slic3r::get_time_dhms(), m_time_processor, and Slic3r::short_time().

Referenced by run_post_process().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_travel_acceleration()

float Slic3r::GCodeProcessor::get_travel_acceleration ( PrintEstimatedStatistics::ETimeMode mode) const
private
7976{
7977 size_t id = static_cast<size_t>(mode);
7978 return (id < m_time_processor.machines.size()) ? m_time_processor.machines[id].travel_acceleration : DEFAULT_TRAVEL_ACCELERATION;
7979}

References DEFAULT_TRAVEL_ACCELERATION, Slic3r::GCodeProcessorResult::id, and m_time_processor.

Referenced by process_G1(), process_VG1(), and store_move_vertex().

Here is the caller graph for this function:

◆ get_xyz_max_jerk()

Vec3f Slic3r::GCodeProcessor::get_xyz_max_jerk ( PrintEstimatedStatistics::ETimeMode mode) const
private
7918{
7919 // Default values from config
7920 const size_t id = static_cast<size_t>(mode);
7921 float jx = 0.0f;
7922 float jy = 0.0f;
7923 float jz = 0.0f;
7924 const float jd = get_option_value(m_time_processor.machine_limits.machine_max_junction_deviation, id);
7925
7926 // Classic Jerk: Junction Deviation is only supported by Marlin firmware when using a JD value grater than 0.
7927 if (m_flavor != gcfMarlinFirmware || jd <= 0.0f)
7928 {
7929 jx = get_option_value(m_time_processor.machine_limits.machine_max_jerk_x, id);
7930 jy = get_option_value(m_time_processor.machine_limits.machine_max_jerk_y, id);
7931 jz = get_option_value(m_time_processor.machine_limits.machine_max_jerk_z, id);
7932 }
7933 else
7934 {
7935 jx = get_axis_max_jerk_with_jd(mode, X);
7936 jy = get_axis_max_jerk_with_jd(mode, Y);
7937 jz = get_axis_max_jerk_with_jd(mode, Z);
7938 }
7939
7940 return Vec3f(jx, jy, jz);
7941}
Eigen::Matrix< float, 3, 1, Eigen::DontAlign > Vec3f
Definition Point.hpp:65

References Slic3r::gcfMarlinFirmware, get_axis_max_jerk_with_jd(), Slic3r::get_option_value(), m_flavor, m_time_processor, Slic3r::X, Slic3r::Y, and Slic3r::Z.

Referenced by process_G1(), and process_VG1().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ handle_offsets_of_second_process()

void Slic3r::GCodeProcessor::handle_offsets_of_second_process ( const TimeProcessor::InsertedLinesMap & inserted_operation_lines)
private
2131{
2132 int total_offset = 0;
2133 auto iter = inserted_operation_lines.begin();
2134 for (GCodeProcessorResult::MoveVertex& move : m_result.moves) {
2135 while (iter != inserted_operation_lines.end() && iter->first < move.gcode_id) {
2136 total_offset += static_cast<int>(iter->second.size());
2137 ++iter;
2138 }
2139 move.gcode_id += total_offset;
2140 }
2141}

References Slic3r::GCodeProcessorResult::MoveVertex::gcode_id, and m_result.

Referenced by run_second_pass_injection().

Here is the caller graph for this function:

◆ init_filament_maps_and_nozzle_type_when_import_only_gcode()

void Slic3r::GCodeProcessor::init_filament_maps_and_nozzle_type_when_import_only_gcode ( )
7133{
7134 if (m_filament_maps.empty()) {
7136 }
7137 if (m_result.nozzle_type.empty()) {
7139 }
7140}
@ ExtruderMax
Definition TriangleSelector.hpp:66
@ ntUndefine
Definition CommonDefs.hpp:14

References Slic3r::ExtruderMax, m_filament_maps, m_result, and Slic3r::ntUndefine.

Referenced by Slic3r::GUI::Plater::load_gcode().

Here is the caller graph for this function:

◆ initialize()

void Slic3r::GCodeProcessor::initialize ( const std::string & filename)
3916{
3918
3919 // process gcode
3920 m_result.filename = filename;
3921 m_result.id = ++s_result_id;
3922}
static unsigned int s_result_id
Definition GCodeProcessor.hpp:1382
bool is_decimal_separator_point()
Definition LocalesUtils.cpp:78

References Slic3r::is_decimal_separator_point(), m_result, and s_result_id.

Here is the call graph for this function:

◆ initialize_from_context()

void Slic3r::GCodeProcessor::initialize_from_context ( const std::shared_ptr< MultiNozzleUtils::NozzleGroupResultBase > & nozzle_group_result)
inline
1422 {
1423 m_nozzle_group_result = nozzle_group_result;
1424 }

References m_nozzle_group_result.

Referenced by Slic3r::Print::export_gcode_from_previous_file(), Slic3r::DoExport::init_gcode_processor(), and Slic3r::Print::reload_gcode_moves().

Here is the caller graph for this function:

◆ initialize_result_moves()

void Slic3r::GCodeProcessor::initialize_result_moves ( )
inline
1445 {
1446 // 1st move must be a dummy move
1447 assert(m_result.moves.empty());
1448 m_result.moves.emplace_back(GCodeProcessorResult::MoveVertex());
1449 }

References m_result.

Referenced by Slic3r::DoExport::init_gcode_processor(), and process_file().

Here is the caller graph for this function:

◆ is_stealth_time_estimator_enabled()

bool Slic3r::GCodeProcessor::is_stealth_time_estimator_enabled ( ) const
inline
1428 {
1429 return m_time_processor.machines[static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Stealth)].enabled;
1430 }

References m_time_processor, and Slic3r::PrintEstimatedStatistics::Stealth.

Referenced by run_post_process(), and Slic3r::DoExport::update_print_estimated_stats().

Here is the caller graph for this function:

◆ minimum_feedrate()

float Slic3r::GCodeProcessor::minimum_feedrate ( PrintEstimatedStatistics::ETimeMode mode,
float feedrate ) const
private
7688{
7689 if (m_time_processor.machine_limits.machine_min_extruding_rate.empty())
7690 return feedrate;
7691
7692 return std::max(feedrate, get_option_value(m_time_processor.machine_limits.machine_min_extruding_rate, static_cast<size_t>(mode)));
7693}

References Slic3r::get_option_value(), and m_time_processor.

Referenced by process_G1(), and process_VG1().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ minimum_travel_feedrate()

float Slic3r::GCodeProcessor::minimum_travel_feedrate ( PrintEstimatedStatistics::ETimeMode mode,
float feedrate ) const
private
7696{
7697 if (m_time_processor.machine_limits.machine_min_travel_rate.empty())
7698 return feedrate;
7699
7700 return std::max(feedrate, get_option_value(m_time_processor.machine_limits.machine_min_travel_rate, static_cast<size_t>(mode)));
7701}

References Slic3r::get_option_value(), and m_time_processor.

Referenced by process_G1(), and process_VG1().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_bambuslicer_tags()

bool Slic3r::GCodeProcessor::process_bambuslicer_tags ( const std::string_view comment)
private
4695{
4696 return false;
4697}

Referenced by process_producers_tags().

Here is the caller graph for this function:

◆ process_buffer()

void Slic3r::GCodeProcessor::process_buffer ( const std::string & buffer)
3925{
3926 //FIXME maybe cache GCodeLine gline to be over multiple parse_buffer() invocations.
3927 m_parser.parse_buffer(buffer, [this](GCodeReader&, const GCodeReader::GCodeLine& line) {
3928 this->process_gcode_line(line, false);
3929 });
3930}
void process_gcode_line(const GCodeReader::GCodeLine &line, bool producers_enabled)
Definition GCodeProcessor.cpp:4170

References m_parser, and process_gcode_line().

Here is the call graph for this function:

◆ process_craftware_tags()

bool Slic3r::GCodeProcessor::process_craftware_tags ( const std::string_view comment)
private
4923{
4924 // segType -> extrusion role
4925 std::string tag = "segType:";
4926 size_t pos = comment.find(tag);
4927 if (pos != comment.npos) {
4928 const std::string_view type = comment.substr(pos + tag.length());
4929 if (type == "Skirt")
4931 else if (type == "Perimeter")
4933 else if (type == "HShell")
4934 set_extrusion_role(erNone); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
4935 else if (type == "InnerHair")
4936 set_extrusion_role(erNone); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
4937 else if (type == "Loop")
4938 set_extrusion_role(erNone); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
4939 else if (type == "Infill")
4941 else if (type == "Raft")
4943 else if (type == "Support")
4945 else if (type == "SupportTouch")
4947 else if (type == "SoftSupport")
4949 else if (type == "Pillar")
4951 else {
4953 BOOST_LOG_TRIVIAL(warning) << "GCodeProcessor found unknown extrusion role: " << type;
4954 }
4955
4957 m_seams_detector.activate(true);
4958
4959 return true;
4960 }
4961
4962 // layer
4963 pos = comment.find(" Layer #");
4964 if (pos == 0) {
4965 ++m_layer_id;
4966 return true;
4967 }
4968
4969 return false;
4970}
void set_extrusion_role(ExtrusionRole role)
Definition GCodeProcessor.cpp:7666
SeamsDetector m_seams_detector
Definition GCodeProcessor.hpp:1343
@ erExternalPerimeter
Definition ExtrusionEntity.hpp:29
@ erSupportMaterialInterface
Definition ExtrusionEntity.hpp:42
@ erSupportMaterial
Definition ExtrusionEntity.hpp:41
@ erInternalInfill
Definition ExtrusionEntity.hpp:31

References Slic3r::erExternalPerimeter, Slic3r::erInternalInfill, Slic3r::erNone, Slic3r::erSkirt, Slic3r::erSupportMaterial, Slic3r::erSupportMaterialInterface, Slic3r::erWipeTower, m_extrusion_role, m_layer_id, m_seams_detector, and set_extrusion_role().

Referenced by process_producers_tags().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_cura_tags()

bool Slic3r::GCodeProcessor::process_cura_tags ( const std::string_view comment)
private
4700{
4701 // TYPE -> extrusion role
4702 std::string tag = "TYPE:";
4703 size_t pos = comment.find(tag);
4704 if (pos != comment.npos) {
4705 const std::string_view type = comment.substr(pos + tag.length());
4706 if (type == "SKIRT")
4708 else if (type == "WALL-OUTER")
4710 else if (type == "WALL-INNER")
4712 else if (type == "SKIN")
4714 else if (type == "FILL")
4716 else if (type == "SUPPORT")
4718 else if (type == "SUPPORT-INTERFACE")
4720 else if (type == "PRIME-TOWER")
4722 else {
4724 BOOST_LOG_TRIVIAL(warning) << "GCodeProcessor found unknown extrusion role: " << type;
4725 }
4726
4728 m_seams_detector.activate(true);
4729
4730 return true;
4731 }
4732
4733 // flavor
4734 tag = "FLAVOR:";
4735 pos = comment.find(tag);
4736 if (pos != comment.npos) {
4737 const std::string_view flavor = comment.substr(pos + tag.length());
4738 if (flavor == "BFB")
4739 m_flavor = gcfMarlinLegacy; // is this correct ?
4740 else if (flavor == "Mach3")
4742 else if (flavor == "Makerbot")
4744 else if (flavor == "UltiGCode")
4745 m_flavor = gcfMarlinLegacy; // is this correct ?
4746 else if (flavor == "Marlin(Volumetric)")
4747 m_flavor = gcfMarlinLegacy; // is this correct ?
4748 else if (flavor == "Griffin")
4749 m_flavor = gcfMarlinLegacy; // is this correct ?
4750 else if (flavor == "Repetier")
4752 else if (flavor == "RepRap")
4754 else if (flavor == "Marlin")
4756 else
4757 BOOST_LOG_TRIVIAL(warning) << "GCodeProcessor found unknown flavor: " << flavor;
4758
4759 return true;
4760 }
4761
4762 // layer
4763 tag = "LAYER:";
4764 pos = comment.find(tag);
4765 if (pos != comment.npos) {
4766 ++m_layer_id;
4767 return true;
4768 }
4769
4770 return false;
4771}
@ gcfMach3
Definition PrintConfig.hpp:61
@ gcfRepetier
Definition PrintConfig.hpp:55
@ gcfMakerWare
Definition PrintConfig.hpp:59
@ erSolidInfill
Definition ExtrusionEntity.hpp:32
@ erPerimeter
Definition ExtrusionEntity.hpp:28

References Slic3r::erExternalPerimeter, Slic3r::erInternalInfill, Slic3r::erNone, Slic3r::erPerimeter, Slic3r::erSkirt, Slic3r::erSolidInfill, Slic3r::erSupportMaterial, Slic3r::erSupportMaterialInterface, Slic3r::erWipeTower, Slic3r::gcfMach3, Slic3r::gcfMakerWare, Slic3r::gcfMarlinLegacy, Slic3r::gcfRepetier, Slic3r::gcfRepRapFirmware, m_extrusion_role, m_flavor, m_layer_id, m_seams_detector, and set_extrusion_role().

Referenced by process_producers_tags().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_custom_gcode_time()

void Slic3r::GCodeProcessor::process_custom_gcode_time ( CustomGCode::Type code)
private
8019{
8020 //FIXME this simulates st_synchronize! is it correct?
8021 // The estimated time may be longer than the real print time.
8023 for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
8024 TimeMachine& machine = m_time_processor.machines[i];
8025 if (!machine.enabled)
8026 continue;
8027
8028 TimeMachine::CustomGCodeTime& gcode_time = machine.gcode_time;
8029 gcode_time.needed = true;
8030 if (gcode_time.cache != 0.0f) {
8031 gcode_time.times.push_back({ code, gcode_time.cache });
8032 gcode_time.cache = 0.0f;
8033 }
8034 }
8035}
void simulate_st_synchronize(float additional_time=0.0f, EMoveType target_move_type=EMoveType::Noop)
Definition GCodeProcessor.cpp:8135
bool needed
Definition GCodeProcessor.hpp:776

References Slic3r::GCodeProcessor::TimeMachine::CustomGCodeTime::cache, Slic3r::PrintEstimatedStatistics::Count, Slic3r::GCodeProcessor::TimeMachine::enabled, Slic3r::GCodeProcessor::TimeMachine::gcode_time, m_time_processor, Slic3r::GCodeProcessor::TimeMachine::CustomGCodeTime::needed, simulate_st_synchronize(), and Slic3r::GCodeProcessor::TimeMachine::CustomGCodeTime::times.

Referenced by process_tags().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_elegoo_M6211()

void Slic3r::GCodeProcessor::process_elegoo_M6211 ( const GCodeReader::GCodeLine & line)
private
140{
141 float length = 0.0f;
142 if (!line.has_value('L', length) || length <= 0.0f)
143 return;
144
145 float t = -1.0f;
146 if (!line.has_value('T', t) || t < 0.0f)
147 return;
148
149 const int filament_id = static_cast<int>(std::round(t));
150 if (filament_id < 0 || filament_id >= m_result.filaments_count)
151 return;
152
153 const int extruder_id = m_filament_maps[filament_id];
154
155 float new_extruder_temp = 0.0f;
156 if (line.has_value('S', new_extruder_temp)) {
157 if (extruder_id >= 0 && static_cast<size_t>(extruder_id) < m_extruder_temps.size())
158 m_extruder_temps[static_cast<size_t>(extruder_id)] = new_extruder_temp;
159 }
160
161 const float m6211_time = estimate_M6211_time(line, m_printer_model, length, new_extruder_temp,
163 const int curr_filament_id = get_filament_id(false);
164 const bool is_first_extrusion = (curr_filament_id == -1) || (filament_id == curr_filament_id);
165
166 m_time_processor.filament_unload_times = 0;
167 m_time_processor.filament_load_times = m6211_time;
168 process_filament_change(filament_id);
169
170 if (extruder_id >= 0 && static_cast<size_t>(extruder_id) < m_remaining_volume.size()) {
171 const float remaining_volume = static_cast<size_t>(extruder_id) < m_nozzle_volume.size() ?
172 m_nozzle_volume[extruder_id] :
173 0.0f;
174 const float filament_diameter = static_cast<size_t>(filament_id) < m_result.filament_diameters.size() ?
175 m_result.filament_diameters[filament_id] :
176 m_result.filament_diameters.back();
177 const float area_filament_cross_section = static_cast<float>(M_PI) * sqr(0.5f * filament_diameter);
178 const float volume_flushed_filament = area_filament_cross_section * length;
179
180 if (volume_flushed_filament >= remaining_volume) {
181 if (!is_first_extrusion)
182 m_used_filaments.update_flush_per_filament(curr_filament_id, remaining_volume);
183
184 m_used_filaments.update_flush_per_filament(filament_id, volume_flushed_filament - remaining_volume);
185 m_remaining_volume[extruder_id] = 0.0f;
186 } else {
187 m_used_filaments.update_flush_per_filament(filament_id, volume_flushed_filament);
188 m_remaining_volume[extruder_id] -= volume_flushed_filament;
189 }
190 }
191}
int get_filament_id(bool force_initialize=true) const
Definition GCodeProcessor.cpp:8295
void process_filament_change(int id)
Definition GCodeProcessor.cpp:7369
std::vector< float > m_remaining_volume
Definition GCodeProcessor.hpp:1249
float estimate_M6211_time(const GCodeReader::GCodeLine &line, std::string_view printer_model, float length, float new_extruder_temp, double current_x, double current_y)
Definition ElegooGCodeProcessorHelper.cpp:126
double length(const Points &pts)
Definition MultiPoint.hpp:181

References get_filament_id(), Slic3r::GCodeReader::GCodeLine::has_value(), Slic3r::length(), m_extruder_temps, m_filament_maps, m_nozzle_volume, M_PI, m_printer_model, m_remaining_volume, m_result, m_start_position, m_time_processor, m_used_filaments, process_filament_change(), Slic3r::sqr(), Slic3r::X, and Slic3r::Y.

Referenced by process_M6211().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_filament_change() [1/2]

void Slic3r::GCodeProcessor::process_filament_change ( int id)
private
7370{
7371 assert(id < m_result.filaments_count);
7372 int prev_extruder_id = get_extruder_id(false);
7373 int prev_filament_id = get_filament_id(false);
7374 int next_extruder_id = m_filament_maps[id];
7375 int next_filament_id = id;
7376 float extra_time = 0;
7377 unsigned int filament_changes_delta = 0;
7378 unsigned int extruder_changes_delta = 0;
7379 float filament_load_time_delta = 0.0f;
7380 float filament_unload_time_delta = 0.0f;
7381 float tool_change_time_delta = 0.0f;
7382
7383 if (prev_filament_id == next_filament_id)
7384 return;
7385
7386 if (prev_extruder_id != -1)
7387 m_last_filament_id[prev_extruder_id] = prev_filament_id;
7388
7389 if (prev_extruder_id == next_extruder_id) {
7390 // don't need extruder change
7391 assert(prev_extruder_id != -1);
7393 m_filament_id[next_extruder_id] = next_filament_id;
7394 filament_changes_delta += 1;
7395 const float filament_unload_time = get_filament_unload_time(static_cast<size_t>(prev_filament_id));
7396 extra_time += filament_unload_time;
7397 filament_unload_time_delta += filament_unload_time;
7398 m_time_processor.extruder_unloaded = false;
7399 const float filament_load_time = get_filament_load_time(static_cast<size_t>(next_filament_id));
7400 extra_time += filament_load_time;
7401 filament_load_time_delta += filament_load_time;
7402 }
7403 else {
7404 if (prev_extruder_id == -1) {
7405 // initialize
7406 m_extruder_id = next_extruder_id;
7407 m_filament_id[next_extruder_id] = next_filament_id;
7408 m_time_processor.extruder_unloaded = false;
7409 const float filament_load_time = get_filament_load_time(static_cast<size_t>(next_filament_id));
7410 extra_time += filament_load_time;
7411 filament_load_time_delta += filament_load_time;
7412 }
7413 else {
7414 //first process cache generated by last extruder
7416 //switch to current extruder
7417 m_extruder_id = next_extruder_id;
7418 if (m_last_filament_id[next_extruder_id] == (unsigned char)(-1)) {
7419 //no filament in current extruder
7420 m_filament_id[next_extruder_id] = next_filament_id;
7421 m_time_processor.extruder_unloaded = false;
7422 const float filament_load_time = get_filament_load_time(static_cast<size_t>(next_filament_id));
7423 extra_time += filament_load_time;
7424 filament_load_time_delta += filament_load_time;
7425 }
7426 else if (m_last_filament_id[next_extruder_id] != next_filament_id) {
7427 //need to change filament
7428 m_filament_id[next_extruder_id] = next_filament_id;
7429 filament_changes_delta += 1;
7430 const float filament_unload_time = get_filament_unload_time(static_cast<size_t>(prev_filament_id));
7431 extra_time += filament_unload_time;
7432 filament_unload_time_delta += filament_unload_time;
7433 m_time_processor.extruder_unloaded = false;
7434 const float filament_load_time = get_filament_load_time(static_cast<size_t>(next_filament_id));
7435 extra_time += filament_load_time;
7436 filament_load_time_delta += filament_load_time;
7437 }
7438 extruder_changes_delta += 1;
7439 const float tool_change_time = get_extruder_change_time(next_extruder_id);
7440 extra_time += tool_change_time;
7441 tool_change_time_delta += tool_change_time;
7442 }
7443 }
7444
7445 if (filament_changes_delta > 0 || extruder_changes_delta > 0 || filament_load_time_delta > 0.0f || filament_unload_time_delta > 0.0f || tool_change_time_delta > 0.0f) {
7446 m_result.lock();
7447 m_result.print_statistics.total_filament_changes += filament_changes_delta;
7448 m_result.print_statistics.total_extruder_changes += extruder_changes_delta;
7449 m_result.print_statistics.total_filament_load_time += filament_load_time_delta;
7450 m_result.print_statistics.total_filament_unload_time += filament_unload_time_delta;
7451 m_result.print_statistics.total_tool_change_time += tool_change_time_delta;
7452 m_result.unlock();
7453 }
7454
7455 m_cp_color.current = m_extruder_colors[next_filament_id];
7456
7457 // Store the tool-change move first, then attribute the filament-change delay to
7458 // it rather than to whichever motion block happens to be pending. This keeps the
7459 // delay out of the per-role feature-time distribution (tool-change moves are not
7460 // counted as an extrusion role) while still including it in the total and
7461 // per-layer times.
7463
7464 // Construct a zero-distance time block for the tool-change move on each enabled
7465 // machine so the synchronize below can land the delay on it. The synchronize
7466 // flushes with keep_last_n_blocks == 0; if fewer than two blocks are queued it
7467 // buffers the delay instead, and this block stays queued to receive it on a
7468 // later pass.
7469 for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
7470 TimeMachine& machine = m_time_processor.machines[i];
7471 if (!machine.enabled)
7472 continue;
7473 TimeBlock block;
7474 block.move_id = static_cast<unsigned int>(m_result.moves.size()) - 1;
7475 block.move_type = EMoveType::Tool_change;
7476 // stamp the current SKIPPABLE type onto the tool-change block (the fleet-wide time_lapse_gcode
7477 // regions stamp stTimelapse); byte-inert because nothing reads the stamp until the injector
7478 // consumes it.
7479 block.skippable_type = m_skippable_type;
7480 block.layer_id = std::max<unsigned int>(1, m_layer_id);
7481 block.g1_line_id = m_g1_line_id;
7482 block.flags.prepare_stage = m_processing_start_custom_gcode;
7483 block.distance = 0.0f;
7484 block.calculate_trapezoid();
7485 machine.blocks.push_back(block);
7486 }
7487
7489
7491}
SkipType m_skippable_type
Definition GCodeProcessor.hpp:1245
float get_filament_load_time(size_t extruder_id)
Definition GCodeProcessor.cpp:7991
unsigned int m_g1_line_id
Definition GCodeProcessor.hpp:1340
int get_machine_config_idx() const
Definition GCodeProcessor.cpp:7706
void store_move_vertex(EMoveType type, EMovePathType path_type=EMovePathType::Noop_move, bool internal_only=false)
Definition GCodeProcessor.cpp:7493
float get_filament_unload_time(size_t extruder_id)
Definition GCodeProcessor.cpp:7997
CpColor m_cp_color
Definition GCodeProcessor.hpp:1342
float get_extruder_change_time(size_t extruder_id)
Definition GCodeProcessor.cpp:8003
bool m_processing_start_custom_gcode
Definition GCodeProcessor.hpp:1338
void process_filaments(CustomGCode::Type code)
Definition GCodeProcessor.cpp:8037
@ ToolChange
Definition CustomGCode.hpp:21
@ Tool_change
Definition GCodeProcessor.hpp:58
unsigned int move_id
Definition GCodeProcessor.hpp:722

References Slic3r::GCodeProcessor::TimeMachine::blocks, Slic3r::GCodeProcessor::TimeBlock::calculate_trapezoid(), Slic3r::PrintEstimatedStatistics::Count, Slic3r::GCodeProcessor::TimeBlock::distance, Slic3r::GCodeProcessor::TimeMachine::enabled, Slic3r::GCodeProcessor::TimeBlock::flags, Slic3r::GCodeProcessor::TimeBlock::g1_line_id, get_extruder_change_time(), get_extruder_id(), get_filament_id(), get_filament_load_time(), get_filament_unload_time(), get_machine_config_idx(), Slic3r::GCodeProcessor::TimeBlock::layer_id, m_cp_color, m_extruder_colors, m_extruder_id, m_filament_id, m_filament_maps, m_g1_line_id, m_last_filament_id, m_layer_id, m_machine_config_idx, m_processing_start_custom_gcode, m_result, m_skippable_type, m_time_processor, Slic3r::GCodeProcessor::TimeBlock::move_id, Slic3r::GCodeProcessor::TimeBlock::move_type, Slic3r::GCodeProcessor::TimeBlock::Flags::prepare_stage, process_filaments(), simulate_st_synchronize(), Slic3r::GCodeProcessor::TimeBlock::skippable_type, store_move_vertex(), Slic3r::Tool_change, and Slic3r::CustomGCode::ToolChange.

Referenced by process_elegoo_M6211(), process_filament_change(), process_M1020(), and process_T().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_filament_change() [2/2]

void Slic3r::GCodeProcessor::process_filament_change ( int id,
int nozzle_id )
private
7258{
7259 // Gate: outside the multi-nozzle context, or when the nozzle-grouping result is not available
7260 // (e.g. re-importing a bare g-code file), run the existing single-arg model byte-for-byte.
7261 if (!use_multi_nozzle_change_time_model() || !m_result.nozzle_group_result) {
7262 // Orca: occupancy bookkeeping is deliberately decoupled from the gated change-time model:
7263 // the per-slot machine-limit resolution needs the recorder during the streaming pass,
7264 // where the richer time model stays byte-frozen behind the result-field gate above.
7265 // Recorder writes have no time effect.
7267 if (auto info = resolve_target_nozzle(*m_nozzle_group_result, id, nozzle_id))
7268 m_nozzle_status_recorder.set_nozzle_status(info->group_id, id, info->extruder_id);
7269 }
7271 return;
7272 }
7273
7274 assert(id < m_result.filaments_count);
7275 const int prev_extruder_id = get_extruder_id(false);
7276 const int prev_filament_id = get_filament_id(false);
7277 float extra_time = 0.0f;
7278
7279 // A same-filament re-select with no explicit nozzle target costs nothing.
7280 if (prev_filament_id == id && nozzle_id == -1)
7281 return;
7282
7283 if (prev_extruder_id != -1)
7284 m_last_filament_id[prev_extruder_id] = static_cast<unsigned char>(prev_filament_id);
7285
7286 // Resolve the destination nozzle: by explicit H<nozzle> id first, else the filament's first nozzle.
7287 std::optional<MultiNozzleUtils::NozzleInfo> target_nozzle_info = resolve_target_nozzle(*m_result.nozzle_group_result, id, nozzle_id);
7288 if (!target_nozzle_info)
7289 return;
7290
7291 const int new_extruder_id = target_nozzle_info->extruder_id;
7292 const int old_extruder_id = prev_extruder_id;
7293 const int new_nozzle_id_in_extruder = target_nozzle_info->group_id;
7294 const int old_nozzle_id_in_extruder = m_nozzle_status_recorder.get_nozzle_in_extruder(new_extruder_id);
7295 const int new_filament_id = id;
7296 const int old_filament_in_nozzle = m_nozzle_status_recorder.get_filament_in_nozzle(new_nozzle_id_in_extruder);
7297 const int old_filament_in_extruder = m_nozzle_status_recorder.get_filament_in_nozzle(old_nozzle_id_in_extruder);
7298
7299 const bool extruder_change = new_extruder_id != old_extruder_id;
7300 const bool nozzle_in_extruder_change = new_nozzle_id_in_extruder != old_nozzle_id_in_extruder;
7301 const bool filament_in_nozzle_change = new_filament_id != old_filament_in_nozzle;
7302
7303 // Orca: attribute the accumulated volume usage to the OLD extruder before switching state. Unlike
7304 // an unconditional call, the single-arg model (and every other Orca estimator path) skips this on
7305 // the very first tool-select (prev_extruder_id == -1) where there is no prior filament segment to
7306 // close out. Matching that keeps H2C's initial `T<fil> H<n>` byte-identical to its single-arg
7307 // baseline; every subsequent change closes out identically.
7308 if (prev_extruder_id != -1)
7310
7311 m_result.lock();
7312 if (extruder_change && old_extruder_id != -1) {
7313 const float t = get_extruder_change_time(new_extruder_id);
7314 extra_time += t;
7315 m_result.print_statistics.total_tool_change_time += t; // Orca-only stat
7316 m_result.print_statistics.total_extruder_changes += 1; // Orca-only stat
7317 }
7318 if (nozzle_in_extruder_change || filament_in_nozzle_change) {
7319 if (old_filament_in_extruder >= 0) {
7320 const float t = get_filament_unload_time(static_cast<size_t>(old_filament_in_extruder));
7321 extra_time += t;
7322 m_result.print_statistics.total_filament_unload_time += t; // Orca-only stat
7323 }
7324 m_time_processor.extruder_unloaded = false;
7325 const float t = get_filament_load_time(static_cast<size_t>(new_filament_id));
7326 extra_time += t;
7327 m_result.print_statistics.total_filament_load_time += t; // Orca-only stat
7328 if (filament_in_nozzle_change && old_filament_in_nozzle != -1)
7329 m_result.print_statistics.total_flush_filament_changes += 1;
7330 }
7331 if (prev_filament_id != -1)
7332 m_result.print_statistics.total_filament_changes += 1;
7333 m_result.unlock();
7334
7335 if (new_extruder_id != -1)
7336 m_filament_id[new_extruder_id] = static_cast<unsigned char>(new_filament_id);
7337 m_extruder_id = static_cast<unsigned char>(new_extruder_id);
7338
7339 // Record the resulting nozzle/extruder occupancy so the next change can classify itself.
7340 m_nozzle_status_recorder.set_nozzle_status(new_nozzle_id_in_extruder, new_filament_id, new_extruder_id);
7341
7342 m_cp_color.current = m_extruder_colors[new_filament_id];
7343
7344 // Same tool-change move + zero-distance time block plumbing as the single-arg model, so the flush
7345 // delay lands on a Tool_change block (kept out of the per-role feature-time distribution).
7347
7348 for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
7349 TimeMachine& machine = m_time_processor.machines[i];
7350 if (!machine.enabled)
7351 continue;
7352 TimeBlock block;
7353 block.move_id = static_cast<unsigned int>(m_result.moves.size()) - 1;
7354 block.move_type = EMoveType::Tool_change;
7355 block.skippable_type = m_skippable_type;
7356 block.layer_id = std::max<unsigned int>(1, m_layer_id);
7357 block.g1_line_id = m_g1_line_id;
7358 block.flags.prepare_stage = m_processing_start_custom_gcode;
7359 block.distance = 0.0f;
7360 block.calculate_trapezoid();
7361 machine.blocks.push_back(block);
7362 }
7363
7365
7367}
std::optional< MultiNozzleUtils::NozzleInfo > resolve_target_nozzle(const MultiNozzleUtils::NozzleGroupResultBase &group, int id, int nozzle_id) const
Definition GCodeProcessor.cpp:7243
bool use_multi_nozzle_change_time_model() const
Definition GCodeProcessor.cpp:7211

References Slic3r::GCodeProcessor::TimeMachine::blocks, Slic3r::GCodeProcessor::TimeBlock::calculate_trapezoid(), Slic3r::PrintEstimatedStatistics::Count, Slic3r::GCodeProcessor::TimeBlock::distance, Slic3r::GCodeProcessor::TimeMachine::enabled, Slic3r::GCodeProcessor::TimeBlock::flags, Slic3r::GCodeProcessor::TimeBlock::g1_line_id, get_extruder_change_time(), get_extruder_id(), get_filament_id(), get_filament_load_time(), get_filament_unload_time(), get_machine_config_idx(), Slic3r::GCodeProcessor::TimeBlock::layer_id, m_cp_color, m_extruder_colors, m_extruder_id, m_filament_id, m_g1_line_id, m_last_filament_id, m_layer_id, m_machine_config_idx, m_nozzle_group_result, m_nozzle_status_recorder, m_processing_start_custom_gcode, m_result, m_skippable_type, m_time_processor, Slic3r::GCodeProcessor::TimeBlock::move_id, Slic3r::GCodeProcessor::TimeBlock::move_type, Slic3r::GCodeProcessor::TimeBlock::Flags::prepare_stage, process_filament_change(), process_filaments(), resolve_target_nozzle(), simulate_st_synchronize(), Slic3r::GCodeProcessor::TimeBlock::skippable_type, store_move_vertex(), Slic3r::Tool_change, Slic3r::CustomGCode::ToolChange, and use_multi_nozzle_change_time_model().

Here is the call graph for this function:

◆ process_filaments()

void Slic3r::GCodeProcessor::process_filaments ( CustomGCode::Type code)
private
8038{
8039 if (code == CustomGCode::ColorChange)
8040 m_used_filaments.process_color_change_cache();
8041
8042 if (code == CustomGCode::ToolChange) {
8043 m_used_filaments.process_model_cache(this);
8044 m_used_filaments.process_support_cache(this);
8045 m_used_filaments.process_total_volume_cache(this);
8046 //BBS: reset remaining filament
8047 size_t last_extruder_id = get_extruder_id();
8048 m_remaining_volume[last_extruder_id] = m_nozzle_volume[last_extruder_id];
8049 }
8050}

References Slic3r::CustomGCode::ColorChange, get_extruder_id(), m_nozzle_volume, m_remaining_volume, m_used_filaments, and Slic3r::CustomGCode::ToolChange.

Referenced by process_filament_change(), process_filament_change(), and process_tags().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_file()

void Slic3r::GCodeProcessor::process_file ( const std::string & filename,
std::function< void()> cancel_callback = nullptr )
3840{
3841 CNumericLocalesSetter locales_setter;
3842
3843 // pre-processing
3844 // parse the gcode file to detect its producer
3845 {
3846 m_parser.parse_file_raw(filename, [this](GCodeReader& reader, const char *begin, const char *end) {
3847 begin = skip_whitespaces(begin, end);
3848 if (begin != end && *begin == ';') {
3849 // Comment.
3850 begin = skip_whitespaces(++ begin, end);
3851 end = remove_eols(begin, end);
3852 if (begin != end) {
3854 if (detect_producer(std::string_view(begin, end - begin))) {
3855 m_parser.quit_parsing();
3856 }
3857 } else if (std::string(begin, end).find("CONFIG_BLOCK_END") != std::string::npos) {
3858 m_parser.quit_parsing();
3859 }
3860 }
3861 }
3862 });
3863 m_parser.reset();
3864
3865 // if the gcode was produced by OrcaSlicer,
3866 // extract the config from it
3868 DynamicPrintConfig config;
3869 config.apply(FullPrintConfig::defaults());
3870 // Silently substitute unknown values by new ones for loading configurations from OrcaSlicer's own G-code.
3871 // Showing substitution log or errors may make sense, but we are not really reading many values from the G-code config,
3872 // thus a probability of incorrect substitution is low and the G-code viewer is a consumer-only anyways.
3873 config.load_from_gcode_file(filename, ForwardCompatibilitySubstitutionRule::EnableSilent);
3874
3875 // Get the correct printer vendor based on the `printer_model` field
3876 auto printer_model_opt = config.opt<ConfigOptionString>("printer_model");
3877 if (printer_model_opt && !printer_model_opt->value.empty()) {
3878 // TODO: Orca hack, proper vendor check?
3879 GCodeProcessor::s_IsBBLPrinter = boost::starts_with(printer_model_opt->value, "Bambu Lab");
3880 }
3881
3882 ConfigOptionStrings *filament_color = config.opt<ConfigOptionStrings>("filament_colour");
3883 ConfigOptionInts *filament_map = config.opt<ConfigOptionInts>("filament_map", true);
3884 if (filament_color && filament_color->size() != filament_map->size()) {
3885 filament_map->values.resize(filament_color->size(), 1);
3886 }
3887
3888 apply_config(config);
3889 }
3891 apply_config_simplify3d(filename);
3893 apply_config_superslicer(filename);
3894 }
3895
3896 // process gcode
3897 m_result.filename = filename;
3898 m_result.id = ++s_result_id;
3900 size_t parse_line_callback_cntr = 10000;
3901 m_parser.parse_file(filename, [this, cancel_callback, &parse_line_callback_cntr](GCodeReader& reader, const GCodeReader::GCodeLine& line) {
3902 if (-- parse_line_callback_cntr == 0) {
3903 // Don't call the cancel_callback() too often, do it every at every 10000'th line.
3904 parse_line_callback_cntr = 10000;
3905 if (cancel_callback)
3906 cancel_callback();
3907 }
3908 this->process_gcode_line(line, true);
3909 }, m_result.lines_ends);
3910
3911 // Don't post-process the G-code to update time stamps.
3912 this->finalize(false);
3913}
bool detect_producer(const std::string_view comment)
Definition GCodeProcessor.cpp:5143
void initialize_result_moves()
Definition GCodeProcessor.hpp:1445
void apply_config_superslicer(const std::string &filename)
Definition GCodeProcessor.cpp:4066
void finalize(bool post_process)
Definition GCodeProcessor.cpp:3966
void apply_config_simplify3d(const std::string &filename)
Definition GCodeProcessor.cpp:4079
@ SuperSlicer
Definition GCodeProcessor.hpp:1362
@ Simplify3D
Definition GCodeProcessor.hpp:1364
@ OrcaSlicer
Definition GCodeProcessor.hpp:1359
@ Slic3rPE
Definition GCodeProcessor.hpp:1360
@ Unknown
Definition GCodeProcessor.hpp:1358
@ Slic3r
Definition GCodeProcessor.hpp:1361
RaycastManager::TrItems::iterator find(RaycastManager::TrItems &items, const RaycastManager::TrKey &key)
Definition RaycastManager.cpp:298

References Slic3r::ConfigBase::apply(), apply_config(), apply_config_simplify3d(), apply_config_superslicer(), detect_producer(), Slic3r::EnableSilent, Slic3r::filament_map(), finalize(), initialize_result_moves(), Slic3r::ConfigBase::load_from_gcode_file(), m_parser, m_producer, m_result, Slic3r::DynamicConfig::opt(), OrcaSlicer, process_gcode_line(), Slic3r::remove_eols(), s_IsBBLPrinter, s_result_id, Simplify3D, Slic3r::ConfigOptionVector< T >::size(), Slic3r::skip_whitespaces(), Slic3r, Slic3rPE, SuperSlicer, and Unknown.

Referenced by Slic3r::Print::export_gcode_from_previous_file(), Slic3r::GUI::Plater::load_gcode(), and Slic3r::Print::reload_gcode_moves().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_G0()

void Slic3r::GCodeProcessor::process_G0 ( const GCodeReader::GCodeLine & line)
private
5157{
5158 process_G1(line);
5159}
void process_G1(const GCodeReader::GCodeLine &line, const std::optional< unsigned int > &remaining_internal_g1_lines=std::nullopt)
Definition GCodeProcessor.cpp:5185

References process_G1().

Referenced by register_commands().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_G1() [1/2]

void Slic3r::GCodeProcessor::process_G1 ( const GCodeReader::GCodeLine & line,
const std::optional< unsigned int > & remaining_internal_g1_lines = std::nullopt )
private
5186{
5187 std::array<std::optional<double>, 4> g1_axes = { std::nullopt, std::nullopt, std::nullopt, std::nullopt };
5188 if (line.has_x()) g1_axes[X] = (double)line.x();
5189 if (line.has_y()) g1_axes[Y] = (double)line.y();
5190 if (line.has_z()) g1_axes[Z] = (double)line.z();
5191 if (line.has_e()) g1_axes[E] = (double)line.e();
5192 std::optional<double> g1_feedrate = std::nullopt;
5193 if (line.has_f()) g1_feedrate = (double)line.f();
5194 if (m_flavor == gcfKlipper) {
5195 // Preserve decimal coordinates for short segments without parsing twice.
5196 for (unsigned char axis = X; axis <= E; ++axis)
5197 if (line.has(static_cast<Axis>(axis)))
5198 g1_axes[axis] = line.precise_value(static_cast<Axis>(axis));
5199 if (line.has_f())
5200 g1_feedrate = line.precise_value(F);
5201 }
5202 process_G1(g1_axes, g1_feedrate);
5203}
@ F
Definition libslic3r.h:145

References Slic3r::E, Slic3r::GCodeReader::GCodeLine::e(), Slic3r::F, Slic3r::GCodeReader::GCodeLine::f(), Slic3r::gcfKlipper, Slic3r::GCodeReader::GCodeLine::has(), Slic3r::GCodeReader::GCodeLine::has_e(), Slic3r::GCodeReader::GCodeLine::has_f(), Slic3r::GCodeReader::GCodeLine::has_x(), Slic3r::GCodeReader::GCodeLine::has_y(), Slic3r::GCodeReader::GCodeLine::has_z(), m_flavor, Slic3r::GCodeReader::GCodeLine::precise_value(), process_G1(), Slic3r::X, Slic3r::GCodeReader::GCodeLine::x(), Slic3r::Y, Slic3r::GCodeReader::GCodeLine::y(), Slic3r::Z, and Slic3r::GCodeReader::GCodeLine::z().

Referenced by process_G0(), process_G1(), process_G10(), process_G11(), process_G28(), process_G2_G3(), and register_commands().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_G1() [2/2]

void Slic3r::GCodeProcessor::process_G1 ( const std::array< std::optional< double >, 4 > & axes = { std::nullopt, std::nullopt, std::nullopt, std::nullopt },
const std::optional< double > & feedrate = std::nullopt,
G1DiscretizationOrigin origin = G1DiscretizationOrigin::G1,
const std::optional< unsigned int > & remaining_internal_g1_lines = std::nullopt )
private
5207{
5208 const std::array<bool, 3> start_axis_known = m_axis_position_known;
5209 int filament_id = get_filament_id();
5210 int last_filament_id = get_last_filament_id();
5211 float filament_diameter = (static_cast<size_t>(filament_id) < m_result.filament_diameters.size()) ? m_result.filament_diameters[filament_id] : m_result.filament_diameters.back();
5212 float filament_radius = 0.5f * filament_diameter;
5213 float area_filament_cross_section = static_cast<float>(M_PI) * sqr(filament_radius);
5214
5215 auto move_type = [this](const AxisCoords& delta_pos) {
5216 if (m_wiping)
5217 return EMoveType::Wipe;
5218 else if (delta_pos[E] < 0.0f)
5219 return (delta_pos[X] != 0.0f || delta_pos[Y] != 0.0f || delta_pos[Z] != 0.0f) ? EMoveType::Travel : EMoveType::Retract;
5220 else if (delta_pos[E] > 0.0f) {
5221 if (delta_pos[X] == 0.0f && delta_pos[Y] == 0.0f)
5222 return (delta_pos[Z] == 0.0f) ? EMoveType::Unretract : EMoveType::Travel;
5223 else if (delta_pos[X] != 0.0f || delta_pos[Y] != 0.0f)
5224 return EMoveType::Extrude;
5225 }
5226 else if (delta_pos[X] != 0.0f || delta_pos[Y] != 0.0f || delta_pos[Z] != 0.0f)
5227 return EMoveType::Travel;
5228
5229 return EMoveType::Noop;
5230 };
5231
5232 auto extract_absolute_position_on_axis = [&](Axis axis, std::optional<double> value, double area_filament_cross_section)
5233 {
5234 if (value.has_value()) {
5236 if (axis == E)
5238
5239 const double lengthsScaleFactor = (m_units == EUnits::Inches) ? double(INCHES_TO_MM) : 1.0;
5240 double ret = *value * lengthsScaleFactor;
5241 // if (axis == E && m_use_volumetric_e)
5242 // ret /= area_filament_cross_section;
5243 return is_relative ? m_start_position[axis] + ret : m_origin[axis] + ret;
5244 }
5245 else
5246 return m_start_position[axis];
5247 };
5248
5249 ++m_g1_line_id;
5250
5251 // enable processing of lines M201/M203/M204/M205
5252 m_time_processor.machine_envelope_processing_enabled = true;
5253
5254 // updates axes positions from line
5255 for (unsigned char a = X; a <= E; ++a) {
5256 m_end_position[a] = extract_absolute_position_on_axis((Axis)a, axes[a], double(area_filament_cross_section));
5257 }
5258 update_position_known_from_move(axes, origin);
5259
5260 // updates feedrate from line, if present
5261 if (feedrate.has_value())
5262 m_feedrate = (*feedrate) * MMMIN_TO_MMSEC;
5263
5264 // calculates movement deltas
5265 float max_abs_delta = 0.0f;
5266 AxisCoords delta_pos;
5267 for (unsigned char a = X; a <= E; ++a) {
5268 delta_pos[a] = m_end_position[a] - m_start_position[a];
5269 max_abs_delta = std::max<float>(max_abs_delta, std::abs(delta_pos[a]));
5270 }
5271
5272 // no displacement, return
5273 if (max_abs_delta == 0.0f)
5274 return;
5275
5276 EMoveType type = move_type(delta_pos);
5277 const float delta_xyz = std::sqrt(sqr(delta_pos[X]) + sqr(delta_pos[Y]) + sqr(delta_pos[Z]));
5278 m_travel_dist = delta_xyz;
5279
5281 std::optional<ExclusionVolumeMotionType> exclusion_motion_type;
5282 switch (type) {
5283 case EMoveType::Travel:
5284 exclusion_motion_type = ExclusionVolumeMotionType::Travel;
5285 break;
5286 case EMoveType::Extrude:
5287 case EMoveType::Wipe:
5288 exclusion_motion_type = ExclusionVolumeMotionType::Extrude;
5289 break;
5290 case EMoveType::Retract:
5292 exclusion_motion_type = ExclusionVolumeMotionType::Other;
5293 break;
5294 default:
5295 break;
5296 }
5297
5298 if (exclusion_motion_type) {
5302 start_axis_known[X] && start_axis_known[Y],
5304 start_axis_known[Z],
5306 get_extruder_id(false),
5307 *exclusion_motion_type,
5308 static_cast<unsigned char>(type),
5309 m_line_id,
5310 m_result.moves.size());
5311 }
5312 }
5313
5314 if (type == EMoveType::Extrude) {
5315 float volume_extruded_filament = area_filament_cross_section * delta_pos[E];
5316 float area_toolpath_cross_section = volume_extruded_filament / delta_xyz;
5317
5319 m_used_filaments.increase_support_caches(volume_extruded_filament);
5321 m_used_filaments.increase_wipe_tower_caches(volume_extruded_filament);
5322 }
5323 else {
5324 // save extruded volume to the cache
5325 m_used_filaments.increase_model_caches(volume_extruded_filament);
5326 }
5327 // volume extruded filament / tool displacement = area toolpath cross section
5328 m_mm3_per_mm = area_toolpath_cross_section;
5329
5330 if (m_forced_height > 0.0f)
5332 else if (origin == G1DiscretizationOrigin::G1) {
5335 }
5336
5337 if (m_height == 0.0f)
5339
5340 if (m_end_position[Z] == 0.0f)
5342
5343 if (origin == G1DiscretizationOrigin::G1)
5345 // The queued blocks of the moves after the erased one follow them down the list.
5346 if (const std::optional<size_t> erased = m_options_z_corrector.update(m_height)) {
5347 for (TimeMachine& machine : m_time_processor.machines) {
5348 for (TimeBlock& block : machine.blocks) {
5349 if (block.move_id > *erased)
5350 --block.move_id;
5351 }
5352 }
5353 }
5354
5355 if (m_forced_width > 0.0f)
5358 // cross section: rectangle
5359 m_width = delta_pos[E] * static_cast<float>(M_PI * sqr(1.05f * filament_radius)) / (delta_xyz * m_height);
5361 // cross section: circle
5362 m_width = static_cast<float>(m_result.filament_diameters[filament_id]) * std::sqrt(delta_pos[E] / delta_xyz);
5363 else
5364 // cross section: rectangle + 2 semicircles
5365 m_width = delta_pos[E] * static_cast<float>(M_PI * sqr(filament_radius)) / (delta_xyz * m_height) + static_cast<float>(1.0 - 0.25 * M_PI) * m_height;
5366
5367 if (m_width == 0.0f)
5369
5370 // clamp width to avoid artifacts which may arise from wrong values of m_height
5371 m_width = std::min(m_width, std::max(2.0f, 4.0f * m_height));
5372 }
5373 else if (type == EMoveType::Unretract && m_flushing) {
5374 int extruder_id = get_extruder_id();
5375 float volume_flushed_filament = area_filament_cross_section * delta_pos[E];
5376 if (m_remaining_volume[extruder_id] > volume_flushed_filament)
5377 {
5378 m_used_filaments.update_flush_per_filament(last_filament_id, volume_flushed_filament);
5379 m_remaining_volume[extruder_id] -= volume_flushed_filament;
5380 }
5381 else {
5382 m_used_filaments.update_flush_per_filament(last_filament_id, m_remaining_volume[extruder_id]);
5383 m_used_filaments.update_flush_per_filament(filament_id, volume_flushed_filament - m_remaining_volume[extruder_id]);
5384 m_remaining_volume[extruder_id] = 0.f;
5385 }
5386 }
5387
5388 // time estimate section
5389 auto move_length = [](const AxisCoords& delta_pos) {
5390 float sq_xyz_length = sqr(delta_pos[X]) + sqr(delta_pos[Y]) + sqr(delta_pos[Z]);
5391 return (sq_xyz_length > 0.0f) ? std::sqrt(sq_xyz_length) : std::abs(delta_pos[E]);
5392 };
5393
5394 auto is_extrusion_only_move = [](const AxisCoords& delta_pos) {
5395 return delta_pos[X] == 0.0f && delta_pos[Y] == 0.0f && delta_pos[Z] == 0.0f && delta_pos[E] != 0.0f;
5396 };
5397
5398 float distance = move_length(delta_pos);
5399 assert(distance != 0.0f);
5400 float inv_distance = 1.0f / distance;
5401
5402 for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
5403 TimeMachine& machine = m_time_processor.machines[i];
5404 if (!machine.enabled)
5405 continue;
5406
5407 TimeMachine::State& curr = machine.curr;
5408 TimeMachine::State& prev = machine.prev;
5409 std::vector<TimeBlock>& blocks = machine.blocks;
5410
5411 curr.feedrate = (delta_pos[E] == 0.0f) ?
5414
5415 //BBS: calculeta enter and exit direction
5416 curr.enter_direction = { static_cast<float>(delta_pos[X]), static_cast<float>(delta_pos[Y]), static_cast<float>(delta_pos[Z]) };
5417 float norm = curr.enter_direction.norm();
5418 if (!is_extrusion_only_move(delta_pos))
5419 curr.enter_direction = curr.enter_direction / norm;
5420 curr.exit_direction = curr.enter_direction;
5421 curr.jd_unit_vec = Vec4f(static_cast<float>(delta_pos[X]),
5422 static_cast<float>(delta_pos[Y]),
5423 static_cast<float>(delta_pos[Z]),
5424 static_cast<float>(delta_pos[E])).normalized();
5425
5426 TimeBlock block;
5427 block.move_type = type;
5428 // stamp the current SKIPPABLE type onto the block. Stamped stTimelapse inside the fleet-wide
5429 // time_lapse_gcode regions; byte-inert because nothing reads the stamp until the injector
5430 // consumes it.
5431 block.skippable_type = m_skippable_type;
5432 //BBS: don't calculate travel time into extrusion path, except travel inside start and end gcode.
5433 block.role = (type != EMoveType::Travel || m_extrusion_role == erCustom) ? m_extrusion_role : erNone;
5434 block.distance = distance;
5435 block.g1_line_id = m_g1_line_id;
5436 block.move_id = static_cast<unsigned int>(m_result.moves.size());
5437 block.remaining_internal_g1_lines = remaining_internal_g1_lines.has_value() ? *remaining_internal_g1_lines : 0;
5438 block.layer_id = std::max<unsigned int>(1, m_layer_id);
5439 block.flags.prepare_stage = m_processing_start_custom_gcode;
5440
5441 //BBS: limite the cruise according to centripetal acceleration
5442 //Only need to handle when both prev and curr segment has movement in x-y plane
5443 if (m_flavor != gcfKlipper && (prev.exit_direction(0) != 0.0f || prev.exit_direction(1) != 0.0f) &&
5444 (curr.enter_direction(0) != 0.0f || curr.enter_direction(1) != 0.0f)) {
5445 Vec3f v1 = prev.exit_direction;
5446 v1(2, 0) = 0.0f;
5447 v1.normalize();
5448 Vec3f v2 = curr.enter_direction;
5449 v2(2, 0) = 0.0f;
5450 v2.normalize();
5451 float norm_diff = (v2 - v1).norm();
5452 //BBS: don't need to consider limitation of centripetal acceleration
5453 //when angle changing is larger than 28.96 degree or two lines are almost collinear.
5454 //Attention!!! these two value must be same with MC side.
5455 if (norm_diff < 0.5f && norm_diff > 0.00001f) {
5456 //BBS: calculate angle
5457 float dot = v1(0) * v2(0) + v1(1) * v2(1);
5458 float cross = v1(0) * v2(1) - v1(1) * v2(0);
5459 float angle = float(atan2(double(cross), double(dot)));
5460 float sin_theta_2 = sqrt((1.0f - cos(angle)) * 0.5f);
5461 float r = sqrt(sqr(delta_pos[X]) + sqr(delta_pos[Y])) * 0.5 / sin_theta_2;
5462 float acc = get_acceleration(static_cast<PrintEstimatedStatistics::ETimeMode>(i));
5463 curr.feedrate = std::min(curr.feedrate, sqrt(acc * r));
5464 }
5465 }
5466
5467 if (m_flavor == gcfKlipper && !is_extrusion_only_move(delta_pos)) {
5468 const float max_velocity = get_axis_max_feedrate(static_cast<PrintEstimatedStatistics::ETimeMode>(i), X, m_machine_config_idx);
5469 if (max_velocity > 0.0f)
5470 curr.feedrate = std::min(curr.feedrate, max_velocity);
5471 }
5472 // Klipper applies E limits to retractions and moves without XY motion,
5473 // not to positive extrusion along a printing path.
5474 const bool limit_extruder = m_flavor != gcfKlipper || delta_pos[E] < 0.0 ||
5475 (delta_pos[X] == 0.0 && delta_pos[Y] == 0.0);
5476 // calculates block cruise feedrate
5477 float min_feedrate_factor = 1.0f;
5478 for (unsigned char a = X; a <= E; ++a) {
5479 curr.axis_feedrate[a] = curr.feedrate * delta_pos[a] * inv_distance;
5480 if (a == E)
5481 curr.axis_feedrate[a] *= machine.extrude_factor_override_percentage;
5482
5483 curr.abs_axis_feedrate[a] = std::abs(curr.axis_feedrate[a]);
5484 if (curr.abs_axis_feedrate[a] != 0.0f && (a != E || limit_extruder) &&
5485 (m_flavor != gcfKlipper || a == Z || a == E)) {
5486 float axis_max_feedrate = get_axis_max_feedrate(static_cast<PrintEstimatedStatistics::ETimeMode>(i), static_cast<Axis>(a), m_machine_config_idx);
5487 if (axis_max_feedrate != 0.0f) min_feedrate_factor = std::min<float>(min_feedrate_factor, axis_max_feedrate / curr.abs_axis_feedrate[a]);
5488 }
5489 }
5490 //BBS: update curr.feedrate
5491 curr.feedrate *= min_feedrate_factor;
5492 block.feedrate_profile.cruise = curr.feedrate;
5493
5494 if (min_feedrate_factor < 1.0f) {
5495 for (unsigned char a = X; a <= E; ++a) {
5496 curr.axis_feedrate[a] *= min_feedrate_factor;
5497 curr.abs_axis_feedrate[a] *= min_feedrate_factor;
5498 }
5499 }
5500
5501 // calculates block acceleration
5502 float acceleration;
5503 if (m_flavor == gcfKlipper && is_extrusion_only_move(delta_pos)) {
5504 // Klipper's max_extrude_only_accel. machine_max_acceleration_e is optional and some
5505 // shipped profiles leave it at 0, so keep the non-zero retract fallback.
5507 if (acceleration <= 0.0f)
5508 acceleration = get_retract_acceleration(static_cast<PrintEstimatedStatistics::ETimeMode>(i));
5509 } else
5510 acceleration =
5513 (is_extrusion_only_move(delta_pos) ?
5515 get_acceleration(static_cast<PrintEstimatedStatistics::ETimeMode>(i)));
5516
5517 //BBS
5518 for (unsigned char a = X; a <= E; ++a) {
5519 if ((a == E && !limit_extruder) || (m_flavor == gcfKlipper && (a == X || a == Y)))
5520 continue;
5521 float axis_max_acceleration = get_axis_max_acceleration(static_cast<PrintEstimatedStatistics::ETimeMode>(i), static_cast<Axis>(a), m_machine_config_idx);
5522 // An unset (0) limit means "no limit", as in the feedrate loop above. Only the Klipper
5523 // planner divides by the block acceleration, so leave the Marlin path as it was.
5524 if (m_flavor == gcfKlipper && axis_max_acceleration <= 0.0f)
5525 continue;
5526 if (acceleration * std::abs(delta_pos[a]) * inv_distance > axis_max_acceleration)
5527 acceleration = axis_max_acceleration / (std::abs(delta_pos[a]) * inv_distance);
5528 }
5529
5530 block.acceleration = acceleration;
5531 if (m_flavor == gcfKlipper) {
5532 block.junction_deviation = get_junction_deviation(static_cast<PrintEstimatedStatistics::ETimeMode>(i), acceleration);
5533 const float cruise_acceleration = machine.requested_accel_to_decel >= 0.0f ?
5534 std::min(machine.acceleration, machine.requested_accel_to_decel) :
5535 machine.acceleration * (1.0f - machine.minimum_cruise_ratio);
5536 block.mcr_delta_v2 = 2.0f * distance * std::min(acceleration, cruise_acceleration);
5537 }
5538
5539 static const float PREVIOUS_FEEDRATE_THRESHOLD = 0.0001f;
5540 const bool has_prev_move = !blocks.empty() && prev.feedrate > PREVIOUS_FEEDRATE_THRESHOLD;
5541
5542 // Orca: junction deviation where the firmware uses it (Klipper always, Marlin 2 with M205 J).
5543 // Negative leaves the classic jerk path below unchanged.
5544 const float vmax_junction_jd = calc_vmax_junction_deviation(block, prev, curr, has_prev_move,
5545 static_cast<PrintEstimatedStatistics::ETimeMode>(i));
5546 const bool use_junction_deviation = vmax_junction_jd >= 0.0f;
5547
5548 // calculates block exit feedrate. Junction deviation has no per axis jerk floor, so a move is
5549 // free to start from rest.
5550 curr.safe_feedrate = use_junction_deviation ? 0.0f : block.feedrate_profile.cruise;
5551
5552 if (!use_junction_deviation) {
5553 for (unsigned char a = X; a <= E; ++a) {
5554 float axis_max_jerk = get_axis_max_jerk(static_cast<PrintEstimatedStatistics::ETimeMode>(i), static_cast<Axis>(a));
5555 if (curr.abs_axis_feedrate[a] > axis_max_jerk)
5556 curr.safe_feedrate = std::min(curr.safe_feedrate, axis_max_jerk);
5557 }
5558 }
5559
5560 block.feedrate_profile.exit = curr.safe_feedrate;
5561
5562 // calculates block entry feedrate
5563 float vmax_junction = use_junction_deviation ? vmax_junction_jd : curr.safe_feedrate;
5564 if (!use_junction_deviation && has_prev_move) {
5565 bool prev_speed_larger = prev.feedrate > block.feedrate_profile.cruise;
5566 float smaller_speed_factor = prev_speed_larger ? (block.feedrate_profile.cruise / prev.feedrate) : (prev.feedrate / block.feedrate_profile.cruise);
5567 // Pick the smaller of the nominal speeds. Higher speed shall not be achieved at the junction during coasting.
5568 vmax_junction = prev_speed_larger ? block.feedrate_profile.cruise : prev.feedrate;
5569
5570 float v_factor = 1.0f;
5571 bool limited = false;
5572
5573 for (unsigned char a = X; a <= E; ++a) {
5574 // Limit an axis. We have to differentiate coasting from the reversal of an axis movement, or a full stop.
5575 if (a == X) {
5576 Vec3f exit_v = prev.feedrate * (prev.exit_direction);
5577 if (prev_speed_larger)
5578 exit_v *= smaller_speed_factor;
5579 Vec3f entry_v = block.feedrate_profile.cruise * (curr.enter_direction);
5580 Vec3f jerk_v = entry_v - exit_v;
5581 jerk_v = Vec3f(abs(jerk_v.x()), abs(jerk_v.y()), abs(jerk_v.z()));
5582 Vec3f max_xyz_jerk_v = get_xyz_max_jerk(static_cast<PrintEstimatedStatistics::ETimeMode>(i));
5583
5584 for (size_t i = 0; i < 3; i++)
5585 {
5586 if (jerk_v[i] > max_xyz_jerk_v[i]) {
5587 v_factor *= max_xyz_jerk_v[i] / jerk_v[i];
5588 jerk_v *= v_factor;
5589 limited = true;
5590 }
5591 }
5592 }
5593 else if (a == Y || a == Z) {
5594 continue;
5595 }
5596 else {
5597 float v_exit = prev.axis_feedrate[a];
5598 float v_entry = curr.axis_feedrate[a];
5599
5600 if (prev_speed_larger)
5601 v_exit *= smaller_speed_factor;
5602
5603 if (limited) {
5604 v_exit *= v_factor;
5605 v_entry *= v_factor;
5606 }
5607
5608 // Calculate the jerk depending on whether the axis is coasting in the same direction or reversing a direction.
5609 float jerk =
5610 (v_exit > v_entry) ?
5611 (((v_entry > 0.0f) || (v_exit < 0.0f)) ?
5612 // coasting
5613 (v_exit - v_entry) :
5614 // axis reversal
5615 std::max(v_exit, -v_entry)) :
5616 // v_exit <= v_entry
5617 (((v_entry < 0.0f) || (v_exit > 0.0f)) ?
5618 // coasting
5619 (v_entry - v_exit) :
5620 // axis reversal
5621 std::max(-v_exit, v_entry));
5622
5623
5624 float axis_max_jerk = get_axis_max_jerk(static_cast<PrintEstimatedStatistics::ETimeMode>(i), static_cast<Axis>(a));
5625 if (jerk > axis_max_jerk) {
5626 v_factor *= axis_max_jerk / jerk;
5627 limited = true;
5628 }
5629 }
5630 }
5631
5632 if (limited)
5633 vmax_junction *= v_factor;
5634
5635 // Now the transition velocity is known, which maximizes the shared exit / entry velocity while
5636 // respecting the jerk factors, it may be possible, that applying separate safe exit / entry velocities will achieve faster prints.
5637 float vmax_junction_threshold = vmax_junction * 0.99f;
5638
5639 // Not coasting. The machine will stop and start the movements anyway, better to start the segment from start.
5640 if (prev.safe_feedrate > vmax_junction_threshold && curr.safe_feedrate > vmax_junction_threshold)
5641 vmax_junction = curr.safe_feedrate;
5642 }
5643
5644 float v_allowable = max_allowable_speed(-acceleration, curr.safe_feedrate, block.distance);
5645 block.feedrate_profile.entry = std::min(vmax_junction, v_allowable);
5646
5647 block.max_entry_speed = vmax_junction;
5648 if (m_flavor == gcfKlipper && has_prev_move) {
5649 const TimeBlock& previous = blocks.back();
5650 block.max_entry_speed = std::min(block.max_entry_speed,
5651 std::sqrt(sqr(previous.max_entry_speed) + 2.0f * previous.distance * previous.acceleration));
5652 block.max_mcr_entry_speed_sqr = std::min(sqr(block.max_entry_speed), previous.max_mcr_entry_speed_sqr + previous.mcr_delta_v2);
5653 }
5654 block.flags.nominal_length = (block.feedrate_profile.cruise <= v_allowable);
5655 block.flags.recalculate = true;
5656 block.safe_feedrate = curr.safe_feedrate;
5657
5658 // calculates block trapezoid
5659 block.calculate_trapezoid();
5660
5661 // updates previous
5662 prev = curr;
5663
5664 blocks.push_back(block);
5665 if (m_flavor == gcfKlipper && blocks.size() > 1)
5666 machine.klipper_junction_flush -= distance / curr.feedrate;
5667 }
5668
5669 if (m_flavor == gcfKlipper ? m_time_processor.machines[0].klipper_junction_flush <= 0.0f :
5672
5673 const Vec3f plate_offset = {(float) m_x_offset, (float) m_y_offset, 0.0f};
5674
5675 if (m_seams_detector.is_active()) {
5676 // check for seam starting vertex
5678 //BBS: m_result.moves.back().position has plate offset, must minus plate offset before calculate the real seam position
5679 const Vec3f new_pos = m_result.moves.back().position - m_extruder_offsets[filament_id] - plate_offset;
5680 if (!m_seams_detector.has_first_vertex()) {
5681 m_seams_detector.set_first_vertex(new_pos);
5682 } else if (m_detect_layer_based_on_tag) {
5683 // We may have sloped loop, drop any previous start pos if we have z increment
5684 const std::optional<Vec3f> first_vertex = m_seams_detector.get_first_vertex();
5685 if (new_pos.z() > first_vertex->z()) {
5686 m_seams_detector.set_first_vertex(new_pos);
5687 }
5688 }
5689 }
5690 // check for seam ending vertex and store the resulting move
5692 auto set_end_position = [this](const Vec3f& pos) {
5693 m_end_position[X] = pos.x(); m_end_position[Y] = pos.y(); m_end_position[Z] = pos.z();
5694 };
5695
5696 const Vec3f curr_pos(m_end_position[X], m_end_position[Y], m_end_position[Z]);
5697 //BBS: m_result.moves.back().position has plate offset, must minus plate offset before calculate the real seam position
5698 const Vec3f new_pos = m_result.moves.back().position - m_extruder_offsets[filament_id] - plate_offset;
5699 const std::optional<Vec3f> first_vertex = m_seams_detector.get_first_vertex();
5700 // the threshold value = 0.0625f == 0.25 * 0.25 is arbitrary, we may find some smarter condition later
5701
5702 if ((new_pos - *first_vertex).squaredNorm() < 0.0625f) {
5703 set_end_position(0.5f * (new_pos + *first_vertex) + m_z_offset * Vec3f::UnitZ());
5705 set_end_position(curr_pos);
5706 }
5707
5708 m_seams_detector.activate(false);
5709 }
5710 }
5712 m_seams_detector.activate(true);
5713 m_seams_detector.set_first_vertex(m_result.moves.back().position - m_extruder_offsets[filament_id] - plate_offset);
5714 }
5715
5716 if (type == EMoveType::Extrude)
5717 add_object_mass(filament_id, area_filament_cross_section * delta_pos[E]);
5718
5719 // store move
5720 store_move_vertex(type);
5721}
#define EPSILON
Definition ColorUtils.cpp:64
static const float DEFAULT_TOOLPATH_HEIGHT
Definition GCodeProcessor.cpp:82
static const float MMMIN_TO_MMSEC
Definition GCodeProcessor.cpp:85
float m_width
Definition GCodeProcessor.hpp:1313
bool m_processing_homing_move
Definition GCodeProcessor.hpp:1234
float m_travel_dist
Definition GCodeProcessor.hpp:1318
void add_object_mass(int filament_id, float volume)
Definition GCodeProcessor.cpp:7607
float get_axis_max_jerk(PrintEstimatedStatistics::ETimeMode mode, Axis axis) const
Definition GCodeProcessor.cpp:7899
float get_retract_acceleration(PrintEstimatedStatistics::ETimeMode mode) const
Definition GCodeProcessor.cpp:7943
float minimum_feedrate(PrintEstimatedStatistics::ETimeMode mode, float feedrate) const
Definition GCodeProcessor.cpp:7687
double extract_absolute_position_on_axis(Axis axis, const GCodeReader::GCodeLine &line, double area_filament_cross_section)
Definition GCodeProcessor.cpp:8172
float calc_vmax_junction_deviation(const TimeBlock &block, const TimeMachine::State &prev, const TimeMachine::State &curr, bool has_prev_move, PrintEstimatedStatistics::ETimeMode mode) const
Definition GCodeProcessor.cpp:7824
bool m_wiping
Definition GCodeProcessor.hpp:1237
float m_mm3_per_mm
Definition GCodeProcessor.hpp:1317
float get_travel_acceleration(PrintEstimatedStatistics::ETimeMode mode) const
Definition GCodeProcessor.cpp:7975
float m_forced_width
Definition GCodeProcessor.hpp:1315
Vec3f get_xyz_max_jerk(PrintEstimatedStatistics::ETimeMode mode) const
Definition GCodeProcessor.cpp:7917
float m_forced_height
Definition GCodeProcessor.hpp:1316
@ G1
Definition GCodeProcessor.hpp:1490
std::array< double, 4 > AxisCoords
Definition GCodeProcessor.hpp:653
float minimum_travel_feedrate(PrintEstimatedStatistics::ETimeMode mode, float feedrate) const
Definition GCodeProcessor.cpp:7695
float m_feedrate
Definition GCodeProcessor.hpp:1312
unsigned int m_line_id
Definition GCodeProcessor.hpp:1310
int get_last_filament_id(bool force_initialize=true) const
Definition GCodeProcessor.cpp:8307
float m_extruded_last_z
Definition GCodeProcessor.hpp:1335
bool m_flushing
Definition GCodeProcessor.hpp:1238
void update_position_known_from_move(const std::array< std::optional< double >, 4 > &axes, G1DiscretizationOrigin origin)
Definition GCodeProcessor.cpp:5161
float distance(SpiralVase::SpiralPoint a, SpiralVase::SpiralPoint b)
Definition SpiralVase.cpp:19
@ erBridgeInfill
Definition ExtrusionEntity.hpp:36
@ erInternalBridgeInfill
Definition ExtrusionEntity.hpp:37
@ erSupportTransition
Definition ExtrusionEntity.hpp:43
@ erOverhangPerimeter
Definition ExtrusionEntity.hpp:30
static float max_allowable_speed(float acceleration, float target_velocity, float distance)
Definition GCodeProcessor.cpp:227
T cross(const boost::geometry::model::d2::point_xy< T > &v1, const boost::geometry::model::d2::point_xy< T > &v2)
Definition ExtrusionSimulator.cpp:168
double angle(const Eigen::MatrixBase< Derived > &v1, const Eigen::MatrixBase< Derived2 > &v2)
Definition Point.hpp:138
@ Travel
Definition ExclusionVolumePathCheck.hpp:17
@ Other
Definition ExclusionVolumePathCheck.hpp:19
@ Extrude
Definition ExclusionVolumePathCheck.hpp:18
EMoveType
Definition GCodeProcessor.hpp:53
@ Retract
Definition GCodeProcessor.hpp:55
@ Travel
Definition GCodeProcessor.hpp:62
@ Unretract
Definition GCodeProcessor.hpp:56
ETimeMode
Definition Types.hpp:200
EMoveType move_type
Definition GCodeProcessor.hpp:717
Definition GCodeProcessor.hpp:755
float feedrate
Definition GCodeProcessor.hpp:756
static constexpr size_t refresh_threshold
Definition GCodeProcessor.hpp:933
static constexpr size_t queue_size
Definition GCodeProcessor.hpp:930

References Slic3r::GCodeProcessor::TimeMachine::State::abs_axis_feedrate, Slic3r::GCodeProcessor::TimeBlock::acceleration, Slic3r::GCodeProcessor::TimeMachine::acceleration, add_object_mass(), Slic3r::angle(), Slic3r::GCodeProcessor::TimeMachine::State::axis_feedrate, Slic3r::GCodeProcessor::TimeMachine::blocks, calc_vmax_junction_deviation(), calculate_time(), Slic3r::GCodeProcessor::TimeBlock::calculate_trapezoid(), Slic3r::PrintEstimatedStatistics::Count, Slic3r::cross(), Slic3r::GCodeProcessor::FeedrateProfile::cruise, Slic3r::GCodeProcessor::TimeMachine::curr, DEFAULT_TOOLPATH_HEIGHT, DEFAULT_TOOLPATH_WIDTH, Slic3r::GCodeProcessor::TimeBlock::distance, Slic3r::dot(), Slic3r::E, Slic3r::GCodeProcessor::TimeMachine::enabled, Slic3r::GCodeProcessor::TimeMachine::State::enter_direction, Slic3r::GCodeProcessor::FeedrateProfile::entry, EPSILON, Slic3r::erBridgeInfill, Slic3r::erCustom, Slic3r::erExternalPerimeter, Slic3r::erInternalBridgeInfill, Slic3r::erNone, Slic3r::erOverhangPerimeter, Slic3r::erSupportMaterial, Slic3r::erSupportMaterialInterface, Slic3r::erSupportTransition, Slic3r::erWipeTower, Slic3r::GCodeProcessor::FeedrateProfile::exit, Slic3r::GCodeProcessor::TimeMachine::State::exit_direction, extract_absolute_position_on_axis(), Slic3r::Extrude, Slic3r::GCodeProcessor::TimeMachine::extrude_factor_override_percentage, Slic3r::GCodeProcessor::TimeMachine::State::feedrate, Slic3r::GCodeProcessor::TimeBlock::feedrate_profile, Slic3r::GCodeProcessor::TimeBlock::flags, G1, Slic3r::GCodeProcessor::TimeBlock::g1_line_id, Slic3r::gcfKlipper, get_acceleration(), get_axis_max_acceleration(), get_axis_max_feedrate(), get_axis_max_jerk(), get_extruder_id(), get_filament_id(), get_junction_deviation(), get_last_filament_id(), get_retract_acceleration(), get_travel_acceleration(), get_xyz_max_jerk(), Inches, INCHES_TO_MM, Slic3r::GCodeProcessor::TimeMachine::State::jd_unit_vec, Slic3r::GCodeProcessor::TimeBlock::junction_deviation, Slic3r::GCodeProcessor::TimeMachine::klipper_junction_flush, Slic3r::GCodeProcessor::TimeBlock::layer_id, m_axis_position_known, m_detect_layer_based_on_tag, m_e_local_positioning_type, m_end_position, m_exclusion_volume_path_checker, m_extruded_last_z, m_extruder_offsets, m_extrusion_role, m_feedrate, m_flavor, m_flushing, m_forced_height, m_forced_width, m_g1_line_id, m_global_positioning_type, m_height, m_layer_id, m_line_id, m_machine_config_idx, m_mm3_per_mm, m_options_z_corrector, m_origin, M_PI, m_processing_homing_move, m_processing_start_custom_gcode, m_remaining_volume, m_result, m_seams_detector, m_skippable_type, m_start_position, m_time_processor, m_travel_dist, m_units, m_used_filaments, m_width, m_wiping, m_x_offset, m_y_offset, m_z_offset, Slic3r::max_allowable_speed(), Slic3r::GCodeProcessor::TimeBlock::max_entry_speed, Slic3r::GCodeProcessor::TimeBlock::max_mcr_entry_speed_sqr, Slic3r::GCodeProcessor::TimeBlock::mcr_delta_v2, Slic3r::GCodeProcessor::TimeMachine::minimum_cruise_ratio, minimum_feedrate(), minimum_travel_feedrate(), MMMIN_TO_MMSEC, Slic3r::GCodeProcessor::TimeBlock::move_id, Slic3r::GCodeProcessor::TimeBlock::move_type, Slic3r::GCodeProcessor::TimeBlock::Flags::nominal_length, Slic3r::Noop, Slic3r::Other, Slic3r::GCodeProcessor::TimeBlock::Flags::prepare_stage, Slic3r::GCodeProcessor::TimeMachine::prev, Slic3r::GCodeProcessor::TimeProcessor::Planner::queue_size, Slic3r::GCodeProcessor::TimeBlock::Flags::recalculate, Slic3r::GCodeProcessor::TimeProcessor::Planner::refresh_threshold, Relative, Slic3r::GCodeProcessor::TimeBlock::remaining_internal_g1_lines, Slic3r::GCodeProcessor::TimeMachine::requested_accel_to_decel, Slic3r::Retract, Slic3r::GCodeProcessor::TimeBlock::role, Slic3r::GCodeProcessor::TimeBlock::safe_feedrate, Slic3r::GCodeProcessor::TimeMachine::State::safe_feedrate, Slic3r::Seam, Slic3r::GCodeProcessor::TimeBlock::skippable_type, Slic3r::sqr(), store_move_vertex(), Slic3r::Travel, Slic3r::Unretract, update_position_known_from_move(), Slic3r::Wipe, Slic3r::X, Slic3r::Y, and Slic3r::Z.

Here is the call graph for this function:

◆ process_G10()

void Slic3r::GCodeProcessor::process_G10 ( const GCodeReader::GCodeLine & line)
private
6379{
6380 // Emulate G1 retract, decrement G1 count as it's will be incremented in process_G1, but it's fake G1
6381 GCodeReader::GCodeLine g10;
6382 g10.set(Axis::E, -this->m_parser.config().retraction_length.get_at(m_extruder_id));
6383 g10.set(Axis::F, this->m_parser.config().retraction_speed.get_at(m_extruder_id) * 60);
6384 //Orca: Firmware retract emulation must not change the modal G1 feedrate.
6385 const float feedrate = m_feedrate;
6386 --m_g1_line_id;
6387 process_G1(g10);
6388 m_feedrate = feedrate;
6389}

References Slic3r::E, Slic3r::F, m_extruder_id, m_feedrate, m_g1_line_id, m_parser, process_G1(), and Slic3r::GCodeReader::GCodeLine::set().

Referenced by register_commands().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_G11()

void Slic3r::GCodeProcessor::process_G11 ( const GCodeReader::GCodeLine & line)
private
6392{
6393 // Emulate G1 unretract, decrement G1 count as it's will be incremented in process_G1, but it's fake G1
6394 GCodeReader::GCodeLine g11;
6395 g11.set(Axis::E, this->m_parser.config().retraction_length.get_at(m_extruder_id) + this->m_parser.config().retract_restart_extra.get_at(m_extruder_id));
6396 g11.set(Axis::F, this->m_parser.config().deretraction_speed.get_at(m_extruder_id) * 60);
6397 // Orca: Firmware unretract emulation must not change the modal G1 feedrate.
6398 const float feedrate = m_feedrate;
6399 --m_g1_line_id;
6400 process_G1(g11);
6401 m_feedrate = feedrate;
6402}

References Slic3r::E, Slic3r::F, m_extruder_id, m_feedrate, m_g1_line_id, m_parser, process_G1(), and Slic3r::GCodeReader::GCodeLine::set().

Referenced by register_commands().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_G20()

void Slic3r::GCodeProcessor::process_G20 ( const GCodeReader::GCodeLine & line)
private
6405{
6407}

References Inches, and m_units.

Referenced by register_commands().

Here is the caller graph for this function:

◆ process_G21()

void Slic3r::GCodeProcessor::process_G21 ( const GCodeReader::GCodeLine & line)
private
6410{
6412}
@ Millimeters
Definition GCodeProcessor.hpp:659

References m_units, and Millimeters.

Referenced by register_commands().

Here is the caller graph for this function:

◆ process_G22()

void Slic3r::GCodeProcessor::process_G22 ( const GCodeReader::GCodeLine & line)
private
6415{
6416 // stores retract move
6418}

References Slic3r::Retract, and store_move_vertex().

Referenced by register_commands().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_G23()

void Slic3r::GCodeProcessor::process_G23 ( const GCodeReader::GCodeLine & line)
private
6421{
6422 // stores unretract move
6424}

References store_move_vertex(), and Slic3r::Unretract.

Referenced by register_commands().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_G28()

void Slic3r::GCodeProcessor::process_G28 ( const GCodeReader::GCodeLine & line)
private
6463{
6464 std::string_view cmd = line.cmd();
6465 std::string new_line_raw = { cmd.data(), cmd.size() };
6466 const std::array<bool, 3> homed = g28_homed_axes(line);
6467 const bool found = std::any_of(homed.begin(), homed.end(), [](const bool value) { return value; });
6468 if (homed[X]) {
6469 new_line_raw += " X0";
6470 }
6471 if (homed[Y]) {
6472 new_line_raw += " Y0";
6473 }
6474 if (homed[Z]) {
6475 new_line_raw += " Z0";
6476 }
6477 if (!found)
6478 new_line_raw += " X0 Y0 Z0";
6479
6480 GCodeReader::GCodeLine new_gline;
6481 GCodeReader reader;
6482 reader.parse_line(new_line_raw, [&](GCodeReader& reader, const GCodeReader::GCodeLine& gline) { new_gline = gline; });
6484 process_G1(new_gline);
6486
6487 // G28's physical endpoint is printer-specific even though the preview uses
6488 // zero. Wait for a subsequent explicit absolute coordinate before checking
6489 // a path from any homed axis.
6490 for (unsigned char axis = X; axis <= Z; ++axis) {
6491 if (!found || homed[axis]) {
6492 m_axis_position_known[axis] = false;
6493 m_axis_origin_known[axis] = true;
6494 }
6495 }
6496}
std::array< bool, 3 > m_axis_origin_known
Definition GCodeProcessor.hpp:1233
static std::array< bool, 3 > g28_homed_axes(const GCodeReader::GCodeLine &line)
Definition GCodeProcessor.cpp:6426

References Slic3r::GCodeReader::GCodeLine::cmd(), Slic3r::g28_homed_axes(), m_axis_origin_known, m_axis_position_known, m_processing_homing_move, Slic3r::GCodeReader::parse_line(), process_G1(), Slic3r::X, Slic3r::Y, and Slic3r::Z.

Referenced by register_commands().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_G29()

void Slic3r::GCodeProcessor::process_G29 ( const GCodeReader::GCodeLine & line)
private
6368{
6369 // Firmware may split one bed-leveling sequence across multiple G29 subcommands.
6370 constexpr float g29_time = 260.0f;
6371 const bool should_add_time = !s_IsBBLPrinter || m_measure_g29_time;
6372 if (should_add_time && !m_g29_time_added) {
6373 simulate_st_synchronize(g29_time);
6374 m_g29_time_added = true;
6375 }
6376}
bool m_measure_g29_time
Definition GCodeProcessor.hpp:1348
bool m_g29_time_added
Definition GCodeProcessor.hpp:1349

References m_g29_time_added, m_measure_g29_time, s_IsBBLPrinter, and simulate_st_synchronize().

Referenced by register_commands().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_G2_G3()

void Slic3r::GCodeProcessor::process_G2_G3 ( const GCodeReader::GCodeLine & line,
bool clockwise )
private
6053{
6054 enum class EFitting { None, IJ, R };
6055 std::string_view axis_pos_I;
6056 std::string_view axis_pos_J;
6057 EFitting fitting = EFitting::None;
6058 if (line.has('R')) {
6059 fitting = EFitting::R;
6060 } else {
6061 axis_pos_I = line.axis_pos('I');
6062 axis_pos_J = line.axis_pos('J');
6063 if (! axis_pos_I.empty() || ! axis_pos_J.empty())
6064 fitting = EFitting::IJ;
6065 }
6066
6067 if (fitting == EFitting::None)
6068 return;
6069
6070 int filament_id = get_filament_id();
6071 const float filament_diameter = (static_cast<size_t>(filament_id) < m_result.filament_diameters.size()) ? m_result.filament_diameters[filament_id] : m_result.filament_diameters.back();
6072 const float filament_radius = 0.5f * filament_diameter;
6073 const float area_filament_cross_section = static_cast<float>(M_PI) * sqr(filament_radius);
6074
6075 AxisCoords end_position = m_start_position;
6076 for (unsigned char a = X; a <= E; ++a) {
6077 end_position[a] = extract_absolute_position_on_axis((Axis)a, line, double(area_filament_cross_section));
6078 }
6079
6080 // relative center
6081 Vec3f rel_center = Vec3f::Zero();
6082#ifndef NDEBUG
6083 double radius = 0.0;
6084#endif // NDEBUG
6085 if (fitting == EFitting::R) {
6086 float r;
6087 if (!line.has_value('R', r) || r == 0.0f)
6088 return;
6089#ifndef NDEBUG
6090 radius = (double)std::abs(r);
6091#endif // NDEBUG
6092 const Vec2f start_pos((float)m_start_position[X], (float)m_start_position[Y]);
6093 const Vec2f end_pos((float)end_position[X], (float)end_position[Y]);
6094 const Vec2f c = Geometry::ArcWelder::arc_center(start_pos, end_pos, r, !clockwise);
6095 rel_center.x() = c.x() - m_start_position[X];
6096 rel_center.y() = c.y() - m_start_position[Y];
6097 }
6098 else {
6099 assert(fitting == EFitting::IJ);
6100 if (! axis_pos_I.empty() && ! line.has_value(axis_pos_I, rel_center.x()))
6101 return;
6102 if (! axis_pos_J.empty() && ! line.has_value(axis_pos_J, rel_center.y()))
6103 return;
6104 }
6105
6106 // scale center, if needed
6107 if (m_units == EUnits::Inches)
6108 rel_center *= INCHES_TO_MM;
6109
6110 struct Arc
6111 {
6112 Vec3d start{ Vec3d::Zero() };
6113 Vec3d end{ Vec3d::Zero() };
6114 Vec3d center{ Vec3d::Zero() };
6115
6116 double angle{ 0.0 };
6117 double delta_x() const { return end.x() - start.x(); }
6118 double delta_y() const { return end.y() - start.y(); }
6119 double delta_z() const { return end.z() - start.z(); }
6120
6121 double length() const { return angle * start_radius(); }
6122 double travel_length() const { return std::sqrt(sqr(length()) + sqr(delta_z())); }
6123 double start_radius() const { return (start - center).norm(); }
6124 double end_radius() const { return (end - center).norm(); }
6125
6126 Vec3d relative_start() const { return start - center; }
6127 Vec3d relative_end() const { return end - center; }
6128
6129 bool is_full_circle() const { return std::abs(delta_x()) < EPSILON && std::abs(delta_y()) < EPSILON; }
6130 };
6131
6132 Arc arc;
6133
6134 // arc start endpoint
6136
6137 // arc center
6138 arc.center = arc.start + rel_center.cast<double>();
6139
6140 // arc end endpoint
6141 arc.end = Vec3d(end_position[X], end_position[Y], end_position[Z]);
6142
6143 // radii
6144 if (std::abs(arc.end_radius() - arc.start_radius()) > 0.001) {
6145 // what to do ???
6146 }
6147
6148 assert(fitting != EFitting::R || std::abs(radius - arc.start_radius()) < EPSILON);
6149
6150 // updates feedrate from line
6151 std::optional<float> feedrate;
6152 if (line.has_f()) {
6153 // feedrate = m_feed_multiply.current * line.f() * MMMIN_TO_MMSEC;
6154 feedrate = 1.0f * line.f() * MMMIN_TO_MMSEC;
6155 }
6156
6157 // updates extrusion from line
6158 std::optional<float> extrusion;
6159 if (line.has_e())
6160 extrusion = end_position[E] - m_start_position[E];
6161
6162 // relative arc endpoints
6163 const Vec3d rel_arc_start = arc.relative_start();
6164 const Vec3d rel_arc_end = arc.relative_end();
6165
6166 // arc angle
6167 if (arc.is_full_circle())
6168 arc.angle = 2.0 * PI;
6169 else {
6170 arc.angle = std::atan2(rel_arc_start.x() * rel_arc_end.y() - rel_arc_start.y() * rel_arc_end.x(),
6171 rel_arc_start.x() * rel_arc_end.x() + rel_arc_start.y() * rel_arc_end.y());
6172 if (arc.angle < 0.0)
6173 arc.angle += 2.0 * PI;
6174 if (clockwise)
6175 arc.angle -= 2.0 * PI;
6176 }
6177
6178 const double travel_length = arc.travel_length();
6179 if (travel_length < 0.001)
6180 return;
6181
6182 auto adjust_target = [this](const AxisCoords& target, const AxisCoords& prev_position) {
6183 AxisCoords ret = target;
6185 for (unsigned char a = X; a <= E; ++a) {
6186 ret[a] -= prev_position[a];
6187 }
6188 }
6190 ret[E] -= prev_position[E];
6191
6192 // if (m_use_volumetric_e)
6193 // ret[E] *= area_filament_cross_section;
6194
6195 const double lengthsScaleFactor = (m_units == EUnits::Inches) ? double(INCHES_TO_MM) : 1.0;
6196 for (unsigned char a = X; a <= E; ++a) {
6197 ret[a] /= lengthsScaleFactor;
6198 }
6199 return ret;
6200 };
6201
6202 auto internal_only_g1_line = [this](const AxisCoords& target, bool has_z, const std::optional<float>& feedrate,
6203 const std::optional<float>& extrusion, const std::optional<unsigned int>& remaining_internal_g1_lines = std::nullopt) {
6204 std::array<std::optional<double>, 4> g1_axes = { target[X], target[Y], std::nullopt, std::nullopt };
6205 std::optional<double> g1_feedrate = std::nullopt;
6206 if (has_z)
6207 g1_axes[Z] = target[Z];
6208 if (extrusion.has_value())
6209 g1_axes[E] = target[E];
6210 if (feedrate.has_value())
6211 g1_feedrate = (double)*feedrate / MMMIN_TO_MMSEC;
6212 process_G1(g1_axes, g1_feedrate, G1DiscretizationOrigin::G2G3, remaining_internal_g1_lines);
6213 };
6214
6215 if (m_flavor == gcfMarlinFirmware) {
6216 // calculate arc segments
6217 // reference:
6218 // Prusa-Firmware-Buddy\lib\Marlin\Marlin\src\gcode\motion\G2_G3.cpp - plan_arc()
6219 // https://github.com/prusa3d/Prusa-Firmware-Buddy-Private/blob/private/lib/Marlin/Marlin/src/gcode/motion/G2_G3.cpp
6220
6221 static const float MAX_ARC_DEVIATION = 0.02f;
6222 static const float MIN_ARC_SEGMENTS_PER_SEC = 50;
6223 static const float MIN_ARC_SEGMENT_MM = 0.1f;
6224 static const float MAX_ARC_SEGMENT_MM = 2.0f;
6225 const float feedrate_mm_s = feedrate.has_value() ? *feedrate : m_feedrate;
6226 const float radius_mm = rel_center.norm();
6227 const float segment_mm = std::clamp(std::min(std::sqrt(8.0f * radius_mm * MAX_ARC_DEVIATION), feedrate_mm_s * (1.0f / MIN_ARC_SEGMENTS_PER_SEC)), MIN_ARC_SEGMENT_MM, MAX_ARC_SEGMENT_MM);
6228 const float flat_mm = radius_mm * std::abs(arc.angle);
6229 const size_t segments = std::max<size_t>(flat_mm / segment_mm + 0.8f, 1);
6230
6231 AxisCoords prev_target = m_start_position;
6232
6233 if (segments > 1) {
6234 const float inv_segments = 1.0f / static_cast<float>(segments);
6235 const float theta_per_segment = static_cast<float>(arc.angle) * inv_segments;
6236 const float cos_T = cos(theta_per_segment);
6237 const float sin_T = sin(theta_per_segment);
6238 const float z_per_segment = arc.delta_z() * inv_segments;
6239 const float extruder_per_segment = (extrusion.has_value()) ? *extrusion * inv_segments : 0.0f;
6240
6241 static const size_t N_ARC_CORRECTION = 25;
6242 size_t arc_recalc_count = N_ARC_CORRECTION;
6243
6244 Vec2f rvec(-rel_center.x(), -rel_center.y());
6245 AxisCoords arc_target = { 0.0f, 0.0f, m_start_position[Z], m_start_position[E] };
6246 for (size_t i = 1; i < segments; ++i) {
6247 if (--arc_recalc_count) {
6248 // Apply vector rotation matrix to previous rvec.a / 1
6249 const float r_new_Y = rvec.x() * sin_T + rvec.y() * cos_T;
6250 rvec.x() = rvec.x() * cos_T - rvec.y() * sin_T;
6251 rvec.y() = r_new_Y;
6252 }
6253 else {
6254 arc_recalc_count = N_ARC_CORRECTION;
6255 // Arc correction to radius vector. Computed only every N_ARC_CORRECTION increments.
6256 // Compute exact location by applying transformation matrix from initial radius vector(=-offset).
6257 // To reduce stuttering, the sin and cos could be computed at different times.
6258 // For now, compute both at the same time.
6259 const float Ti = i * theta_per_segment;
6260 const float cos_Ti = cos(Ti);
6261 const float sin_Ti = sin(Ti);
6262 rvec.x() = -rel_center.x() * cos_Ti + rel_center.y() * sin_Ti;
6263 rvec.y() = -rel_center.x() * sin_Ti - rel_center.y() * cos_Ti;
6264 }
6265
6266 // Update arc_target location
6267 arc_target[X] = arc.center.x() + rvec.x();
6268 arc_target[Y] = arc.center.y() + rvec.y();
6269 arc_target[Z] += z_per_segment;
6270 arc_target[E] += extruder_per_segment;
6271
6272 m_start_position = m_end_position; // this is required because we are skipping the call to process_gcode_line()
6273 internal_only_g1_line(adjust_target(arc_target, prev_target), z_per_segment != 0.0, (i == 1) ? feedrate : std::nullopt,
6274 extrusion, segments - i);
6275 prev_target = arc_target;
6276 }
6277 }
6278
6279 // Ensure last segment arrives at target location.
6280 m_start_position = m_end_position; // this is required because we are skipping the call to process_gcode_line()
6281 internal_only_g1_line(adjust_target(end_position, prev_target), arc.delta_z() != 0.0, (segments == 1) ? feedrate : std::nullopt, extrusion);
6282 }
6283 else {
6284 // calculate arc segments
6285 // reference:
6286 // Prusa-Firmware\Firmware\motion_control.cpp - mc_arc()
6287 // https://github.com/prusa3d/Prusa-Firmware/blob/MK3/Firmware/motion_control.cpp
6288
6289 // segments count
6290#if 0
6291 static const double MM_PER_ARC_SEGMENT = 1.0;
6292 const size_t segments = std::max<size_t>(std::floor(travel_length / MM_PER_ARC_SEGMENT), 1);
6293#else
6294 static const double gcode_arc_tolerance = 0.0125;
6295 const size_t segments = Geometry::ArcWelder::arc_discretization_steps(arc.start_radius(), std::abs(arc.angle), gcode_arc_tolerance);
6296#endif
6297
6298 const double inv_segment = 1.0 / double(segments);
6299 const double theta_per_segment = arc.angle * inv_segment;
6300 const double z_per_segment = arc.delta_z() * inv_segment;
6301 const double extruder_per_segment = (extrusion.has_value()) ? *extrusion * inv_segment : 0.0;
6302 const double sq_theta_per_segment = sqr(theta_per_segment);
6303 const double cos_T = 1.0 - 0.5 * sq_theta_per_segment;
6304 const double sin_T = theta_per_segment - sq_theta_per_segment * theta_per_segment / 6.0f;
6305
6306 AxisCoords prev_target = m_start_position;
6307 AxisCoords arc_target;
6308
6309 // Initialize the linear axis
6310 arc_target[Z] = m_start_position[Z];
6311
6312 // Initialize the extruder axis
6313 arc_target[E] = m_start_position[E];
6314
6315 static const size_t N_ARC_CORRECTION = 25;
6316 Vec3d curr_rel_arc_start = arc.relative_start();
6317 size_t count = N_ARC_CORRECTION;
6318
6319 for (size_t i = 1; i < segments; ++i) {
6320 if (count-- == 0) {
6321 const double cos_Ti = ::cos(i * theta_per_segment);
6322 const double sin_Ti = ::sin(i * theta_per_segment);
6323 curr_rel_arc_start.x() = -double(rel_center.x()) * cos_Ti + double(rel_center.y()) * sin_Ti;
6324 curr_rel_arc_start.y() = -double(rel_center.x()) * sin_Ti - double(rel_center.y()) * cos_Ti;
6325 count = N_ARC_CORRECTION;
6326 }
6327 else {
6328 const float r_axisi = curr_rel_arc_start.x() * sin_T + curr_rel_arc_start.y() * cos_T;
6329 curr_rel_arc_start.x() = curr_rel_arc_start.x() * cos_T - curr_rel_arc_start.y() * sin_T;
6330 curr_rel_arc_start.y() = r_axisi;
6331 }
6332
6333 // Update arc_target location
6334 arc_target[X] = arc.center.x() + curr_rel_arc_start.x();
6335 arc_target[Y] = arc.center.y() + curr_rel_arc_start.y();
6336 arc_target[Z] += z_per_segment;
6337 arc_target[E] += extruder_per_segment;
6338
6339 m_start_position = m_end_position; // this is required because we are skipping the call to process_gcode_line()
6340 internal_only_g1_line(adjust_target(arc_target, prev_target), z_per_segment != 0.0, (i == 1) ? feedrate : std::nullopt,
6341 extrusion, segments - i);
6342 prev_target = arc_target;
6343 }
6344
6345 // Ensure last segment arrives at target location.
6346 m_start_position = m_end_position; // this is required because we are skipping the call to process_gcode_line()
6347 internal_only_g1_line(adjust_target(end_position, prev_target), arc.delta_z() != 0.0, (segments == 1) ? feedrate : std::nullopt, extrusion);
6348 }
6349
6350 // Internal linearized arc segments inherit the arc's starting certainty.
6351 // Only the original absolute command may establish a newly known endpoint.
6353}
static unsigned int count
Definition AuxiliaryDataViewModel.cpp:246
@ G2G3
Definition GCodeProcessor.hpp:1491
static constexpr double PI
Definition libslic3r.h:81
void arc(std::vector< std::pair< Vec2d, Vec2d > > &out, double cx, double cy, double rx, double ry, double a0, double a1, int n=14)
Definition DesignSketchTool.cpp:7759
size_t arc_discretization_steps(const FloatType radius, const FloatType angle, const FloatType deviation)
Definition ArcWelder.hpp:50
Eigen::Matrix< Float, 2, 1, Eigen::DontAlign > arc_center(const Eigen::MatrixBase< Derived > &start_pos, const Eigen::MatrixBase< Derived2 > &end_pos, const Float radius, const bool is_ccw)
Definition ArcWelder.hpp:22
void center(ExPolygonsWithIds &e)
Definition Emboss.cpp:1382
@ None
Definition SketchEngine.hpp:180

References Slic3r::angle(), Slic3r::Geometry::ArcWelder::arc_center(), Slic3r::Geometry::ArcWelder::arc_discretization_steps(), Slic3r::GCodeReader::GCodeLine::axis_pos(), Slic3r::center(), count, Slic3r::E, EPSILON, extract_absolute_position_on_axis(), Slic3r::GCodeReader::GCodeLine::f(), G2G3, Slic3r::gcfMarlinFirmware, get_filament_id(), Slic3r::GCodeReader::GCodeLine::has(), Slic3r::GCodeReader::GCodeLine::has_e(), Slic3r::GCodeReader::GCodeLine::has_f(), Slic3r::GCodeReader::GCodeLine::has_value(), Inches, INCHES_TO_MM, Slic3r::length(), m_e_local_positioning_type, m_end_position, m_feedrate, m_flavor, m_global_positioning_type, M_PI, m_result, m_start_position, m_units, MMMIN_TO_MMSEC, Slic3r::None, PI, process_G1(), Relative, Slic3r::sqr(), update_position_known_from_move(), Slic3r::X, Slic3r::Y, and Slic3r::Z.

Referenced by register_commands().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_G4()

void Slic3r::GCodeProcessor::process_G4 ( const GCodeReader::GCodeLine & line)
private
6357{
6358 float value_s = 0.0;
6359 float value_p = 0.0;
6360 if (line.has_value('S', value_s) || line.has_value('P', value_p)) {
6361 value_s += value_p * 0.001;
6362 simulate_st_synchronize(value_s);
6363 }
6364}

References Slic3r::GCodeReader::GCodeLine::has_value(), and simulate_st_synchronize().

Referenced by register_commands().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_G90()

void Slic3r::GCodeProcessor::process_G90 ( const GCodeReader::GCodeLine & line)
private

References Absolute, and m_global_positioning_type.

Referenced by register_commands().

Here is the caller graph for this function:

◆ process_G91()

void Slic3r::GCodeProcessor::process_G91 ( const GCodeReader::GCodeLine & line)
private

References m_global_positioning_type, and Relative.

Referenced by register_commands().

Here is the caller graph for this function:

◆ process_G92()

void Slic3r::GCodeProcessor::process_G92 ( const GCodeReader::GCodeLine & line)
private
6509{
6510 float lengths_scale_factor = (m_units == EUnits::Inches) ? INCHES_TO_MM : 1.0f;
6511 bool any_found = false;
6512
6513 if (line.has_x()) {
6515 m_origin[X] = m_end_position[X] - line.x() * lengths_scale_factor;
6516 any_found = true;
6517 }
6518
6519 if (line.has_y()) {
6521 m_origin[Y] = m_end_position[Y] - line.y() * lengths_scale_factor;
6522 any_found = true;
6523 }
6524
6525 if (line.has_z()) {
6527 m_origin[Z] = m_end_position[Z] - line.z() * lengths_scale_factor;
6528 any_found = true;
6529 // Belt only: the start G-code's purge-blob advance + G92 Z0 resets leave a constant
6530 // machine-Z origin offset here; the designed-view back-transform subtracts it so
6531 // toolpaths map to the model's belt coordinate (gcode Z). Gated on belt_tilt_angle
6532 // (set from the belt header, parsed before the body) so non-belt G-code processing
6533 // is byte-identical — no unconditional work on the shared path.
6534 if (m_result.belt_tilt_angle != 0.f)
6535 m_result.belt_z_origin = m_origin[Z];
6536 }
6537
6538 if (line.has_e()) {
6539 // extruder coordinate can grow to the point where its float representation does not allow for proper addition with small increments,
6540 // we set the value taken from the G92 line as the new current position for it
6541 m_end_position[E] = line.e() * lengths_scale_factor;
6542 any_found = true;
6543 }
6544 else
6546
6547 if (!any_found && !line.has_unknown_axis()) {
6548 // The G92 may be called for axes that PrusaSlicer does not recognize, for example see GH issue #3510,
6549 // where G92 A0 B0 is called although the extruder axis is till E.
6550 for (unsigned char a = X; a <= E; ++a) {
6551 if (a <= Z)
6553 m_origin[a] = m_end_position[a];
6554 }
6555 }
6556}

References Slic3r::E, Slic3r::GCodeReader::GCodeLine::e(), Slic3r::GCodeReader::GCodeLine::has_e(), Slic3r::GCodeReader::GCodeLine::has_unknown_axis(), Slic3r::GCodeReader::GCodeLine::has_x(), Slic3r::GCodeReader::GCodeLine::has_y(), Slic3r::GCodeReader::GCodeLine::has_z(), Inches, INCHES_TO_MM, m_axis_origin_known, m_axis_position_known, m_end_position, m_origin, m_result, m_units, simulate_st_synchronize(), Slic3r::X, Slic3r::GCodeReader::GCodeLine::x(), Slic3r::Y, Slic3r::GCodeReader::GCodeLine::y(), Slic3r::Z, and Slic3r::GCodeReader::GCodeLine::z().

Referenced by register_commands().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_gcode_line()

void Slic3r::GCodeProcessor::process_gcode_line ( const GCodeReader::GCodeLine & line,
bool producers_enabled )
private
4171{
4172/* std::cout << line.raw() << std::endl; */
4173
4174 ++m_line_id;
4175
4176 // update start position
4178
4179 const std::string_view cmd = line.cmd();
4180 if (m_flavor == gcfKlipper)
4181 {
4182 if (ascii_iequals(cmd, "SET_VELOCITY_LIMIT"))
4183 {
4185 return;
4186 }
4187// ORCA: Add Pressure Advance visualization support
4188 if (ascii_iequals(cmd, "SET_PRESSURE_ADVANCE"))
4189 {
4191 return;
4192 }
4193 }
4194
4195 if (cmd.length() > 1) {
4196 // process command lines
4197 m_command_processor.process_comand(cmd, line);
4198 }
4199 else {
4200 const std::string &comment = line.raw();
4201 if (comment.length() > 2 && comment.front() == ';')
4202 {
4203 std::string comment_content = comment.substr(1); // only format like ";V{cmd}" is valid
4204 if (comment_content[0] == 'V' || comment_content[0] == 'v') {
4205 GCodeReader reader;
4206 GCodeReader::GCodeLine new_line;
4207 reader.parse_line(comment_content, [&new_line](const auto& greader, const auto& gline) {
4208 new_line = gline;
4209 });
4210 m_command_processor.process_comand(new_line.cmd(), new_line);
4211 }
4212 else {
4213 // Process tags embedded into comments. Tag comments always start at the start of a line
4214 // with a comment and continue with a tag without any whitespace separator.
4215 process_tags(comment_content, producers_enabled);
4216 }
4217 }
4218 }
4219}
void process_SET_VELOCITY_LIMIT(const GCodeReader::GCodeLine &line)
Definition GCodeProcessor.cpp:6869
CommandProcessor m_command_processor
Definition GCodeProcessor.hpp:1217
void process_SET_PRESSURE_ADVANCE(const GCodeReader::GCodeLine &line)
Definition GCodeProcessor.cpp:6617
void process_tags(const std::string_view comment, bool producers_enabled)
Definition GCodeProcessor.cpp:4402
bool ascii_iequals(std::string_view a, std::string_view b)
Definition Utils.hpp:306

References Slic3r::ascii_iequals(), Slic3r::GCodeReader::GCodeLine::cmd(), Slic3r::gcfKlipper, m_command_processor, m_end_position, m_flavor, m_line_id, m_start_position, Slic3r::GCodeReader::parse_line(), process_SET_PRESSURE_ADVANCE(), process_SET_VELOCITY_LIMIT(), process_tags(), and Slic3r::GCodeReader::GCodeLine::raw().

Referenced by process_buffer(), and process_file().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_ideamaker_tags()

bool Slic3r::GCodeProcessor::process_ideamaker_tags ( const std::string_view comment)
private
4973{
4974 // TYPE -> extrusion role
4975 std::string tag = "TYPE:";
4976 size_t pos = comment.find(tag);
4977 if (pos != comment.npos) {
4978 const std::string_view type = comment.substr(pos + tag.length());
4979 if (type == "RAFT")
4981 else if (type == "WALL-OUTER")
4983 else if (type == "WALL-INNER")
4985 else if (type == "SOLID-FILL")
4987 else if (type == "FILL")
4989 else if (type == "BRIDGE")
4991 else if (type == "INTERNAL BRIDGE")
4993 else if (type == "SUPPORT")
4995 else {
4997 BOOST_LOG_TRIVIAL(warning) << "GCodeProcessor found unknown extrusion role: " << type;
4998 }
4999
5001 m_seams_detector.activate(true);
5002
5003 return true;
5004 }
5005
5006 // geometry
5007 // width
5008 tag = "WIDTH:";
5009 pos = comment.find(tag);
5010 if (pos != comment.npos) {
5011 if (!parse_number(comment.substr(pos + tag.length()), m_forced_width))
5012 BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Width (" << comment << ").";
5013 return true;
5014 }
5015
5016 // height
5017 tag = "HEIGHT:";
5018 pos = comment.find(tag);
5019 if (pos != comment.npos) {
5020 if (!parse_number(comment.substr(pos + tag.length()), m_forced_height))
5021 BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Height (" << comment << ").";
5022 return true;
5023 }
5024
5025 // layer
5026 pos = comment.find("LAYER:");
5027 if (pos == 0) {
5028 ++m_layer_id;
5029 return true;
5030 }
5031
5032 return false;
5033}

References Slic3r::erBridgeInfill, Slic3r::erExternalPerimeter, Slic3r::erInternalBridgeInfill, Slic3r::erInternalInfill, Slic3r::erNone, Slic3r::erPerimeter, Slic3r::erSkirt, Slic3r::erSolidInfill, Slic3r::erSupportMaterial, m_extrusion_role, m_forced_height, m_forced_width, m_layer_id, m_seams_detector, Slic3r::parse_number(), and set_extrusion_role().

Referenced by process_producers_tags().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_kissslicer_tags()

bool Slic3r::GCodeProcessor::process_kissslicer_tags ( const std::string_view comment)
private
5036{
5037 // extrusion roles
5038
5039 // ; 'Raft Path'
5040 size_t pos = comment.find(" 'Raft Path'");
5041 if (pos == 0) {
5043 return true;
5044 }
5045
5046 // ; 'Support Interface Path'
5047 pos = comment.find(" 'Support Interface Path'");
5048 if (pos == 0) {
5050 return true;
5051 }
5052
5053 // ; 'Travel/Ironing Path'
5054 pos = comment.find(" 'Travel/Ironing Path'");
5055 if (pos == 0) {
5057 return true;
5058 }
5059
5060 // ; 'Support (may Stack) Path'
5061 pos = comment.find(" 'Support (may Stack) Path'");
5062 if (pos == 0) {
5064 return true;
5065 }
5066
5067 // ; 'Perimeter Path'
5068 pos = comment.find(" 'Perimeter Path'");
5069 if (pos == 0) {
5071 m_seams_detector.activate(true);
5072 return true;
5073 }
5074
5075 // ; 'Pillar Path'
5076 pos = comment.find(" 'Pillar Path'");
5077 if (pos == 0) {
5078 set_extrusion_role(erNone); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
5079 return true;
5080 }
5081
5082 // ; 'Destring/Wipe/Jump Path'
5083 pos = comment.find(" 'Destring/Wipe/Jump Path'");
5084 if (pos == 0) {
5085 set_extrusion_role(erNone); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
5086 return true;
5087 }
5088
5089 // ; 'Prime Pillar Path'
5090 pos = comment.find(" 'Prime Pillar Path'");
5091 if (pos == 0) {
5092 set_extrusion_role(erNone); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
5093 return true;
5094 }
5095
5096 // ; 'Loop Path'
5097 pos = comment.find(" 'Loop Path'");
5098 if (pos == 0) {
5099 set_extrusion_role(erNone); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
5100 return true;
5101 }
5102
5103 // ; 'Crown Path'
5104 pos = comment.find(" 'Crown Path'");
5105 if (pos == 0) {
5106 set_extrusion_role(erNone); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
5107 return true;
5108 }
5109
5110 // ; 'Solid Path'
5111 pos = comment.find(" 'Solid Path'");
5112 if (pos == 0) {
5114 return true;
5115 }
5116
5117 // ; 'Stacked Sparse Infill Path'
5118 pos = comment.find(" 'Stacked Sparse Infill Path'");
5119 if (pos == 0) {
5121 return true;
5122 }
5123
5124 // ; 'Sparse Infill Path'
5125 pos = comment.find(" 'Sparse Infill Path'");
5126 if (pos == 0) {
5128 return true;
5129 }
5130
5131 // geometry
5132
5133 // layer
5134 pos = comment.find(" BEGIN_LAYER_");
5135 if (pos == 0) {
5136 ++m_layer_id;
5137 return true;
5138 }
5139
5140 return false;
5141}
@ erIroning
Definition ExtrusionEntity.hpp:35

References Slic3r::erExternalPerimeter, Slic3r::erInternalInfill, Slic3r::erIroning, Slic3r::erNone, Slic3r::erSkirt, Slic3r::erSolidInfill, Slic3r::erSupportMaterial, Slic3r::erSupportMaterialInterface, m_layer_id, m_seams_detector, and set_extrusion_role().

Referenced by process_producers_tags().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_M1()

void Slic3r::GCodeProcessor::process_M1 ( const GCodeReader::GCodeLine & line)
private
6559{
6561}

References simulate_st_synchronize().

Referenced by register_commands().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_M1020()

void Slic3r::GCodeProcessor::process_M1020 ( const GCodeReader::GCodeLine & line)
private
7057{
7058 int curr_filament_id = get_filament_id(false);
7059 int curr_extruder_id = get_extruder_id(false);
7060 if (line.raw().length() > 5) {
7061 std::string filament_id_str = line.raw().substr(7);
7062 if (filament_id_str.empty())
7063 return;
7064
7065 int eid = 0;
7066 eid = std::stoi(filament_id_str);
7067 if (eid < 0 || eid > 254) {
7068 // M1020-1 is a valid gcode line for RepRap Firmwares (used to deselects all tools)
7069 if ((m_flavor != gcfRepRapFirmware && m_flavor != gcfRepRapSprinter) || eid != -1)
7070 BOOST_LOG_TRIVIAL(error) << "Invalid M1020 command (" << line.raw() << ").";
7071 }
7072 else {
7073 if (eid >= m_result.filaments_count) {
7074 BOOST_LOG_TRIVIAL(error) << "Invalid M1020 command (" << line.raw() << ").";
7075 return;
7076 }
7077 // carry the H<nozzle> logical-nozzle id. process_filament_change(int,int) self-gates back
7078 // to the single-arg model for the single-nozzle fleet, so this is byte-inert for them.
7079 int nozzle_id = -1;
7080 float nozzle_val = 0.f;
7081 if (line.has_value('H', nozzle_val))
7082 nozzle_id = static_cast<int>(nozzle_val);
7083 process_filament_change(eid, nozzle_id);
7084 }
7085 }
7086}
@ gcfRepRapSprinter
Definition PrintConfig.hpp:57

References Slic3r::gcfRepRapFirmware, Slic3r::gcfRepRapSprinter, get_extruder_id(), get_filament_id(), Slic3r::GCodeReader::GCodeLine::has_value(), m_flavor, m_result, process_filament_change(), and Slic3r::GCodeReader::GCodeLine::raw().

Referenced by register_commands().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_M104()

void Slic3r::GCodeProcessor::process_M104 ( const GCodeReader::GCodeLine & line)
private
6574{
6575 int filament_id = get_filament_id();
6576 float new_temp;
6577 if (line.has_value('S', new_temp))
6578 m_extruder_temps[filament_id] = new_temp;
6579}

References get_filament_id(), Slic3r::GCodeReader::GCodeLine::has_value(), and m_extruder_temps.

Referenced by process_VM104(), and register_commands().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_M106()

void Slic3r::GCodeProcessor::process_M106 ( const GCodeReader::GCodeLine & line)
private
6587{
6588 //BBS: for Bambu machine ,we both use M106 P1 and M106 to indicate the part cooling fan
6589 //So we must not ignore M106 P1
6590 if (!line.has('P') || (line.has('P') && line.p() == 1.0f)) {
6591 // The absence of P means the print cooling fan, so ignore anything else.
6592 float new_fan_speed;
6593 if (line.has_value('S', new_fan_speed))
6594 m_fan_speed = (100.0f / 255.0f) * new_fan_speed;
6595 else
6596 m_fan_speed = 100.0f;
6597 }
6598}
float m_fan_speed
Definition GCodeProcessor.hpp:1319

References Slic3r::GCodeReader::GCodeLine::has(), Slic3r::GCodeReader::GCodeLine::has_value(), m_fan_speed, and Slic3r::GCodeReader::GCodeLine::p().

Referenced by register_commands().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_M107()

void Slic3r::GCodeProcessor::process_M107 ( const GCodeReader::GCodeLine & line)
private
6632{
6633 m_fan_speed = 0.0f;
6634}

References m_fan_speed.

Referenced by register_commands().

Here is the caller graph for this function:

◆ process_M108()

void Slic3r::GCodeProcessor::process_M108 ( const GCodeReader::GCodeLine & line)
private
6637{
6638 // These M-codes are used by Sailfish to change active tool.
6639 // They have to be processed otherwise toolchanges will be unrecognised
6640
6641 if (m_flavor != gcfSailfish)
6642 return;
6643
6644 std::string cmd = line.raw();
6645 size_t pos = cmd.find("T");
6646 if (pos != std::string::npos)
6647 process_T(cmd.substr(pos));
6648}
void process_T(const GCodeReader::GCodeLine &line)
Definition GCodeProcessor.cpp:7044
@ gcfSailfish
Definition PrintConfig.hpp:60

References Slic3r::gcfSailfish, m_flavor, process_T(), and Slic3r::GCodeReader::GCodeLine::raw().

Referenced by register_commands().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_M109()

void Slic3r::GCodeProcessor::process_M109 ( const GCodeReader::GCodeLine & line)
private
6651{
6652 if (m_flavor == gcfKlipper)
6654 int filament_id = get_filament_id();
6655 float new_temp;
6656 if (line.has_value('R', new_temp)) {
6657 float val;
6658 if (line.has_value('T', val)) {
6659 size_t eid = static_cast<size_t>(val);
6660 if (eid < m_extruder_temps.size())
6661 m_extruder_temps[eid] = new_temp;
6662 }
6663 else
6664 m_extruder_temps[filament_id] = new_temp;
6665 }
6666 else if (line.has_value('S', new_temp))
6667 m_extruder_temps[filament_id] = new_temp;
6668}

References Slic3r::gcfKlipper, get_filament_id(), Slic3r::GCodeReader::GCodeLine::has_value(), m_extruder_temps, m_flavor, and simulate_st_synchronize().

Referenced by process_VM109(), and register_commands().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_M132()

void Slic3r::GCodeProcessor::process_M132 ( const GCodeReader::GCodeLine & line)
private
6676{
6677 // This command is used by Makerbot to load the current home position from EEPROM
6678 // see: https://github.com/makerbot/s3g/blob/master/doc/GCodeProtocol.md
6679
6680 if (line.has('X'))
6681 m_origin[X] = 0.0f;
6682
6683 if (line.has('Y'))
6684 m_origin[Y] = 0.0f;
6685
6686 if (line.has('Z'))
6687 m_origin[Z] = 0.0f;
6688
6689 if (line.has('E'))
6690 m_origin[E] = 0.0f;
6691}

References Slic3r::E, Slic3r::GCodeReader::GCodeLine::has(), m_origin, Slic3r::X, Slic3r::Y, and Slic3r::Z.

Referenced by register_commands().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_M135()

void Slic3r::GCodeProcessor::process_M135 ( const GCodeReader::GCodeLine & line)
private
6694{
6695 // These M-codes are used by MakerWare to change active tool.
6696 // They have to be processed otherwise toolchanges will be unrecognised
6697
6698 if (m_flavor != gcfMakerWare)
6699 return;
6700
6701 std::string cmd = line.raw();
6702 size_t pos = cmd.find("T");
6703 if (pos != std::string::npos)
6704 process_T(cmd.substr(pos));
6705}

References Slic3r::gcfMakerWare, m_flavor, process_T(), and Slic3r::GCodeReader::GCodeLine::raw().

Referenced by register_commands().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_M140()

void Slic3r::GCodeProcessor::process_M140 ( const GCodeReader::GCodeLine & line)
private
6708{
6709 float new_temp;
6710 if (line.has_value('S', new_temp))
6711 m_highest_bed_temp = m_highest_bed_temp < (int)new_temp ? (int)new_temp : m_highest_bed_temp;
6712}
int m_highest_bed_temp
Definition GCodeProcessor.hpp:1334

References Slic3r::GCodeReader::GCodeLine::has_value(), and m_highest_bed_temp.

Referenced by register_commands().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_M190()

void Slic3r::GCodeProcessor::process_M190 ( const GCodeReader::GCodeLine & line)
private
6715{
6716 if (m_flavor == gcfKlipper)
6718 float new_temp;
6719 if (line.has_value('S', new_temp))
6720 m_highest_bed_temp = m_highest_bed_temp < (int)new_temp ? (int)new_temp : m_highest_bed_temp;
6721}

References Slic3r::gcfKlipper, Slic3r::GCodeReader::GCodeLine::has_value(), m_flavor, m_highest_bed_temp, and simulate_st_synchronize().

Referenced by register_commands().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_M191()

void Slic3r::GCodeProcessor::process_M191 ( const GCodeReader::GCodeLine & line)
private
6724{
6725 float chamber_temp = 0;
6726 const float wait_chamber_temp_time = 720.0;
6727 // BBS: when chamber_temp>40,caculate time required for heating
6728 if (line.has_value('S', chamber_temp) && chamber_temp > 40)
6729 simulate_st_synchronize(wait_chamber_temp_time);
6730}

References Slic3r::GCodeReader::GCodeLine::has_value(), and simulate_st_synchronize().

Referenced by register_commands().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_M201()

void Slic3r::GCodeProcessor::process_M201 ( const GCodeReader::GCodeLine & line)
private
6734{
6735 // see http://reprap.org/wiki/G-code#M201:_Set_max_printing_acceleration
6736 float factor = ((m_flavor != gcfRepRapSprinter && m_flavor != gcfRepRapFirmware) && m_units == EUnits::Inches) ? INCHES_TO_MM : 1.0f;
6737
6738 // The arrays are slot-major ([slot*2 + mode]); a firmware M201 changes the machine's live
6739 // limits globally, so write the value into EVERY slot's mode entry. Orca: covering every slot
6740 // (not a partial range) keeps the per-slot reads in lockstep with the mode-only reads they
6741 // replaced. Per-mode gating unchanged: Stealth entries only once envelope processing is on.
6742 auto set_all_slots = [](ConfigOptionFloats &option, size_t mode, float value) {
6743 for (size_t slot_base = 0; slot_base < option.size(); slot_base += 2)
6744 set_option_value(option, slot_base + mode, value);
6745 };
6746 for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
6747 if (static_cast<PrintEstimatedStatistics::ETimeMode>(i) == PrintEstimatedStatistics::ETimeMode::Normal || m_time_processor.machine_envelope_processing_enabled) {
6748 if (line.has_x()) set_all_slots(m_time_processor.machine_limits.machine_max_acceleration_x, i, line.x() * factor);
6749
6750 if (line.has_y()) set_all_slots(m_time_processor.machine_limits.machine_max_acceleration_y, i, line.y() * factor);
6751
6752 if (line.has_z()) set_all_slots(m_time_processor.machine_limits.machine_max_acceleration_z, i, line.z() * factor);
6753
6754 if (line.has_e()) set_all_slots(m_time_processor.machine_limits.machine_max_acceleration_e, i, line.e() * factor);
6755 }
6756 }
6757}
static void set_option_value(ConfigOptionFloats &option, size_t id, float value)
Definition GCodeProcessor.cpp:196

References Slic3r::PrintEstimatedStatistics::Count, Slic3r::GCodeReader::GCodeLine::e(), Slic3r::gcfRepRapFirmware, Slic3r::gcfRepRapSprinter, Slic3r::GCodeReader::GCodeLine::has_e(), Slic3r::GCodeReader::GCodeLine::has_x(), Slic3r::GCodeReader::GCodeLine::has_y(), Slic3r::GCodeReader::GCodeLine::has_z(), Inches, INCHES_TO_MM, m_flavor, m_time_processor, m_units, Slic3r::PrintEstimatedStatistics::Normal, Slic3r::set_option_value(), Slic3r::ConfigOptionVector< double >::size(), Slic3r::GCodeReader::GCodeLine::x(), Slic3r::GCodeReader::GCodeLine::y(), and Slic3r::GCodeReader::GCodeLine::z().

Referenced by register_commands().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_M203()

void Slic3r::GCodeProcessor::process_M203 ( const GCodeReader::GCodeLine & line)
private
6760{
6761 // see http://reprap.org/wiki/G-code#M203:_Set_maximum_feedrate
6762 if (m_flavor == gcfRepetier)
6763 return;
6764
6765 // see http://reprap.org/wiki/G-code#M203:_Set_maximum_feedrate
6766 // http://smoothieware.org/supported-g-codes
6768
6769 // Slot-major arrays; a firmware M203 changes the live limits globally — write every slot's
6770 // mode entry (see process_M201). Per-mode gating unchanged.
6771 auto set_all_slots = [](ConfigOptionFloats &option, size_t mode, float value) {
6772 for (size_t slot_base = 0; slot_base < option.size(); slot_base += 2)
6773 set_option_value(option, slot_base + mode, value);
6774 };
6775 for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
6776 if (static_cast<PrintEstimatedStatistics::ETimeMode>(i) == PrintEstimatedStatistics::ETimeMode::Normal || m_time_processor.machine_envelope_processing_enabled) {
6777 if (line.has_x())
6778 set_all_slots(m_time_processor.machine_limits.machine_max_speed_x, i, line.x() * factor);
6779
6780 if (line.has_y())
6781 set_all_slots(m_time_processor.machine_limits.machine_max_speed_y, i, line.y() * factor);
6782
6783 if (line.has_z())
6784 set_all_slots(m_time_processor.machine_limits.machine_max_speed_z, i, line.z() * factor);
6785
6786 if (line.has_e())
6787 set_all_slots(m_time_processor.machine_limits.machine_max_speed_e, i, line.e() * factor);
6788 }
6789 }
6790}
@ gcfSmoothie
Definition PrintConfig.hpp:63

References Slic3r::PrintEstimatedStatistics::Count, Slic3r::GCodeReader::GCodeLine::e(), Slic3r::gcfKlipper, Slic3r::gcfMarlinFirmware, Slic3r::gcfMarlinLegacy, Slic3r::gcfRepetier, Slic3r::gcfSmoothie, Slic3r::GCodeReader::GCodeLine::has_e(), Slic3r::GCodeReader::GCodeLine::has_x(), Slic3r::GCodeReader::GCodeLine::has_y(), Slic3r::GCodeReader::GCodeLine::has_z(), m_flavor, m_time_processor, MMMIN_TO_MMSEC, Slic3r::PrintEstimatedStatistics::Normal, Slic3r::set_option_value(), Slic3r::ConfigOptionVector< double >::size(), Slic3r::GCodeReader::GCodeLine::x(), Slic3r::GCodeReader::GCodeLine::y(), and Slic3r::GCodeReader::GCodeLine::z().

Referenced by register_commands().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_M204()

void Slic3r::GCodeProcessor::process_M204 ( const GCodeReader::GCodeLine & line)
private
6793{
6794 float value;
6795 if (m_flavor == gcfKlipper) {
6796 if (!line.has_value('S', value)) {
6797 float travel;
6798 if (!line.has_value('P', value) || !line.has_value('T', travel))
6799 return;
6800 value = std::min(value, travel);
6801 }
6802 // Klipper replaces its single live max_accel for print and travel; the profile-clamping
6803 // setters would diverge from the firmware when custom G-code raises the limit.
6804 if (value > 0.0f) {
6805 for (auto& machine : m_time_processor.machines)
6806 machine.acceleration = machine.travel_acceleration = value;
6807 }
6808 return;
6809 }
6810 for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
6812 m_time_processor.machine_envelope_processing_enabled) {
6813 if (line.has_value('S', value)) {
6814 // Legacy acceleration format. This format is used by the legacy Marlin, MK2 or MK3 firmware
6815 // It is also generated by PrusaSlicer to control acceleration per extrusion type
6816 // (perimeters, first layer etc) when 'Marlin (legacy)' flavor is used.
6819 if (line.has_value('T', value))
6821 }
6822 else {
6823 // New acceleration format, compatible with the upstream Marlin.
6824 if (line.has_value('P', value))
6826 if (line.has_value('R', value))
6828 if (line.has_value('T', value))
6829 // Interpret the T value as the travel acceleration in the new Marlin format.
6831 }
6832 }
6833 }
6834}
void set_acceleration(PrintEstimatedStatistics::ETimeMode mode, float value)
Definition GCodeProcessor.cpp:7965
void set_retract_acceleration(PrintEstimatedStatistics::ETimeMode mode, float value)
Definition GCodeProcessor.cpp:7949
void set_travel_acceleration(PrintEstimatedStatistics::ETimeMode mode, float value)
Definition GCodeProcessor.cpp:7981

References Slic3r::PrintEstimatedStatistics::Count, Slic3r::gcfKlipper, Slic3r::GCodeReader::GCodeLine::has_value(), m_flavor, m_time_processor, Slic3r::PrintEstimatedStatistics::Normal, set_acceleration(), set_retract_acceleration(), and set_travel_acceleration().

Referenced by register_commands().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_M205()

void Slic3r::GCodeProcessor::process_M205 ( const GCodeReader::GCodeLine & line)
private
6837{
6838 for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
6840 m_time_processor.machine_envelope_processing_enabled) {
6841 if (line.has_x()) {
6842 float max_jerk = line.x();
6843 set_option_value(m_time_processor.machine_limits.machine_max_jerk_x, i, max_jerk);
6844 set_option_value(m_time_processor.machine_limits.machine_max_jerk_y, i, max_jerk);
6845 }
6846
6847 if (line.has_y())
6848 set_option_value(m_time_processor.machine_limits.machine_max_jerk_y, i, line.y());
6849
6850 if (line.has_z())
6851 set_option_value(m_time_processor.machine_limits.machine_max_jerk_z, i, line.z());
6852
6853 if (line.has_e())
6854 set_option_value(m_time_processor.machine_limits.machine_max_jerk_e, i, line.e());
6855
6856 float value;
6857 if (line.has_value('S', value))
6858 set_option_value(m_time_processor.machine_limits.machine_min_extruding_rate, i, value);
6859
6860 if (line.has_value('T', value))
6861 set_option_value(m_time_processor.machine_limits.machine_min_travel_rate, i, value);
6862
6863 if (line.has_value('J', value))
6864 set_option_value(m_time_processor.machine_limits.machine_max_junction_deviation, i, value);
6865 }
6866 }
6867}

References Slic3r::PrintEstimatedStatistics::Count, Slic3r::GCodeReader::GCodeLine::e(), Slic3r::GCodeReader::GCodeLine::has_e(), Slic3r::GCodeReader::GCodeLine::has_value(), Slic3r::GCodeReader::GCodeLine::has_x(), Slic3r::GCodeReader::GCodeLine::has_y(), Slic3r::GCodeReader::GCodeLine::has_z(), m_time_processor, Slic3r::PrintEstimatedStatistics::Normal, Slic3r::set_option_value(), Slic3r::GCodeReader::GCodeLine::x(), Slic3r::GCodeReader::GCodeLine::y(), and Slic3r::GCodeReader::GCodeLine::z().

Referenced by register_commands().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_M221()

void Slic3r::GCodeProcessor::process_M221 ( const GCodeReader::GCodeLine & line)
private
6918{
6919 float value_s;
6920 float value_t;
6921 if (line.has_value('S', value_s) && !line.has_value('T', value_t)) {
6922 value_s *= 0.01f;
6923 for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
6924 m_time_processor.machines[i].extrude_factor_override_percentage = value_s;
6925 }
6926 }
6927}

References Slic3r::PrintEstimatedStatistics::Count, Slic3r::GCodeReader::GCodeLine::has_value(), and m_time_processor.

Referenced by register_commands().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_M400()

void Slic3r::GCodeProcessor::process_M400 ( const GCodeReader::GCodeLine & line)
private
6948{
6949 float value_s = 0.0;
6950 float value_p = 0.0;
6951 const bool has_delay = line.has_value('S', value_s) || line.has_value('P', value_p);
6952 if (m_flavor != gcfKlipper && !has_delay)
6953 return;
6954 value_s += value_p * 0.001;
6955 // Skip post-print end-gcode dwells so they don't inflate the M73 estimate (see
6956 // m_skip_end_gcode_delays). Only omits dwell time — no state is updated here.
6957 if (m_skip_end_gcode_delays && has_delay)
6958 return;
6959 simulate_st_synchronize(value_s);
6960}
bool m_skip_end_gcode_delays
Definition GCodeProcessor.hpp:1286

References Slic3r::gcfKlipper, Slic3r::GCodeReader::GCodeLine::has_value(), m_flavor, m_skip_end_gcode_delays, and simulate_st_synchronize().

Referenced by register_commands().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_M401()

void Slic3r::GCodeProcessor::process_M401 ( const GCodeReader::GCodeLine & line)
private
6963{
6964 if (m_flavor != gcfRepetier)
6965 return;
6966
6967 for (unsigned char a = 0; a <= 3; ++a) {
6968 m_cached_position.position[a] = m_start_position[a];
6969 }
6970 m_cached_position.feedrate = m_feedrate;
6971}
CachedPosition m_cached_position
Definition GCodeProcessor.hpp:1236

References Slic3r::gcfRepetier, m_cached_position, m_feedrate, m_flavor, and m_start_position.

Referenced by register_commands().

Here is the caller graph for this function:

◆ process_M402()

void Slic3r::GCodeProcessor::process_M402 ( const GCodeReader::GCodeLine & line)
private
6974{
6975 if (m_flavor != gcfRepetier)
6976 return;
6977
6978 // see for reference:
6979 // https://github.com/repetier/Repetier-Firmware/blob/master/src/ArduinoAVR/Repetier/Printer.cpp
6980 // void Printer::GoToMemoryPosition(bool x, bool y, bool z, bool e, float feed)
6981
6982 bool has_xyz = !(line.has('X') || line.has('Y') || line.has('Z'));
6983
6984 float p = FLT_MAX;
6985 for (unsigned char a = X; a <= Z; ++a) {
6986 if (has_xyz || line.has(a)) {
6987 p = m_cached_position.position[a];
6988 if (p != FLT_MAX)
6989 m_start_position[a] = p;
6990 }
6991 }
6992
6993 p = m_cached_position.position[E];
6994 if (p != FLT_MAX)
6995 m_start_position[E] = p;
6996
6997 p = FLT_MAX;
6998 if (!line.has_value(4, p))
6999 p = m_cached_position.feedrate;
7000
7001 if (p != FLT_MAX)
7002 m_feedrate = p;
7003}

References Slic3r::E, Slic3r::gcfRepetier, Slic3r::GCodeReader::GCodeLine::has(), Slic3r::GCodeReader::GCodeLine::has_value(), m_cached_position, m_feedrate, m_flavor, m_start_position, Slic3r::X, and Slic3r::Z.

Referenced by register_commands().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_M566()

void Slic3r::GCodeProcessor::process_M566 ( const GCodeReader::GCodeLine & line)
private
7006{
7007 for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
7008 if (line.has_x())
7009 set_option_value(m_time_processor.machine_limits.machine_max_jerk_x, i, line.x() * MMMIN_TO_MMSEC);
7010
7011 if (line.has_y())
7012 set_option_value(m_time_processor.machine_limits.machine_max_jerk_y, i, line.y() * MMMIN_TO_MMSEC);
7013
7014 if (line.has_z())
7015 set_option_value(m_time_processor.machine_limits.machine_max_jerk_z, i, line.z() * MMMIN_TO_MMSEC);
7016
7017 if (line.has_e())
7018 set_option_value(m_time_processor.machine_limits.machine_max_jerk_e, i, line.e() * MMMIN_TO_MMSEC);
7019 }
7020}

References Slic3r::PrintEstimatedStatistics::Count, Slic3r::GCodeReader::GCodeLine::e(), Slic3r::GCodeReader::GCodeLine::has_e(), Slic3r::GCodeReader::GCodeLine::has_x(), Slic3r::GCodeReader::GCodeLine::has_y(), Slic3r::GCodeReader::GCodeLine::has_z(), m_time_processor, MMMIN_TO_MMSEC, Slic3r::set_option_value(), Slic3r::GCodeReader::GCodeLine::x(), Slic3r::GCodeReader::GCodeLine::y(), and Slic3r::GCodeReader::GCodeLine::z().

Referenced by register_commands().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_M572()

void Slic3r::GCodeProcessor::process_M572 ( const GCodeReader::GCodeLine & line)
private
6610{
6611 float pa_value = m_pressure_advance;
6612 line.has_value('S', pa_value);
6613 m_pressure_advance = std::max(0.0f, pa_value);
6614 // BOOST_LOG_TRIVIAL(debug) << "M572 command: PA set to " << m_pressure_advance;
6615}
float m_pressure_advance
Definition GCodeProcessor.hpp:1322

References Slic3r::GCodeReader::GCodeLine::has_value(), and m_pressure_advance.

Referenced by register_commands().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_M6211()

void Slic3r::GCodeProcessor::process_M6211 ( const GCodeReader::GCodeLine & line)
private
2923{
2924 if (boost::algorithm::istarts_with(m_printer_model, "elegoo"))
2926}
void process_elegoo_M6211(const GCodeReader::GCodeLine &line)
Definition ElegooGCodeProcessorHelper.cpp:139

References m_printer_model, and process_elegoo_M6211().

Referenced by register_commands().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_M622()

void Slic3r::GCodeProcessor::process_M622 ( const GCodeReader::GCodeLine & line)
private
6930{
6931 float value_j;
6932 if(line.has_value('J',value_j)){
6933 int interger_j = (int)(std::round(value_j));
6934 if(interger_j == 1 && !m_measure_g29_time)
6935 m_measure_g29_time = true;
6936 }
6937
6938}

References Slic3r::GCodeReader::GCodeLine::has_value(), and m_measure_g29_time.

Referenced by register_commands().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_M623()

void Slic3r::GCodeProcessor::process_M623 ( const GCodeReader::GCodeLine & line)
private
6941{
6943 m_measure_g29_time = false;
6944}

References m_measure_g29_time.

Referenced by register_commands().

Here is the caller graph for this function:

◆ process_M702()

void Slic3r::GCodeProcessor::process_M702 ( const GCodeReader::GCodeLine & line)
private
7023{
7024 int filament_id = get_filament_id();
7025 if (line.has('C')) {
7026 // MK3 MMU2 specific M code:
7027 // M702 C is expected to be sent by the custom end G-code when finalizing a print.
7028 // The MK3 unit shall unload and park the active filament into the MMU2 unit.
7029 m_time_processor.extruder_unloaded = true;
7031 }
7032}

References get_filament_id(), get_filament_unload_time(), Slic3r::GCodeReader::GCodeLine::has(), m_time_processor, and simulate_st_synchronize().

Referenced by register_commands().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_M82()

void Slic3r::GCodeProcessor::process_M82 ( const GCodeReader::GCodeLine & line)
private

References Absolute, and m_e_local_positioning_type.

Referenced by register_commands().

Here is the caller graph for this function:

◆ process_M83()

void Slic3r::GCodeProcessor::process_M83 ( const GCodeReader::GCodeLine & line)
private

References m_e_local_positioning_type, and Relative.

Referenced by register_commands().

Here is the caller graph for this function:

◆ process_M900()

void Slic3r::GCodeProcessor::process_M900 ( const GCodeReader::GCodeLine & line)
private
6602{
6603 float pa_value = m_pressure_advance;
6604 line.has_value('K', pa_value);
6605 m_pressure_advance = std::max(0.0f, pa_value);
6606 // BOOST_LOG_TRIVIAL(debug) << "M900 command: PA set to " << m_pressure_advance;
6607}

References Slic3r::GCodeReader::GCodeLine::has_value(), and m_pressure_advance.

Referenced by register_commands().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_producers_tags()

bool Slic3r::GCodeProcessor::process_producers_tags ( const std::string_view comment)
private
4678{
4679 switch (m_producer)
4680 {
4682 case EProducer::Slic3r:
4684 case EProducer::OrcaSlicer: { return process_bambuslicer_tags(comment); }
4685 case EProducer::Cura: { return process_cura_tags(comment); }
4686 case EProducer::Simplify3D: { return process_simplify3d_tags(comment); }
4687 case EProducer::CraftWare: { return process_craftware_tags(comment); }
4688 case EProducer::ideaMaker: { return process_ideamaker_tags(comment); }
4689 case EProducer::KissSlicer: { return process_kissslicer_tags(comment); }
4690 default: { return false; }
4691 }
4692}
bool process_cura_tags(const std::string_view comment)
Definition GCodeProcessor.cpp:4699
bool process_craftware_tags(const std::string_view comment)
Definition GCodeProcessor.cpp:4922
bool process_bambuslicer_tags(const std::string_view comment)
Definition GCodeProcessor.cpp:4694
bool process_kissslicer_tags(const std::string_view comment)
Definition GCodeProcessor.cpp:5035
bool process_ideamaker_tags(const std::string_view comment)
Definition GCodeProcessor.cpp:4972
@ CraftWare
Definition GCodeProcessor.hpp:1365
@ ideaMaker
Definition GCodeProcessor.hpp:1366
@ Cura
Definition GCodeProcessor.hpp:1363
@ KissSlicer
Definition GCodeProcessor.hpp:1367
bool process_simplify3d_tags(const std::string_view comment)
Definition GCodeProcessor.cpp:4773

References CraftWare, Cura, ideaMaker, KissSlicer, m_producer, OrcaSlicer, process_bambuslicer_tags(), process_craftware_tags(), process_cura_tags(), process_ideamaker_tags(), process_kissslicer_tags(), process_simplify3d_tags(), Simplify3D, Slic3r, Slic3rPE, and SuperSlicer.

Referenced by process_tags().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_SET_PRESSURE_ADVANCE()

void Slic3r::GCodeProcessor::process_SET_PRESSURE_ADVANCE ( const GCodeReader::GCodeLine & line)
private
6618{
6619 static const std::regex regex(R"(SET_PRESSURE_ADVANCE\s+(?:.*\s+)?ADVANCE\s*=\s*([\d.]+))");
6620 std::smatch matches;
6621
6622 if (std::regex_search(line.raw(), matches, regex) && matches.size() > 1) {
6623 float pa_value = 0;
6624 try {
6625 pa_value = std::stof(matches[1].str());
6626 } catch (...) {}
6627 m_pressure_advance = std::max(0.0f, pa_value);
6628 }
6629}

References m_pressure_advance, and Slic3r::GCodeReader::GCodeLine::raw().

Referenced by process_gcode_line().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_SET_VELOCITY_LIMIT()

void Slic3r::GCodeProcessor::process_SET_VELOCITY_LIMIT ( const GCodeReader::GCodeLine & line)
private
6870{
6871 static const std::regex parameter_pattern(
6872 R"(\s(VELOCITY|ACCEL|ACCEL_TO_DECEL|SQUARE_CORNER_VELOCITY|MINIMUM_CRUISE_RATIO)\s*=\s*([+]?(?:[0-9]+(?:\.[0-9]*)?|\.[0-9]+)(?:[eE][+-]?[0-9]+)?)(?=\s|;|$))",
6873 std::regex::icase);
6874 const std::string command = line.raw().substr(0, line.raw().find(';'));
6875 std::vector<std::pair<std::string, float>> parameters;
6876 for (std::sregex_iterator it(command.begin(), command.end(), parameter_pattern), end; it != end; ++it) {
6877 float value;
6878 try {
6879 value = std::stof((*it)[2].str());
6880 } catch (const std::exception&) {
6881 continue;
6882 }
6883 if (std::isfinite(value))
6884 parameters.emplace_back(boost::to_upper_copy((*it)[1].str()), value);
6885 }
6886 // Klipper 0.13 converts ACCEL_TO_DECEL only when the line has no MINIMUM_CRUISE_RATIO, and later
6887 // releases ignore it, so a line carrying both (as Orca writes) is planned with the cruise ratio.
6888 const bool has_cruise_ratio = std::any_of(parameters.begin(), parameters.end(),
6889 [](const auto& parameter) { return parameter.first == "MINIMUM_CRUISE_RATIO" && parameter.second >= 0.0f && parameter.second < 1.0f; });
6890 for (const auto& [name, value] : parameters) {
6891 for (size_t i = 0; i < m_time_processor.machines.size(); ++i) {
6892 TimeMachine& machine = m_time_processor.machines[i];
6893 // Klipper replaces its single live max_accel for print and travel; the profile-clamping
6894 // setters would diverge from the firmware when custom G-code raises the limit.
6895 if (name == "ACCEL" && value > 0.0f)
6896 machine.acceleration = machine.travel_acceleration = value;
6897 else if (name == "MINIMUM_CRUISE_RATIO" && value >= 0.0f && value < 1.0f) {
6898 if (machine.klipper_queue_priming && machine.requested_accel_to_decel >= 0.0f)
6899 machine.klipper_junction_flush -= 1.0f;
6900 machine.minimum_cruise_ratio = value;
6901 machine.requested_accel_to_decel = -1.0f;
6902 } else if (name == "ACCEL_TO_DECEL" && value > 0.0f && !has_cruise_ratio) {
6903 if (machine.klipper_queue_priming && machine.requested_accel_to_decel < 0.0f)
6904 machine.klipper_junction_flush += 1.0f;
6905 machine.requested_accel_to_decel = value;
6906 } else if (name == "SQUARE_CORNER_VELOCITY" && value >= 0.0f) {
6907 set_option_value(m_time_processor.machine_limits.machine_max_jerk_x, i, value);
6908 set_option_value(m_time_processor.machine_limits.machine_max_jerk_y, i, value);
6909 } else if (name == "VELOCITY" && value > 0.0f) {
6910 set_option_value(m_time_processor.machine_limits.machine_max_speed_x, i, value);
6911 set_option_value(m_time_processor.machine_limits.machine_max_speed_y, i, value);
6912 }
6913 }
6914 }
6915}

References Slic3r::GCodeProcessor::TimeMachine::acceleration, Slic3r::GCodeProcessor::TimeMachine::klipper_junction_flush, Slic3r::GCodeProcessor::TimeMachine::klipper_queue_priming, m_time_processor, Slic3r::GCodeProcessor::TimeMachine::minimum_cruise_ratio, Slic3r::GCodeReader::GCodeLine::raw(), Slic3r::GCodeProcessor::TimeMachine::requested_accel_to_decel, Slic3r::set_option_value(), and Slic3r::GCodeProcessor::TimeMachine::travel_acceleration.

Referenced by process_gcode_line().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_simplify3d_tags()

bool Slic3r::GCodeProcessor::process_simplify3d_tags ( const std::string_view comment)
private
4774{
4775 // extrusion roles
4776
4777 // in older versions the comments did not contain the key 'feature'
4778 std::string_view cmt = comment;
4779 size_t pos = cmt.find(" feature");
4780 if (pos == 0)
4781 cmt.remove_prefix(8);
4782
4783 // ; skirt
4784 pos = cmt.find(" skirt");
4785 if (pos == 0) {
4787 return true;
4788 }
4789
4790 // ; outer perimeter
4791 pos = cmt.find(" outer perimeter");
4792 if (pos == 0) {
4794 m_seams_detector.activate(true);
4795 return true;
4796 }
4797
4798 // ; inner perimeter
4799 pos = cmt.find(" inner perimeter");
4800 if (pos == 0) {
4802 return true;
4803 }
4804
4805 // ; gap fill
4806 pos = cmt.find(" gap fill");
4807 if (pos == 0) {
4809 return true;
4810 }
4811
4812 // ; infill
4813 pos = cmt.find(" infill");
4814 if (pos == 0) {
4816 return true;
4817 }
4818
4819 // ; solid layer
4820 pos = cmt.find(" solid layer");
4821 if (pos == 0) {
4823 return true;
4824 }
4825
4826 // ; bridge
4827 pos = cmt.find(" bridge");
4828 if (pos == 0) {
4830 return true;
4831 }
4832
4833 // ; internal bridge
4834 pos = cmt.find(" internal bridge");
4835 if (pos == 0) {
4837 return true;
4838 }
4839
4840 // ; support
4841 pos = cmt.find(" support");
4842 if (pos == 0) {
4844 return true;
4845 }
4846
4847 // ; dense support
4848 pos = cmt.find(" dense support");
4849 if (pos == 0) {
4851 return true;
4852 }
4853
4854 // ; prime pillar
4855 pos = cmt.find(" prime pillar");
4856 if (pos == 0) {
4858 return true;
4859 }
4860
4861 // ; ooze shield
4862 pos = cmt.find(" ooze shield");
4863 if (pos == 0) {
4864 set_extrusion_role(erNone); // Missing mapping
4865 return true;
4866 }
4867
4868 // ; raft
4869 pos = cmt.find(" raft");
4870 if (pos == 0) {
4872 return true;
4873 }
4874
4875 // ; internal single extrusion
4876 pos = cmt.find(" internal single extrusion");
4877 if (pos == 0) {
4878 set_extrusion_role(erNone); // Missing mapping
4879 return true;
4880 }
4881
4882 // geometry
4883 // ; tool
4884 std::string tag = " tool";
4885 pos = cmt.find(tag);
4886 if (pos == 0) {
4887 const std::string_view data = cmt.substr(pos + tag.length());
4888 std::string h_tag = "H";
4889 size_t h_start = data.find(h_tag);
4890 size_t h_end = data.find_first_of(' ', h_start);
4891 std::string w_tag = "W";
4892 size_t w_start = data.find(w_tag);
4893 size_t w_end = data.find_first_of(' ', w_start);
4894 if (h_start != data.npos) {
4895 if (!parse_number(data.substr(h_start + 1, (h_end != data.npos) ? h_end - h_start - 1 : h_end), m_forced_height))
4896 BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Height (" << comment << ").";
4897 }
4898 if (w_start != data.npos) {
4899 if (!parse_number(data.substr(w_start + 1, (w_end != data.npos) ? w_end - w_start - 1 : w_end), m_forced_width))
4900 BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Width (" << comment << ").";
4901 }
4902
4903 return true;
4904 }
4905
4906 // ; layer
4907 tag = " layer";
4908 pos = cmt.find(tag);
4909 if (pos == 0) {
4910 // skip lines "; layer end"
4911 const std::string_view data = cmt.substr(pos + tag.length());
4912 size_t end_start = data.find("end");
4913 if (end_start == data.npos)
4914 ++m_layer_id;
4915
4916 return true;
4917 }
4918
4919 return false;
4920}
@ erGapFill
Definition ExtrusionEntity.hpp:38

References Slic3r::erBridgeInfill, Slic3r::erExternalPerimeter, Slic3r::erGapFill, Slic3r::erInternalBridgeInfill, Slic3r::erInternalInfill, Slic3r::erNone, Slic3r::erPerimeter, Slic3r::erSkirt, Slic3r::erSolidInfill, Slic3r::erSupportMaterial, Slic3r::erSupportMaterialInterface, Slic3r::erWipeTower, m_forced_height, m_forced_width, m_layer_id, m_seams_detector, Slic3r::parse_number(), and set_extrusion_role().

Referenced by process_producers_tags().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_SYNC()

void Slic3r::GCodeProcessor::process_SYNC ( const GCodeReader::GCodeLine & line)
private
7036{
7037 float time = 0;
7038 if (line.has_value('T', time) ) {
7040 }
7041}

References Slic3r::GCodeReader::GCodeLine::has_value(), and simulate_st_synchronize().

Referenced by register_commands().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_T() [1/3]

void Slic3r::GCodeProcessor::process_T ( const GCodeReader::GCodeLine & line)
private
7045{
7046 // parse the H<nozzle> logical-nozzle id off the T line. H2C's change_filament template emits
7047 // `T<fil> H<nozzle>`; the single-nozzle fleet emits a bare `T<fil>` (H absent → -1 → byte-inert
7048 // via the self-gate).
7049 int nozzle_id = -1;
7050 float nozzle_val = 0.f;
7051 if (line.has_value('H', nozzle_val))
7052 nozzle_id = static_cast<int>(nozzle_val);
7053 process_T(line.cmd(), nozzle_id);
7054}

References Slic3r::GCodeReader::GCodeLine::cmd(), Slic3r::GCodeReader::GCodeLine::has_value(), and process_T().

Referenced by process_M108(), process_M135(), process_T(), process_T(), process_tags(), and register_commands().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_T() [2/3]

void Slic3r::GCodeProcessor::process_T ( const std::string_view command)
private
7089{
7090 // the no-nozzle-context callers (custom-gcode tool-change strings, color-print T parsing) route
7091 // through the H-less variant; -1 keeps the richer model on its filament-first nozzle fallback.
7092 process_T(command, -1);
7093}

References process_T().

Here is the call graph for this function:

◆ process_T() [3/3]

void Slic3r::GCodeProcessor::process_T ( const std::string_view command,
int nozzle_id )
private
7096{
7097 unsigned int eid = 0;
7098 auto ret = std::from_chars(command.data() + 1, command.data()+command.size(), eid);
7099 if (std::errc::invalid_argument == ret.ec)
7100 return;
7101
7102 int curr_filament_id = get_filament_id(false);
7103 int curr_extruder_id = get_extruder_id(false);
7104 //TODO: multi switch
7105 if (command.length() > 1) {
7106 if (eid < 0 || eid > 254) {
7107 //BBS: T255, T1000 and T1100 is used as special command for BBL machine and does not cost time. return directly
7108 // Orca: T1001 (hotend-type detection) and T65535/T65279 (AMS unload virtual-tool selects, paired with
7109 // M620/M621 S65535/S65279) are firmware opcodes emitted verbatim by BBL machine start/end g-code, not
7110 // real tool changes - whitelist them so the time estimator stops flagging these valid lines.
7111 if ((m_flavor == gcfMarlinLegacy || m_flavor == gcfMarlinFirmware) && (command == "Tx" || command == "Tc" || command == "T?" ||
7112 eid == 1000 || eid == 1100 || eid == 255 || eid == 1001 || eid == 65279 || eid == 65535))
7113 return;
7114
7115 // T-1 is a valid gcode line for RepRap Firmwares (used to deselects all tools)
7116 if ((m_flavor != gcfRepRapFirmware && m_flavor != gcfRepRapSprinter) || eid != -1)
7117 BOOST_LOG_TRIVIAL(error) << "Invalid T command (" << command << ").";
7118 }
7119 else {
7120 if (eid >= m_result.filaments_count) {
7121 BOOST_LOG_TRIVIAL(error) << "Invalid T command (" << command << ").";
7122 return;
7123 }
7124 // process_filament_change(int,int) self-gates back to the single-arg model for the
7125 // single-nozzle fleet, so this call is byte-inert for X1/P1/A1/H2S/A2L.
7126 process_filament_change(eid, nozzle_id);
7127 }
7128 }
7129}

References Slic3r::gcfMarlinFirmware, Slic3r::gcfMarlinLegacy, Slic3r::gcfRepRapFirmware, Slic3r::gcfRepRapSprinter, get_extruder_id(), get_filament_id(), m_flavor, m_result, and process_filament_change().

Here is the call graph for this function:

◆ process_tags()

void Slic3r::GCodeProcessor::process_tags ( const std::string_view comment,
bool producers_enabled )
private
4403{
4404 // producers tags
4405 if (producers_enabled && process_producers_tags(comment))
4406 return;
4407
4408 // extrusion role tag
4409 if (boost::starts_with(comment, reserved_tag(ETags::Role))) {
4412 m_seams_detector.activate(true);
4414 return;
4415 }
4416
4417 // ; OBJECT_ID start
4418 if (boost::starts_with(comment, " start printing object")) {
4420 return;
4421 }
4422
4423 // ; OBJECT_ID end
4424 if (boost::starts_with(comment, " stop printing object")) {
4425 m_object_label_id = -1;
4426 return;
4427 }
4428
4429 // ; Z_HEIGHT:
4430 if (boost::starts_with(comment, " Z_HEIGHT:")) {
4431 m_print_z = get_z_height(comment);
4432 return;
4433 }
4434
4435 // ;Z: -- the layer Z tag non-BBL printers write. Only read on a belt printer,
4436 // where the preview labels its layers with it (GCodeViewer::load_as_gcode);
4437 // elsewhere print_z stays unset, as it always was, so nothing downstream of
4438 // it changes for other printers.
4439 if (m_belt_printer && boost::starts_with(comment, "Z:")) {
4440 m_print_z = get_z_height(comment);
4441 return;
4442 }
4443
4444 if (boost::starts_with(comment, " CONFIG_BLOCK_START")) {
4445 m_in_config_block = true;
4446 return;
4447 }
4448 if (boost::starts_with(comment, " CONFIG_BLOCK_END")) {
4449 m_in_config_block = false;
4450 return;
4451 }
4452
4453 // Belt printer: derive the physical tilt magnitude from the slicing-rotation
4454 // angle header comment (used to enable the preview's belt view). Only the belt
4455 // header carries it outside the config block; the config block lists the key
4456 // for every printer, belt or not.
4457 if (!m_in_config_block && boost::starts_with(comment, " belt_slice_rotation_angle = ")) {
4458 try {
4459 m_result.belt_tilt_angle = std::abs(std::stof(std::string(comment.substr(29))));
4460 } catch (...) {}
4461 return;
4462 }
4463 // wipe start tag
4464 if (boost::starts_with(comment, reserved_tag(ETags::Wipe_Start))) {
4465 m_wiping = true;
4466 return;
4467 }
4468
4469 // wipe end tag
4470 if (boost::starts_with(comment, reserved_tag(ETags::Wipe_End))) {
4471 m_wiping = false;
4472 return;
4473 }
4474
4475 if (boost::starts_with(comment, reserved_tag(ETags::Wipe_Tower_Start))) {
4476 m_wipe_tower = true;
4477 return;
4478 }
4479
4480 if (boost::starts_with(comment, reserved_tag(ETags::Wipe_Tower_End))) {
4481 m_wipe_tower = false;
4482 m_used_filaments.process_wipe_tower_cache(this);
4483 return;
4484 }
4485
4486 // SKIPPABLE region tags. Mark the current section so its time blocks are stamped with the skip
4487 // type. The shipping time_lapse_gcode template emits these tags fleet-wide, so this parse fires on
4488 // essentially every slice (m_skippable → true, m_skippable_type → stTimelapse); it only sets
4489 // internal state and early-returns, so the output is byte-identical until the injector reads the
4490 // stamps.
4491 if (boost::starts_with(comment, GCodeProcessor::Skippable_Start_Tag)) {
4492 m_skippable = true;
4493 return;
4494 }
4495
4496 if (boost::starts_with(comment, GCodeProcessor::Skippable_End_Tag)) {
4497 m_skippable = false;
4499 return;
4500 }
4501
4502 // skippable type
4503 if (boost::starts_with(comment, GCodeProcessor::Skippable_Type_Tag)) {
4504 std::string_view type = comment.substr(GCodeProcessor::Skippable_Type_Tag.length());
4505 set_skippable_type(type);
4506 return;
4507 }
4508
4509 //BBS: flush start tag
4510 if (boost::starts_with(comment, GCodeProcessor::Flush_Start_Tag)) {
4511 m_flushing = true;
4512 return;
4513 }
4514
4515 //BBS: flush end tag
4516 if (boost::starts_with(comment, GCodeProcessor::Flush_End_Tag)) {
4517 m_flushing = false;
4518 return;
4519 }
4520
4521 if (boost::starts_with(comment, GCodeProcessor::VFlush_Start_Tag)) {
4522 m_virtual_flushing = true;
4523 return;
4524 }
4525
4526 if (boost::starts_with(comment, GCodeProcessor::VFlush_End_Tag)) {
4527 m_virtual_flushing = false;
4528 return;
4529 }
4530
4531 // End gcode marker: skip post-print M400 S/P dwells after this point so the M73 estimate reports
4532 // print-completion time, not post-print filtration/cooldown. BBS drops the same remainder in
4533 // calculate_time(is_final).
4534 if (comment == Machine_End_GCode_Start_Tag) {
4536 return;
4537 }
4538
4539 // Orca: Integrate filament consumption for purging performed to an external device and controlled via macros
4540 // (eg. Happy Hare) in the filament consumption stats.
4541 if (boost::starts_with(comment, GCodeProcessor::External_Purge_Tag)) {
4542 static const std::regex numberRegex(R"(\d+\.\d+)");
4543 std::smatch match;
4544 std::string line(comment);
4545 if (std::regex_search(line, match, numberRegex)) {
4546 int filament_id = get_filament_id();
4547 float filament_diameter = (static_cast<size_t>(filament_id) < m_result.filament_diameters.size()) ? m_result.filament_diameters[filament_id] : m_result.filament_diameters.back();
4548 float filament_radius = 0.5f * filament_diameter;
4549 float area_filament_cross_section = static_cast<float>(M_PI) * sqr(filament_radius);
4550
4551 float dE = std::stof(match.str());
4552 float volume_extruded_filament = area_filament_cross_section * dE;
4553 m_used_filaments.update_flush_per_filament(filament_id, volume_extruded_filament);
4554 }
4555 return;
4556 }
4557
4558 if (!producers_enabled || m_producer == EProducer::OrcaSlicer) {
4559 // height tag
4560 if (boost::starts_with(comment, reserved_tag(ETags::Height))) {
4561 if (!parse_number(comment.substr(reserved_tag(ETags::Height).size()), m_forced_height))
4562 BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Height (" << comment << ").";
4563 return;
4564 }
4565 // width tag
4566 if (boost::starts_with(comment, reserved_tag(ETags::Width))) {
4567 if (!parse_number(comment.substr(reserved_tag(ETags::Width).size()), m_forced_width))
4568 BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Width (" << comment << ").";
4569 return;
4570 }
4571 // Orca: manual tool change tag
4572 if (m_manual_filament_change && boost::starts_with(comment, reserved_tag(ETags::Manual_Tool_Change))) {
4573 std::string_view tool_change_cmd = comment.substr(reserved_tag(ETags::Manual_Tool_Change).length());
4574 if (boost::starts_with(tool_change_cmd, "T")) {
4575 process_T(tool_change_cmd);
4576 }
4577 }
4578 }
4579
4580 // color change tag
4581 if (boost::starts_with(comment, reserved_tag(ETags::Color_Change))) {
4582 unsigned char filament_id = 0;
4583 static std::vector<std::string> Default_Colors = {
4584 "#0B2C7A", // { 0.043f, 0.173f, 0.478f }, // bluish
4585 "#1C8891", // { 0.110f, 0.533f, 0.569f },
4586 "#AAF200", // { 0.667f, 0.949f, 0.000f },
4587 "#F5CE0A", // { 0.961f, 0.808f, 0.039f },
4588 "#D16830", // { 0.820f, 0.408f, 0.188f },
4589 "#942616", // { 0.581f, 0.149f, 0.087f } // reddish
4590 };
4591
4592 std::string color = Default_Colors[0];
4593 auto is_valid_color = [](const std::string& color) {
4594 auto is_hex_digit = [](char c) {
4595 return ((c >= '0' && c <= '9') ||
4596 (c >= 'A' && c <= 'F') ||
4597 (c >= 'a' && c <= 'f'));
4598 };
4599
4600 if (color[0] != '#' || color.length() != 7)
4601 return false;
4602 for (int i = 1; i <= 6; ++i) {
4603 if (!is_hex_digit(color[i]))
4604 return false;
4605 }
4606 return true;
4607 };
4608
4609 std::vector<std::string> tokens;
4610 boost::split(tokens, comment, boost::is_any_of(","), boost::token_compress_on);
4611 if (tokens.size() > 1) {
4612 if (tokens[1][0] == 'T') {
4613 int eid;
4614 if (!parse_number(tokens[1].substr(1), eid) || eid < 0 || eid > 255) {
4615 BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid value for Color_Change (" << comment << ").";
4616 return;
4617 }
4618 filament_id = static_cast<unsigned char>(eid);
4619 }
4620 }
4621 if (tokens.size() > 2) {
4622 if (is_valid_color(tokens[2]))
4623 color = tokens[2];
4624 }
4625 else {
4626 color = Default_Colors[m_last_default_color_id];
4628 if (m_last_default_color_id == Default_Colors.size())
4630 }
4631
4632 if (filament_id < m_extruder_colors.size())
4633 m_extruder_colors[filament_id] = static_cast<unsigned char>(m_extruder_offsets.size()) + m_cp_color.counter; // color_change position in list of color for preview
4634 ++m_cp_color.counter;
4635 if (m_cp_color.counter == UCHAR_MAX)
4636 m_cp_color.counter = 0;
4637
4638 if (get_filament_id() == filament_id) {
4639 m_cp_color.current = m_extruder_colors[filament_id];
4641 CustomGCode::Item item = { static_cast<double>(m_end_position[2]), CustomGCode::ColorChange, filament_id + 1, color, "" };
4642 m_result.custom_gcode_per_print_z.emplace_back(item);
4646 }
4647
4648 return;
4649 }
4650
4651 // pause print tag
4652 if (comment == reserved_tag(ETags::Pause_Print)) {
4654 CustomGCode::Item item = { static_cast<double>(m_end_position[2]), CustomGCode::PausePrint, get_filament_id() + 1, "", ""};
4655 m_result.custom_gcode_per_print_z.emplace_back(item);
4658 return;
4659 }
4660
4661 // custom code tag
4662 if (comment == reserved_tag(ETags::Custom_Code)) {
4664 CustomGCode::Item item = { static_cast<double>(m_end_position[2]), CustomGCode::Custom, get_filament_id() + 1, "", ""};
4665 m_result.custom_gcode_per_print_z.emplace_back(item);
4667 return;
4668 }
4669
4670 // layer change tag
4671 if (comment == reserved_tag(ETags::Layer_Change)) {
4672 ++m_layer_id;
4673 return;
4674 }
4675}
static ExtrusionRole string_to_role(const std::string_view role)
Definition ExtrusionEntity.cpp:701
static const std::string Machine_End_GCode_Start_Tag
Definition GCodeProcessor.hpp:597
static const std::string VFlush_End_Tag
Definition GCodeProcessor.hpp:578
static const std::string Skippable_End_Tag
Definition GCodeProcessor.hpp:588
void set_skippable_type(const std::string_view type)
Definition GCodeProcessor.cpp:7673
static const std::string VFlush_Start_Tag
Definition GCodeProcessor.hpp:577
void process_custom_gcode_time(CustomGCode::Type code)
Definition GCodeProcessor.cpp:8018
static const std::string & reserved_tag(ETags tag)
Definition GCodeProcessor.hpp:636
static const std::string Skippable_Start_Tag
Definition GCodeProcessor.hpp:587
size_t m_last_default_color_id
Definition GCodeProcessor.hpp:1345
bool m_in_config_block
Definition GCodeProcessor.hpp:1339
static const std::string Flush_Start_Tag
Definition GCodeProcessor.hpp:575
@ Color_Change
Definition GCodeProcessor.hpp:610
@ Width
Definition GCodeProcessor.hpp:608
@ Wipe_Tower_End
Definition GCodeProcessor.hpp:620
@ Pause_Print
Definition GCodeProcessor.hpp:611
@ Wipe_End
Definition GCodeProcessor.hpp:606
@ Layer_Change
Definition GCodeProcessor.hpp:609
@ Custom_Code
Definition GCodeProcessor.hpp:612
@ Role
Definition GCodeProcessor.hpp:604
@ Wipe_Start
Definition GCodeProcessor.hpp:605
@ Wipe_Tower_Start
Definition GCodeProcessor.hpp:619
@ Height
Definition GCodeProcessor.hpp:607
@ Manual_Tool_Change
Definition GCodeProcessor.hpp:617
static const std::string External_Purge_Tag
Definition GCodeProcessor.hpp:579
bool m_skippable
Definition GCodeProcessor.hpp:1244
bool process_producers_tags(const std::string_view comment)
Definition GCodeProcessor.cpp:4677
static const std::string Skippable_Type_Tag
Definition GCodeProcessor.hpp:589
static const std::string Flush_End_Tag
Definition GCodeProcessor.hpp:576
bool m_virtual_flushing
Definition GCodeProcessor.hpp:1239
int m_object_label_id
Definition GCodeProcessor.hpp:1246
float m_print_z
Definition GCodeProcessor.hpp:1248
bool m_wipe_tower
Definition GCodeProcessor.hpp:1240
@ PausePrint
Definition CustomGCode.hpp:20
@ Custom
Definition CustomGCode.hpp:23
@ stNone
Definition GCodeProcessor.hpp:77
@ Custom_GCode
Definition GCodeProcessor.hpp:61
@ Color_change
Definition GCodeProcessor.hpp:59
static int get_object_label_id(const std::string_view comment_1)
Definition GCodeProcessor.cpp:239
static float get_z_height(const std::string_view comment_1)
Definition GCodeProcessor.cpp:252
static bool is_hex_digit(char c)
Definition DeviceManager.cpp:5641

References Color_Change, Slic3r::Color_change, Slic3r::CustomGCode::ColorChange, Slic3r::CustomGCode::Custom, Custom_Code, Slic3r::Custom_GCode, Slic3r::erCustom, Slic3r::erExternalPerimeter, External_Purge_Tag, Flush_End_Tag, Flush_Start_Tag, get_filament_id(), Slic3r::get_object_label_id(), Slic3r::get_z_height(), Height, Slic3r::is_hex_digit(), Layer_Change, Slic3r::length(), m_belt_printer, m_cp_color, m_end_position, m_extruder_colors, m_extruder_offsets, m_extrusion_role, m_flushing, m_forced_height, m_forced_width, m_g1_line_id, m_in_config_block, m_last_default_color_id, m_layer_id, m_manual_filament_change, m_object_label_id, m_options_z_corrector, M_PI, m_print_z, m_processing_start_custom_gcode, m_producer, m_result, m_seams_detector, m_skip_end_gcode_delays, m_skippable, m_skippable_type, m_used_filaments, m_virtual_flushing, m_wipe_tower, m_wiping, Machine_End_GCode_Start_Tag, Manual_Tool_Change, OrcaSlicer, Slic3r::parse_number(), Slic3r::Pause_Print, Pause_Print, Slic3r::CustomGCode::PausePrint, process_custom_gcode_time(), process_filaments(), process_producers_tags(), process_T(), reserved_tag(), Role, set_extrusion_role(), set_skippable_type(), Skippable_End_Tag, Skippable_Start_Tag, Skippable_Type_Tag, Slic3r::sqr(), Slic3r::stNone, store_move_vertex(), Slic3r::ExtrusionEntity::string_to_role(), VFlush_End_Tag, VFlush_Start_Tag, Width, Wipe_End, Wipe_Start, Wipe_Tower_End, and Wipe_Tower_Start.

Referenced by process_gcode_line().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_VG1()

void Slic3r::GCodeProcessor::process_VG1 ( const GCodeReader::GCodeLine & line)
private
5724{
5725 int filament_id = get_filament_id();
5726 int last_filament_id = get_last_filament_id();
5727 float filament_diameter = (static_cast<size_t>(filament_id) < m_result.filament_diameters.size()) ? m_result.filament_diameters[filament_id] : m_result.filament_diameters.back();
5728 float filament_radius = 0.5f * filament_diameter;
5729 float area_filament_cross_section = static_cast<float>(M_PI) * sqr(filament_radius);
5730
5731 auto absolute_position = [this](Axis axis, const GCodeReader::GCodeLine& lineG1) {
5733 if (axis == E)
5735
5736 if (lineG1.has(Slic3r::Axis(axis))) {
5737 float lengthsScaleFactor = (m_units == EUnits::Inches) ? INCHES_TO_MM : 1.0f;
5738 float ret = lineG1.value(Slic3r::Axis(axis)) * lengthsScaleFactor;
5739 return is_relative ? m_start_position[axis] + ret : m_origin[axis] + ret;
5740 }
5741 else
5742 return m_start_position[axis];
5743 };
5744
5745 auto move_type = [this](const AxisCoords& delta_pos) {
5747
5748 if (m_wiping)
5749 type = EMoveType::Wipe;
5750 else if (delta_pos[E] < 0.0f)
5751 type = (delta_pos[X] != 0.0f || delta_pos[Y] != 0.0f || delta_pos[Z] != 0.0f) ? EMoveType::Travel : EMoveType::Retract;
5752 else if (delta_pos[E] > 0.0f) {
5753 if (delta_pos[X] == 0.0f && delta_pos[Y] == 0.0f)
5754 type = (delta_pos[Z] == 0.0f) ? EMoveType::Unretract : EMoveType::Travel;
5755 else if (delta_pos[X] != 0.0f || delta_pos[Y] != 0.0f)
5756 type = EMoveType::Extrude;
5757 }
5758 else if (delta_pos[X] != 0.0f || delta_pos[Y] != 0.0f || delta_pos[Z] != 0.0f)
5759 type = EMoveType::Travel;
5760
5761 return type;
5762 };
5763
5764 ++m_g1_line_id;
5765
5766 // enable processing of lines M201/M203/M204/M205
5767 m_time_processor.machine_envelope_processing_enabled = true;
5768
5769 // updates axes positions from line
5770 for (unsigned char a = X; a <= E; ++a) {
5771 m_end_position[a] = absolute_position((Axis)a, line);
5772 }
5773
5774 // updates feedrate from line, if present
5775 if (line.has_f())
5776 m_feedrate = line.f() * MMMIN_TO_MMSEC;
5777
5778 // calculates movement deltas
5779 float max_abs_delta = 0.0f;
5780 AxisCoords delta_pos;
5781 for (unsigned char a = X; a <= E; ++a) {
5782 delta_pos[a] = m_end_position[a] - m_start_position[a];
5783 max_abs_delta = std::max<float>(max_abs_delta, std::abs(delta_pos[a]));
5784 }
5785
5786 // no displacement, return
5787 if (max_abs_delta == 0.0f)
5788 return;
5789
5790 EMoveType type = move_type(delta_pos);
5791 // BBS: now we only support virtual flush
5793 int extruder_id = get_extruder_id();
5794 float volume_flushed_filament = area_filament_cross_section * delta_pos[E];
5795 if (m_remaining_volume[extruder_id] > volume_flushed_filament)
5796 {
5797 m_used_filaments.update_flush_per_filament(last_filament_id, volume_flushed_filament);
5798 m_remaining_volume[extruder_id] -= volume_flushed_filament;
5799 }
5800 else {
5801 m_used_filaments.update_flush_per_filament(last_filament_id, m_remaining_volume[extruder_id]);
5802 m_used_filaments.update_flush_per_filament(filament_id, volume_flushed_filament - m_remaining_volume[extruder_id]);
5803 m_remaining_volume[extruder_id] = 0.f;
5804 }
5805 }
5806
5807 if (line.has_f())
5808 m_feedrate = line.f() * MMMIN_TO_MMSEC;
5809
5810 // time estimate section
5811 auto move_length = [](const AxisCoords& delta_pos) {
5812 float sq_xyz_length = sqr(delta_pos[X]) + sqr(delta_pos[Y]) + sqr(delta_pos[Z]);
5813 return (sq_xyz_length > 0.0f) ? std::sqrt(sq_xyz_length) : std::abs(delta_pos[E]);
5814 };
5815
5816 auto is_extrusion_only_move = [](const AxisCoords& delta_pos) {
5817 return delta_pos[X] == 0.0f && delta_pos[Y] == 0.0f && delta_pos[Z] == 0.0f && delta_pos[E] != 0.0f;
5818 };
5819
5820 float distance = move_length(delta_pos);
5821 assert(distance != 0.0f);
5822 float inv_distance = 1.0f / distance;
5823
5824 for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
5825 TimeMachine& machine = m_time_processor.machines[i];
5826 if (!machine.enabled)
5827 continue;
5828
5829 TimeMachine::State& curr = machine.curr;
5830 TimeMachine::State& prev = machine.prev;
5831 std::vector<TimeBlock>& blocks = machine.blocks;
5832
5833 curr.feedrate = (delta_pos[E] == 0.0f) ?
5836
5837 //BBS: calculeta enter and exit direction
5838 curr.enter_direction = { static_cast<float>(delta_pos[X]), static_cast<float>(delta_pos[Y]), static_cast<float>(delta_pos[Z]) };
5839 float norm = curr.enter_direction.norm();
5840 if (!is_extrusion_only_move(delta_pos))
5841 curr.enter_direction = curr.enter_direction / norm;
5842 curr.exit_direction = curr.enter_direction;
5843 curr.jd_unit_vec = Vec4f(static_cast<float>(delta_pos[X]),
5844 static_cast<float>(delta_pos[Y]),
5845 static_cast<float>(delta_pos[Z]),
5846 static_cast<float>(delta_pos[E])).normalized();
5847
5848 TimeBlock block;
5849 block.move_type = type;
5850 // stamp the current SKIPPABLE type onto the block. Stamped stTimelapse inside the fleet-wide
5851 // time_lapse_gcode regions; byte-inert because nothing reads the stamp until the injector
5852 // consumes it.
5853 block.skippable_type = m_skippable_type;
5854 //BBS: don't calculate travel time into extrusion path, except travel inside start and end gcode.
5855 block.role = (type != EMoveType::Travel || m_extrusion_role == erCustom) ? m_extrusion_role : erNone;
5856 block.distance = distance;
5857 block.g1_line_id = m_g1_line_id;
5858 block.layer_id = std::max<unsigned int>(1, m_layer_id);
5859 block.flags.prepare_stage = m_processing_start_custom_gcode;
5860
5861 //BBS: limite the cruise according to centripetal acceleration
5862 //Only need to handle when both prev and curr segment has movement in x-y plane
5863 if ((prev.exit_direction(0) != 0.0f || prev.exit_direction(1) != 0.0f) &&
5864 (curr.enter_direction(0) != 0.0f || curr.enter_direction(1) != 0.0f)) {
5865 Vec3f v1 = prev.exit_direction;
5866 v1(2, 0) = 0.0f;
5867 v1.normalize();
5868 Vec3f v2 = curr.enter_direction;
5869 v2(2, 0) = 0.0f;
5870 v2.normalize();
5871 float norm_diff = (v2 - v1).norm();
5872 //BBS: don't need to consider limitation of centripetal acceleration
5873 //when angle changing is larger than 28.96 degree or two lines are almost collinear.
5874 //Attention!!! these two value must be same with MC side.
5875 if (norm_diff < 0.5f && norm_diff > 0.00001f) {
5876 //BBS: calculate angle
5877 float dot = v1(0) * v2(0) + v1(1) * v2(1);
5878 float cross = v1(0) * v2(1) - v1(1) * v2(0);
5879 float angle = float(atan2(double(cross), double(dot)));
5880 float sin_theta_2 = sqrt((1.0f - cos(angle)) * 0.5f);
5881 float r = sqrt(sqr(delta_pos[X]) + sqr(delta_pos[Y])) * 0.5 / sin_theta_2;
5882 float acc = get_acceleration(static_cast<PrintEstimatedStatistics::ETimeMode>(i));
5883 curr.feedrate = std::min(curr.feedrate, sqrt(acc * r));
5884 }
5885 }
5886
5887 // calculates block cruise feedrate
5888 float min_feedrate_factor = 1.0f;
5889 for (unsigned char a = X; a <= E; ++a) {
5890 curr.axis_feedrate[a] = curr.feedrate * delta_pos[a] * inv_distance;
5891 if (a == E)
5892 curr.axis_feedrate[a] *= machine.extrude_factor_override_percentage;
5893
5894 curr.abs_axis_feedrate[a] = std::abs(curr.axis_feedrate[a]);
5895 if (curr.abs_axis_feedrate[a] != 0.0f) {
5896 float axis_max_feedrate = get_axis_max_feedrate(static_cast<PrintEstimatedStatistics::ETimeMode>(i), static_cast<Axis>(a), m_machine_config_idx);
5897 if (axis_max_feedrate != 0.0f) min_feedrate_factor = std::min<float>(min_feedrate_factor, axis_max_feedrate / curr.abs_axis_feedrate[a]);
5898 }
5899 }
5900 //BBS: update curr.feedrate
5901 curr.feedrate *= min_feedrate_factor;
5902 block.feedrate_profile.cruise = curr.feedrate;
5903
5904 if (min_feedrate_factor < 1.0f) {
5905 for (unsigned char a = X; a <= E; ++a) {
5906 curr.axis_feedrate[a] *= min_feedrate_factor;
5907 curr.abs_axis_feedrate[a] *= min_feedrate_factor;
5908 }
5909 }
5910
5911 // calculates block acceleration
5912 float acceleration =
5914 (is_extrusion_only_move(delta_pos) ?
5916 get_acceleration(static_cast<PrintEstimatedStatistics::ETimeMode>(i)));
5917
5918 //BBS
5919 for (unsigned char a = X; a <= E; ++a) {
5920 float axis_max_acceleration = get_axis_max_acceleration(static_cast<PrintEstimatedStatistics::ETimeMode>(i), static_cast<Axis>(a), m_machine_config_idx);
5921 if (acceleration * std::abs(delta_pos[a]) * inv_distance > axis_max_acceleration)
5922 acceleration = axis_max_acceleration / (std::abs(delta_pos[a]) * inv_distance);
5923 }
5924
5925 block.acceleration = acceleration;
5926
5927 static const float PREVIOUS_FEEDRATE_THRESHOLD = 0.0001f;
5928 const bool has_prev_move = !blocks.empty() && prev.feedrate > PREVIOUS_FEEDRATE_THRESHOLD;
5929
5930 // Orca: junction deviation where the firmware uses it (Klipper always, Marlin 2 with M205 J).
5931 // Negative leaves the classic jerk path below unchanged.
5932 const float vmax_junction_jd = calc_vmax_junction_deviation(block, prev, curr, has_prev_move,
5933 static_cast<PrintEstimatedStatistics::ETimeMode>(i));
5934 const bool use_junction_deviation = vmax_junction_jd >= 0.0f;
5935
5936 // calculates block exit feedrate. Junction deviation has no per axis jerk floor, so a move is
5937 // free to start from rest.
5938 curr.safe_feedrate = use_junction_deviation ? 0.0f : block.feedrate_profile.cruise;
5939
5940 if (!use_junction_deviation) {
5941 for (unsigned char a = X; a <= E; ++a) {
5942 float axis_max_jerk = get_axis_max_jerk(static_cast<PrintEstimatedStatistics::ETimeMode>(i), static_cast<Axis>(a));
5943 if (curr.abs_axis_feedrate[a] > axis_max_jerk)
5944 curr.safe_feedrate = std::min(curr.safe_feedrate, axis_max_jerk);
5945 }
5946 }
5947
5948 block.feedrate_profile.exit = curr.safe_feedrate;
5949
5950 // calculates block entry feedrate
5951 float vmax_junction = use_junction_deviation ? vmax_junction_jd : curr.safe_feedrate;
5952 if (!use_junction_deviation && has_prev_move) {
5953 bool prev_speed_larger = prev.feedrate > block.feedrate_profile.cruise;
5954 float smaller_speed_factor = prev_speed_larger ? (block.feedrate_profile.cruise / prev.feedrate) : (prev.feedrate / block.feedrate_profile.cruise);
5955 // Pick the smaller of the nominal speeds. Higher speed shall not be achieved at the junction during coasting.
5956 vmax_junction = prev_speed_larger ? block.feedrate_profile.cruise : prev.feedrate;
5957
5958 float v_factor = 1.0f;
5959 bool limited = false;
5960
5961 for (unsigned char a = X; a <= E; ++a) {
5962 // Limit an axis. We have to differentiate coasting from the reversal of an axis movement, or a full stop.
5963 if (a == X) {
5964 Vec3f exit_v = prev.feedrate * (prev.exit_direction);
5965 if (prev_speed_larger)
5966 exit_v *= smaller_speed_factor;
5967 Vec3f entry_v = block.feedrate_profile.cruise * (curr.enter_direction);
5968 Vec3f jerk_v = entry_v - exit_v;
5969 jerk_v = Vec3f(abs(jerk_v.x()), abs(jerk_v.y()), abs(jerk_v.z()));
5970 Vec3f max_xyz_jerk_v = get_xyz_max_jerk(static_cast<PrintEstimatedStatistics::ETimeMode>(i));
5971
5972 for (size_t i = 0; i < 3; i++)
5973 {
5974 if (jerk_v[i] > max_xyz_jerk_v[i]) {
5975 v_factor *= max_xyz_jerk_v[i] / jerk_v[i];
5976 jerk_v *= v_factor;
5977 limited = true;
5978 }
5979 }
5980 }
5981 else if (a == Y || a == Z) {
5982 continue;
5983 }
5984 else {
5985 float v_exit = prev.axis_feedrate[a];
5986 float v_entry = curr.axis_feedrate[a];
5987
5988 if (prev_speed_larger)
5989 v_exit *= smaller_speed_factor;
5990
5991 if (limited) {
5992 v_exit *= v_factor;
5993 v_entry *= v_factor;
5994 }
5995
5996 // Calculate the jerk depending on whether the axis is coasting in the same direction or reversing a direction.
5997 float jerk =
5998 (v_exit > v_entry) ?
5999 (((v_entry > 0.0f) || (v_exit < 0.0f)) ?
6000 // coasting
6001 (v_exit - v_entry) :
6002 // axis reversal
6003 std::max(v_exit, -v_entry)) :
6004 // v_exit <= v_entry
6005 (((v_entry < 0.0f) || (v_exit > 0.0f)) ?
6006 // coasting
6007 (v_entry - v_exit) :
6008 // axis reversal
6009 std::max(-v_exit, v_entry));
6010
6011
6012 float axis_max_jerk = get_axis_max_jerk(static_cast<PrintEstimatedStatistics::ETimeMode>(i), static_cast<Axis>(a));
6013 if (jerk > axis_max_jerk) {
6014 v_factor *= axis_max_jerk / jerk;
6015 limited = true;
6016 }
6017 }
6018 }
6019
6020 if (limited)
6021 vmax_junction *= v_factor;
6022
6023 // Now the transition velocity is known, which maximizes the shared exit / entry velocity while
6024 // respecting the jerk factors, it may be possible, that applying separate safe exit / entry velocities will achieve faster prints.
6025 float vmax_junction_threshold = vmax_junction * 0.99f;
6026
6027 // Not coasting. The machine will stop and start the movements anyway, better to start the segment from start.
6028 if (prev.safe_feedrate > vmax_junction_threshold && curr.safe_feedrate > vmax_junction_threshold)
6029 vmax_junction = curr.safe_feedrate;
6030 }
6031
6032 float v_allowable = max_allowable_speed(-acceleration, curr.safe_feedrate, block.distance);
6033 block.feedrate_profile.entry = std::min(vmax_junction, v_allowable);
6034
6035 block.max_entry_speed = vmax_junction;
6036 block.flags.nominal_length = (block.feedrate_profile.cruise <= v_allowable);
6037 block.flags.recalculate = true;
6038 block.safe_feedrate = curr.safe_feedrate;
6039
6040 // calculates block trapezoid
6041 block.calculate_trapezoid();
6042
6043 // updates previous
6044 prev = curr;
6045
6046 blocks.push_back(block);
6047 }
6048
6049 // do not save the move
6050}

References Slic3r::GCodeProcessor::TimeMachine::State::abs_axis_feedrate, Slic3r::GCodeProcessor::TimeBlock::acceleration, Slic3r::angle(), Slic3r::GCodeProcessor::TimeMachine::State::axis_feedrate, Slic3r::GCodeProcessor::TimeMachine::blocks, calc_vmax_junction_deviation(), Slic3r::GCodeProcessor::TimeBlock::calculate_trapezoid(), Slic3r::PrintEstimatedStatistics::Count, Slic3r::cross(), Slic3r::GCodeProcessor::FeedrateProfile::cruise, Slic3r::GCodeProcessor::TimeMachine::curr, Slic3r::GCodeProcessor::TimeBlock::distance, Slic3r::dot(), Slic3r::E, Slic3r::GCodeProcessor::TimeMachine::enabled, Slic3r::GCodeProcessor::TimeMachine::State::enter_direction, Slic3r::GCodeProcessor::FeedrateProfile::entry, Slic3r::erCustom, Slic3r::erNone, Slic3r::GCodeProcessor::FeedrateProfile::exit, Slic3r::GCodeProcessor::TimeMachine::State::exit_direction, Slic3r::Extrude, Slic3r::GCodeProcessor::TimeMachine::extrude_factor_override_percentage, Slic3r::GCodeReader::GCodeLine::f(), Slic3r::GCodeProcessor::TimeMachine::State::feedrate, Slic3r::GCodeProcessor::TimeBlock::feedrate_profile, Slic3r::GCodeProcessor::TimeBlock::flags, Slic3r::GCodeProcessor::TimeBlock::g1_line_id, get_acceleration(), get_axis_max_acceleration(), get_axis_max_feedrate(), get_axis_max_jerk(), get_extruder_id(), get_filament_id(), get_last_filament_id(), get_retract_acceleration(), get_travel_acceleration(), get_xyz_max_jerk(), Slic3r::GCodeReader::GCodeLine::has_f(), Inches, INCHES_TO_MM, Slic3r::GCodeProcessor::TimeMachine::State::jd_unit_vec, Slic3r::GCodeProcessor::TimeBlock::layer_id, m_e_local_positioning_type, m_end_position, m_extrusion_role, m_feedrate, m_g1_line_id, m_global_positioning_type, m_layer_id, m_machine_config_idx, m_origin, M_PI, m_processing_start_custom_gcode, m_remaining_volume, m_result, m_skippable_type, m_start_position, m_time_processor, m_units, m_used_filaments, m_virtual_flushing, m_wiping, Slic3r::max_allowable_speed(), Slic3r::GCodeProcessor::TimeBlock::max_entry_speed, minimum_feedrate(), minimum_travel_feedrate(), MMMIN_TO_MMSEC, Slic3r::GCodeProcessor::TimeBlock::move_type, Slic3r::GCodeProcessor::TimeBlock::Flags::nominal_length, Slic3r::Noop, Slic3r::GCodeProcessor::TimeBlock::Flags::prepare_stage, Slic3r::GCodeProcessor::TimeMachine::prev, Slic3r::GCodeProcessor::TimeBlock::Flags::recalculate, Relative, Slic3r::Retract, Slic3r::GCodeProcessor::TimeBlock::role, Slic3r::GCodeProcessor::TimeBlock::safe_feedrate, Slic3r::GCodeProcessor::TimeMachine::State::safe_feedrate, Slic3r::GCodeProcessor::TimeBlock::skippable_type, Slic3r::sqr(), Slic3r::Travel, Slic3r::Unretract, Slic3r::Wipe, Slic3r::X, Slic3r::Y, and Slic3r::Z.

Referenced by register_commands().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_VM104()

void Slic3r::GCodeProcessor::process_VM104 ( const GCodeReader::GCodeLine & line)
private
6582{
6583 process_M104(line);
6584}
void process_M104(const GCodeReader::GCodeLine &line)
Definition GCodeProcessor.cpp:6573

References process_M104().

Referenced by register_commands().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_VM109()

void Slic3r::GCodeProcessor::process_VM109 ( const GCodeReader::GCodeLine & line)
private
6671{
6672 process_M109(line);
6673}
void process_M109(const GCodeReader::GCodeLine &line)
Definition GCodeProcessor.cpp:6650

References process_M109().

Referenced by register_commands().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ register_commands()

void Slic3r::GCodeProcessor::register_commands ( )
private
2832{
2833 // !!! registered command must be upper case
2834 std::unordered_map<std::string, CommandProcessor::command_handler_t> command_handler_list = {
2835 {"G0", [this](const GCodeReader::GCodeLine& line) { process_G0(line); }}, // Move
2836 {"G1", [this](const GCodeReader::GCodeLine& line) { process_G1(line); }}, // Move
2837 {"G2", [this](const GCodeReader::GCodeLine& line) { process_G2_G3(line, true); }}, // Move
2838 {"G3", [this](const GCodeReader::GCodeLine& line) { process_G2_G3(line, false); }}, // Move
2839 {"G4", [this](const GCodeReader::GCodeLine& line) { process_G4(line); }}, // Delay
2840
2841 {"G10", [this](const GCodeReader::GCodeLine& line) { process_G10(line); }}, // Retract
2842 {"G11", [this](const GCodeReader::GCodeLine& line) { process_G11(line); }}, // Unretract
2843
2844 {"G20", [this](const GCodeReader::GCodeLine& line) { process_G20(line); }}, // Set Units to Inches
2845 {"G21", [this](const GCodeReader::GCodeLine& line) { process_G21(line); }}, // Set Units to Millimeters
2846 {"G22", [this](const GCodeReader::GCodeLine& line) { process_G22(line); }}, // Firmware controlled retract
2847 {"G23", [this](const GCodeReader::GCodeLine& line) { process_G23(line); }}, // Firmware controlled unretract
2848 {"G28", [this](const GCodeReader::GCodeLine& line) { process_G28(line); }}, // Move to origin
2849 {"G29", [this](const GCodeReader::GCodeLine& line) { process_G29(line); }},
2850
2851 {"G90", [this](const GCodeReader::GCodeLine& line) { process_G90(line); }}, // Set to Absolute Positioning
2852 {"G91", [this](const GCodeReader::GCodeLine& line) { process_G91(line); }}, // Set to Relative Positioning
2853 {"G92", [this](const GCodeReader::GCodeLine& line) { process_G92(line); }}, // Set Position
2854
2855 {"M1", [this](const GCodeReader::GCodeLine& line) { process_M1(line); }}, // Sleep or Conditional stop
2856
2857 {"M82", [this](const GCodeReader::GCodeLine& line) { process_M82(line); }}, // Set extruder to absolute mode
2858 {"M83", [this](const GCodeReader::GCodeLine& line) { process_M83(line); }}, // Set extruder to relative mode
2859
2860 {"M104", [this](const GCodeReader::GCodeLine& line) { process_M104(line); }}, // Set extruder temperature
2861 {"M106", [this](const GCodeReader::GCodeLine& line) { process_M106(line); }}, // Set fan speed
2862 {"M107", [this](const GCodeReader::GCodeLine& line) { process_M107(line); }}, // Disable fan
2863 {"M108", [this](const GCodeReader::GCodeLine& line) { process_M108(line); }}, // Set tool (Sailfish)
2864 {"M109", [this](const GCodeReader::GCodeLine& line) { process_M109(line); }}, // Set extruder temperature and wait
2865
2866 {"M132", [this](const GCodeReader::GCodeLine& line) { process_M132(line); }}, // Recall stored home offsets
2867 {"M135", [this](const GCodeReader::GCodeLine& line) { process_M135(line); }}, // Set tool (MakerWare)
2868
2869 {"M140", [this](const GCodeReader::GCodeLine& line) { process_M140(line); }}, // Set bed temperature
2870 {"M190", [this](const GCodeReader::GCodeLine& line) { process_M190(line); }}, // Wait bed temperature
2871 {"M191", [this](const GCodeReader::GCodeLine& line) { process_M191(line); }}, // Wait chamber temperature
2872
2873 {"M201", [this](const GCodeReader::GCodeLine& line) { process_M201(line); }}, // Set max printing acceleration
2874 {"M203", [this](const GCodeReader::GCodeLine& line) { process_M203(line); }}, // Set maximum feedrate
2875 {"M204", [this](const GCodeReader::GCodeLine& line) { process_M204(line); }}, // Set default acceleration
2876 {"M205", [this](const GCodeReader::GCodeLine& line) { process_M205(line); }}, // Advanced settings
2877 {"M221", [this](const GCodeReader::GCodeLine& line) { process_M221(line); }}, // Set extrude factor override percentage
2878
2879 {"M400", [this](const GCodeReader::GCodeLine& line) { process_M400(line); }}, // BBS delay
2880 {"M401", [this](const GCodeReader::GCodeLine& line) { process_M401(line); }}, // Repetier: Store x, y and z position
2881 {"M402", [this](const GCodeReader::GCodeLine& line) { process_M402(line); }}, // Repetier: Go to stored position
2882 {"M566", [this](const GCodeReader::GCodeLine& line) { process_M566(line); }}, // Set allowable instantaneous speed change
2883 {"M702", [this](const GCodeReader::GCodeLine& line) { process_M702(line); }}, // Unload the current filament into the MK3 MMU2 unit at the end of print.
2884 {"M1020", [this](const GCodeReader::GCodeLine& line) { process_M1020(line); }}, // Select Tool
2885
2886// ORCA: Add Pressure Advance visualization support
2887 {"M900", [this](const GCodeReader::GCodeLine& line) { process_M900(line); }}, // Marlin: Set pressure advance
2888 {"M572", [this](const GCodeReader::GCodeLine& line) { process_M572(line); }}, // RepRapFirmware/Duet: Set pressure advance
2889
2890 {"T", [this](const GCodeReader::GCodeLine& line) { process_T(line); }}, // Select Tool
2891 {"SYNC", [this](const GCodeReader::GCodeLine& line) { process_SYNC(line); }}, // SYNC TIME
2892
2893 {"VG1", [this](const GCodeReader::GCodeLine& line) { process_VG1(line); }},
2894 {"VM104", [this](const GCodeReader::GCodeLine& line) { process_VM104(line); }},
2895 {"VM109", [this](const GCodeReader::GCodeLine& line) { process_VM109(line); }},
2896 {"M622", [this](const GCodeReader::GCodeLine& line) { process_M622(line);}},
2897 {"M623", [this](const GCodeReader::GCodeLine& line) { process_M623(line);}},
2898 {"M6211", [this](const GCodeReader::GCodeLine& line) { process_M6211(line); }}
2899 };
2900
2901 std::unordered_set<std::string>early_quit_commands = {
2902 "T"
2903 };
2904
2905 auto to_lowercase = [](std::string str)->std::string {
2906 std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) {
2907 return std::tolower(c);
2908 });
2909 return str;
2910 };
2911
2912 for (auto elem : command_handler_list) {
2913 auto& uppercase_cmd = elem.first;
2914 auto& handler = elem.second;
2915 bool early_quit = early_quit_commands.count(uppercase_cmd) > 0;
2916 m_command_processor.register_command(uppercase_cmd, handler,early_quit);
2917 if (auto lowercase_cmd = to_lowercase(uppercase_cmd); lowercase_cmd != uppercase_cmd)
2918 m_command_processor.register_command(lowercase_cmd, handler,early_quit);
2919 }
2920}
void process_G90(const GCodeReader::GCodeLine &line)
Definition GCodeProcessor.cpp:6498
void process_M135(const GCodeReader::GCodeLine &line)
Definition GCodeProcessor.cpp:6693
void process_VG1(const GCodeReader::GCodeLine &line)
Definition GCodeProcessor.cpp:5723
void process_M900(const GCodeReader::GCodeLine &line)
Definition GCodeProcessor.cpp:6601
void process_M622(const GCodeReader::GCodeLine &line)
Definition GCodeProcessor.cpp:6929
void process_M190(const GCodeReader::GCodeLine &line)
Definition GCodeProcessor.cpp:6714
void process_M203(const GCodeReader::GCodeLine &line)
Definition GCodeProcessor.cpp:6759
void process_M6211(const GCodeReader::GCodeLine &line)
Definition GCodeProcessor.cpp:2922
void process_M106(const GCodeReader::GCodeLine &line)
Definition GCodeProcessor.cpp:6586
void process_G10(const GCodeReader::GCodeLine &line)
Definition GCodeProcessor.cpp:6378
void process_M623(const GCodeReader::GCodeLine &line)
Definition GCodeProcessor.cpp:6940
void process_G21(const GCodeReader::GCodeLine &line)
Definition GCodeProcessor.cpp:6409
void process_M566(const GCodeReader::GCodeLine &line)
Definition GCodeProcessor.cpp:7005
void process_G29(const GCodeReader::GCodeLine &line)
Definition GCodeProcessor.cpp:6367
void process_G28(const GCodeReader::GCodeLine &line)
Definition GCodeProcessor.cpp:6462
void process_M221(const GCodeReader::GCodeLine &line)
Definition GCodeProcessor.cpp:6917
void process_G91(const GCodeReader::GCodeLine &line)
Definition GCodeProcessor.cpp:6503
void process_M205(const GCodeReader::GCodeLine &line)
Definition GCodeProcessor.cpp:6836
void process_M107(const GCodeReader::GCodeLine &line)
Definition GCodeProcessor.cpp:6631
void process_VM109(const GCodeReader::GCodeLine &line)
Definition GCodeProcessor.cpp:6670
void process_G92(const GCodeReader::GCodeLine &line)
Definition GCodeProcessor.cpp:6508
void process_M140(const GCodeReader::GCodeLine &line)
Definition GCodeProcessor.cpp:6707
void process_M132(const GCodeReader::GCodeLine &line)
Definition GCodeProcessor.cpp:6675
void process_SYNC(const GCodeReader::GCodeLine &line)
Definition GCodeProcessor.cpp:7035
void process_M1(const GCodeReader::GCodeLine &line)
Definition GCodeProcessor.cpp:6558
void process_M83(const GCodeReader::GCodeLine &line)
Definition GCodeProcessor.cpp:6568
void process_M204(const GCodeReader::GCodeLine &line)
Definition GCodeProcessor.cpp:6792
void process_M400(const GCodeReader::GCodeLine &line)
Definition GCodeProcessor.cpp:6947
void process_G2_G3(const GCodeReader::GCodeLine &line, bool clockwise)
Definition GCodeProcessor.cpp:6052
void process_G22(const GCodeReader::GCodeLine &line)
Definition GCodeProcessor.cpp:6414
void process_M201(const GCodeReader::GCodeLine &line)
Definition GCodeProcessor.cpp:6733
void process_G20(const GCodeReader::GCodeLine &line)
Definition GCodeProcessor.cpp:6404
void process_M191(const GCodeReader::GCodeLine &line)
Definition GCodeProcessor.cpp:6723
void process_M572(const GCodeReader::GCodeLine &line)
Definition GCodeProcessor.cpp:6609
void process_VM104(const GCodeReader::GCodeLine &line)
Definition GCodeProcessor.cpp:6581
void process_G11(const GCodeReader::GCodeLine &line)
Definition GCodeProcessor.cpp:6391
void process_M82(const GCodeReader::GCodeLine &line)
Definition GCodeProcessor.cpp:6563
void process_M402(const GCodeReader::GCodeLine &line)
Definition GCodeProcessor.cpp:6973
void process_G23(const GCodeReader::GCodeLine &line)
Definition GCodeProcessor.cpp:6420
void process_M401(const GCodeReader::GCodeLine &line)
Definition GCodeProcessor.cpp:6962
void process_M702(const GCodeReader::GCodeLine &line)
Definition GCodeProcessor.cpp:7022
void process_M108(const GCodeReader::GCodeLine &line)
Definition GCodeProcessor.cpp:6636
void process_G4(const GCodeReader::GCodeLine &line)
Definition GCodeProcessor.cpp:6356
void process_M1020(const GCodeReader::GCodeLine &line)
Definition GCodeProcessor.cpp:7056
void process_G0(const GCodeReader::GCodeLine &line)
Definition GCodeProcessor.cpp:5156

References m_command_processor, process_G0(), process_G1(), process_G10(), process_G11(), process_G20(), process_G21(), process_G22(), process_G23(), process_G28(), process_G29(), process_G2_G3(), process_G4(), process_G90(), process_G91(), process_G92(), process_M1(), process_M1020(), process_M104(), process_M106(), process_M107(), process_M108(), process_M109(), process_M132(), process_M135(), process_M140(), process_M190(), process_M191(), process_M201(), process_M203(), process_M204(), process_M205(), process_M221(), process_M400(), process_M401(), process_M402(), process_M566(), process_M572(), process_M6211(), process_M622(), process_M623(), process_M702(), process_M82(), process_M83(), process_M900(), process_SYNC(), process_T(), process_VG1(), process_VM104(), and process_VM109().

Referenced by GCodeProcessor().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ reserved_tag()

const std::string & Slic3r::GCodeProcessor::reserved_tag ( ETags tag)
inlinestatic

◆ reset()

void Slic3r::GCodeProcessor::reset ( )
3703{
3707 m_extruder_offsets = std::vector<Vec3f>(MIN_EXTRUDERS_COUNT, Vec3f::Zero());
3709 m_nozzle_volume = std::vector<float>(MAXIMUM_EXTRUDER_NUMBER, 0.f);
3710
3711 m_start_position = { 0.0f, 0.0f, 0.0f, 0.0f };
3712 m_end_position = { 0.0f, 0.0f, 0.0f, 0.0f };
3713 m_origin = { 0.0f, 0.0f, 0.0f, 0.0f };
3714 m_axis_position_known = { false, false, false };
3715 m_axis_origin_known = { true, true, true };
3718 m_cached_position.reset();
3719 m_wiping = false;
3720 m_flushing = false;
3721 m_virtual_flushing = false;
3722 m_wipe_tower = false;
3723 // reset SKIPPABLE tracking + the collected ranges (stored on the member; see run_post_process).
3724 m_skippable = false;
3726 m_skippable_blocks.clear();
3727 // reset the first-pass usage-block state (rebuilt each run_post_process).
3728 m_filament_blocks.clear();
3729 m_extruder_blocks.clear();
3730 m_machine_start_gcode_end_line_id = (unsigned int) (-1);
3731 m_machine_end_gcode_start_line_id = (unsigned int) (-1);
3733 m_remaining_volume = std::vector<float>(MAXIMUM_EXTRUDER_NUMBER, 0.f);
3734
3735 m_line_id = 0;
3736 m_last_line_id = 0;
3737 m_feedrate = 0.0f;
3738 m_width = 0.0f;
3739 m_height = 0.0f;
3740 m_forced_width = 0.0f;
3741 m_forced_height = 0.0f;
3742 m_mm3_per_mm = 0.0f;
3743 m_travel_dist = 0.0f;
3744 m_fan_speed = 0.0f;
3745 m_z_offset = 0.0f;
3746
3748
3749 m_filament_id = std::vector<unsigned char>(MAXIMUM_EXTRUDER_NUMBER, static_cast<unsigned char>(-1));
3750 m_last_filament_id = std::vector<unsigned char>(MAXIMUM_EXTRUDER_NUMBER, static_cast<unsigned char>(-1));
3751 m_extruder_id = static_cast<unsigned char>(-1);
3752 // clear the multi-nozzle occupancy tracker between slices (the richer hotend-change model's only
3753 // mutable state). Inert for the single-nozzle fleet (never populated).
3754 m_nozzle_status_recorder = MultiNozzleUtils::NozzleStatusRecorder{};
3755 // drop the slot-resolution context and its cached slot; re-seeded per export.
3756 m_nozzle_group_result.reset();
3759 for (size_t i = 0; i < MIN_EXTRUDERS_COUNT; ++i) {
3760 m_extruder_colors[i] = static_cast<unsigned char>(i);
3761 }
3763 for (size_t i = 0; i < MIN_EXTRUDERS_COUNT; ++i) {
3764 m_extruder_temps[i] = 0.0f;
3765 }
3766
3769
3770 // reset pre-heat / pre-cool injector estimator inputs to defaults. Repopulated by apply_config
3771 // each slice.
3772 m_filament_types.clear();
3773 m_nozzle_diameter.clear();
3777 m_enable_pre_heating = false;
3780
3782
3783 m_extruded_last_z = 0.0f;
3784 m_zero_layer_height = 0.0f;
3785 m_first_layer_height = 0.0f;
3787 m_in_config_block = false;
3788 m_g1_line_id = 0;
3789 m_layer_id = 0;
3790 m_cp_color.reset();
3791 m_mass_locator = nullptr;
3792
3794
3795 m_time_processor.reset();
3796 m_used_filaments.reset();
3797
3798 m_result.reset();
3799 m_result.id = ++s_result_id;
3800
3802
3803 m_options_z_corrector.reset();
3804
3806
3807 m_seams_count = 0;
3808 m_g29_time_added = false;
3809 m_preheat_time = 0.f;
3810 m_preheat_steps = 1;
3811}
static const size_t MIN_EXTRUDERS_COUNT
Definition GCodeProcessor.cpp:92
std::vector< std::pair< unsigned int, unsigned int > > m_skippable_blocks
Definition GCodeProcessor.hpp:1274
std::vector< ExtruderPreHeating::FilamentUsageBlock > m_filament_blocks
Definition GCodeProcessor.hpp:1279
int m_seams_count
Definition GCodeProcessor.hpp:1347
unsigned int m_machine_end_gcode_start_line_id
Definition GCodeProcessor.hpp:1282
unsigned int m_last_line_id
Definition GCodeProcessor.hpp:1311
unsigned int m_machine_start_gcode_end_line_id
Definition GCodeProcessor.hpp:1281
std::vector< ExtruderPreHeating::ExtruderUsageBlcok > m_extruder_blocks
Definition GCodeProcessor.hpp:1280
float m_zero_layer_height
Definition GCodeProcessor.hpp:1337
static constexpr size_t MAXIMUM_EXTRUDER_NUMBER
Definition libslic3r.h:70

References Absolute, Slic3r::erNone, Slic3r::gcfRepRapSprinter, m_axis_origin_known, m_axis_position_known, m_cached_position, m_cp_color, m_detect_layer_based_on_tag, m_e_local_positioning_type, m_enable_pre_heating, m_end_position, m_exclusion_volume_path_checker, m_extruded_last_z, m_extruder_blocks, m_extruder_colors, m_extruder_id, m_extruder_max_nozzle_count, m_extruder_offsets, m_extruder_temps, m_extrusion_role, m_fan_speed, m_feedrate, m_filament_blocks, m_filament_id, m_filament_pre_cooling_temp, m_filament_preheat_temperature_delta, m_filament_types, m_first_layer_height, m_flavor, m_flushing, m_forced_height, m_forced_width, m_g1_line_id, m_g29_time_added, m_global_positioning_type, m_handle_hotend_as_extruder, m_has_filament_switcher, m_height, m_highest_bed_temp, m_hotend_cooling_rate, m_hotend_heating_rate, m_in_config_block, m_last_default_color_id, m_last_filament_id, m_last_line_id, m_layer_id, m_line_id, m_machine_config_idx, m_machine_end_gcode_start_line_id, m_machine_start_gcode_end_line_id, m_mass_locator, m_mm3_per_mm, m_nozzle_diameter, m_nozzle_group_result, m_nozzle_status_recorder, m_nozzle_volume, m_options_z_corrector, m_origin, m_physical_extruder_map, m_preheat_steps, m_preheat_time, m_processing_homing_move, m_processing_start_custom_gcode, m_producer, m_remaining_volume, m_result, m_seams_count, m_skip_end_gcode_delays, m_skippable, m_skippable_blocks, m_skippable_type, m_start_position, m_time_processor, m_travel_dist, m_units, m_used_filaments, m_virtual_flushing, m_width, m_wipe_tower, m_wiping, m_z_offset, m_zero_layer_height, MAXIMUM_EXTRUDER_NUMBER, Millimeters, MIN_EXTRUDERS_COUNT, s_result_id, Slic3r::stNone, and Unknown.

Referenced by GCodeProcessor(), and Slic3r::DoExport::init_gcode_processor().

Here is the caller graph for this function:

◆ resolve_target_nozzle()

std::optional< MultiNozzleUtils::NozzleInfo > Slic3r::GCodeProcessor::resolve_target_nozzle ( const MultiNozzleUtils::NozzleGroupResultBase & group,
int id,
int nozzle_id ) const
private
7245{
7246 std::optional<MultiNozzleUtils::NozzleInfo> info;
7247 if (nozzle_id != -1)
7248 info = group.get_nozzle_from_id(nozzle_id);
7249 if (!info) {
7250 auto used_nozzles = group.get_nozzles_for_filament(id);
7251 if (!used_nozzles.empty())
7252 info = used_nozzles.front();
7253 }
7254 return info;
7255}

References Slic3r::MultiNozzleUtils::NozzleGroupResultBase::get_nozzle_from_id(), and Slic3r::MultiNozzleUtils::NozzleGroupResultBase::get_nozzles_for_filament().

Referenced by process_filament_change().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ result()

GCodeProcessorResult & Slic3r::GCodeProcessor::result ( )
inline
1435{ return m_result; }

References m_result.

Referenced by Slic3r::GCodeProcessor::OptionsZCorrector::OptionsZCorrector(), calculate_time(), Slic3r::GCodeProcessor::TimeMachine::calculate_time(), ensure_nozzle_group_result(), Slic3r::Print::reload_gcode_moves(), and Slic3r::ExportLines::synchronize_moves().

Here is the caller graph for this function:

◆ run_post_process()

void Slic3r::GCodeProcessor::run_post_process ( )
private

M104.1: Early Set Hotend Temperature (preheat, and with stealth mode support)

This GCode is used to tell the XL printer the time estimate when a tool will be used next, so that the printer can start preheating the tool in advance.

Parameters

  • P - <number> - time in seconds till the temperature S is required (in standard mode)
  • Q - <number> - time in seconds till the temperature S is required (in stealth mode) The rest is same as M104
1168{
1169 FilePtr in{ boost::nowide::fopen(m_result.filename.c_str(), "rb") };
1170 if (in.f == nullptr)
1171 throw Slic3r::RuntimeError(_u8L("G-code processor post-process export failed.\nCannot open file for reading.\n"));
1172
1173 // temporary file to contain modified gcode
1174 std::string out_path = m_result.filename + ".postprocess";
1175 FilePtr out{ boost::nowide::fopen(out_path.c_str(), "wb") };
1176 if (out.f == nullptr)
1177 throw Slic3r::RuntimeError(_u8L("G-code processor post-process export failed.\nCannot open file for writing.\n"));
1178
1179 std::vector<double> filament_mm(m_result.filaments_count, 0.0);
1180 std::vector<double> filament_cm3(m_result.filaments_count, 0.0);
1181 std::vector<double> filament_g(m_result.filaments_count, 0.0);
1182 std::vector<double> filament_cost(m_result.filaments_count, 0.0);
1183
1184 double filament_total_g = 0.0;
1185 double filament_total_cost = 0.0;
1186
1187 for (const auto& [id, volume] : m_result.print_statistics.total_volumes_per_extruder) {
1188 filament_mm[id] = volume / (static_cast<double>(M_PI) * sqr(0.5 * m_result.filament_diameters[id]));
1189 filament_cm3[id] = volume * 0.001;
1190 filament_g[id] = filament_cm3[id] * double(m_result.filament_densities[id]);
1191 filament_cost[id] = filament_g[id] * double(m_result.filament_costs[id]) * 0.001;
1192 filament_total_g += filament_g[id];
1193 filament_total_cost += filament_cost[id];
1194 }
1195
1196 double total_g_wipe_tower = m_print->print_statistics().total_wipe_tower_filament;
1197
1198
1199 auto time_in_minutes = [](float time_in_seconds) {
1200 assert(time_in_seconds >= 0.f);
1201 return int((time_in_seconds + 0.5f) / 60.0f);
1202 };
1203
1204 auto time_in_last_minute = [](float time_in_seconds) {
1205 assert(time_in_seconds <= 60.0f);
1206 return time_in_seconds / 60.0f;
1207 };
1208
1209 auto format_line_M73_main = [this](const std::string& mask, int percent, int time) {
1210 if(this->m_disable_m73)
1211 return std::string("");
1212
1213 char line_M73[64];
1214 sprintf(line_M73, mask.c_str(),
1215 std::to_string(percent).c_str(),
1216 std::to_string(time).c_str());
1217 return std::string(line_M73);
1218 };
1219
1220 auto format_line_M73_stop_int = [this](const std::string& mask, int time) {
1221 if (this->m_disable_m73)
1222 return std::string("");
1223 char line_M73[64];
1224 sprintf(line_M73, mask.c_str(), std::to_string(time).c_str());
1225 return std::string(line_M73);
1226 };
1227
1228 auto format_line_exhaust_fan_control = [](const std::string& mask,int fan_index,int percent) {
1229 char line_fan[64] = { 0 };
1230 sprintf(line_fan,mask.c_str(),
1231 std::to_string(fan_index).c_str(),
1232 std::to_string(int((percent/100.0)*255)).c_str());
1233 return std::string(line_fan);
1234 };
1235
1236 auto format_time_float = [](float time) {
1238 };
1239
1240 auto format_line_M73_stop_float = [format_time_float](const std::string& mask, float time) {
1241 char line_M73[64];
1242 sprintf(line_M73, mask.c_str(), format_time_float(time).c_str());
1243 return std::string(line_M73);
1244 };
1245
1246 std::string gcode_line;
1247 size_t g1_lines_counter = 0;
1248 // keeps track of last exported pair <percent, remaining time>
1249 std::array<std::pair<int, int>, static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count)> last_exported_main;
1250 for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
1251 last_exported_main[i] = { 0, time_in_minutes(m_time_processor.machines[i].time) };
1252 }
1253
1254 // keeps track of last exported remaining time to next printer stop
1255 std::array<int, static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count)> last_exported_stop;
1256 for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
1257 last_exported_stop[i] = time_in_minutes(m_time_processor.machines[i].time);
1258 }
1259
1260 m_result.lines_ends.clear();
1261 // m_result.lines_ends.emplace_back(std::vector<size_t>());
1262 GCodeFileWriter writer(out, out_path, m_result.lines_ends, "GCode processor post process export failed.\nIs the disk full?");
1264 m_time_processor.machines, writer);
1265 // The line map holds an entry for each line of the file, and the first pass counted them
1266 export_line.reserve(m_line_id);
1267
1268 // replace placeholder lines with the proper final value
1269 // gcode_line is in/out parameter, to reduce expensive memory allocation
1270 auto process_placeholders = [&](std::string& gcode_line) {
1271 bool processed = false;
1272
1273 // remove trailing '\n'
1274 auto line = std::string_view(gcode_line).substr(0, gcode_line.length() - 1);
1275
1276 if (line.length() > 1) {
1277 line = line.substr(1);
1279 for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
1280 const TimeMachine& machine = m_time_processor.machines[i];
1281 if (machine.enabled) {
1282 // export pair <percent, remaining time>
1283 export_line.append_line(format_line_M73_main(machine.line_m73_main_mask.c_str(),
1285 (line == reserved_tag(ETags::First_Line_M73_Placeholder)) ? time_in_minutes(machine.time) : 0));
1286 processed = true;
1287
1288 // export remaining time to next printer stop
1289 if (line == reserved_tag(ETags::First_Line_M73_Placeholder) && !machine.stop_times.empty()) {
1290 const int to_export_stop = time_in_minutes(machine.stop_times.front().elapsed_time);
1291 export_line.append_line(format_line_M73_stop_int(machine.line_m73_stop_mask.c_str(), to_export_stop));
1292 last_exported_stop[i] = to_export_stop;
1293 }
1294 }
1295 }
1297 for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
1298 const TimeMachine& machine = m_time_processor.machines[i];
1300 if (mode == PrintEstimatedStatistics::ETimeMode::Normal || machine.enabled) {
1301 char buf[128];
1302 if (!s_IsBBLPrinter)
1303 // Orca: compatibility with klipper_estimator
1304 sprintf(buf, "; estimated printing time (%s mode) = %s\n",
1305 (mode == PrintEstimatedStatistics::ETimeMode::Normal) ? "normal" : "silent",
1306 get_time_dhms(machine.time).c_str());
1307 else {
1308 sprintf(buf, "; model printing time: %s; total estimated time: %s\n",
1309 get_time_dhms(machine.time - machine.prepare_time).c_str(), get_time_dhms(machine.time).c_str());
1310 }
1311 export_line.append_line(buf);
1312 }
1313 }
1314 for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
1315 const TimeMachine& machine = m_time_processor.machines[i];
1317 if (mode == PrintEstimatedStatistics::ETimeMode::Normal || machine.enabled) {
1318 char buf[128];
1319 sprintf(buf, "; estimated first layer printing time (%s mode) = %s\n",
1320 (mode == PrintEstimatedStatistics::ETimeMode::Normal) ? "normal" : "silent",
1321 get_time_dhms(machine.prepare_time).c_str());
1322 export_line.append_line(buf);
1323 processed = true;
1324 }
1325 }
1326 }
1327 // Orca: write total layer number, this is used by Bambu printers only as of now
1329 char buf[128];
1330 sprintf(buf, "; total layer number: %u\n", m_layer_id);
1331 export_line.append_line(buf);
1332 processed = true;
1333 }
1334 }
1335
1336 return processed;
1337 };
1338
1339 auto process_used_filament = [&](std::string& gcode_line) {
1340 // Prefilter for parsing speed.
1341 if (gcode_line.size() < 8 || gcode_line[0] != ';' || gcode_line[1] != ' ')
1342 return false;
1343 if (const char c = gcode_line[2]; c != 'f' && c != 't')
1344 return false;
1345 auto process_tag = [](std::string& gcode_line, const std::string_view tag, const std::vector<double>& values) {
1346 if (boost::algorithm::starts_with(gcode_line, tag)) {
1347 gcode_line = tag;
1348 char buf[1024];
1349 for (size_t i = 0; i < values.size(); ++i) {
1350 sprintf(buf, i == values.size() - 1 ? " %.2lf\n" : " %.2lf,", values[i]);
1351 gcode_line += buf;
1352 }
1353 return true;
1354 }
1355 return false;
1356 };
1357
1358 bool ret = false;
1359 ret |= process_tag(gcode_line, PrintStatistics::FilamentUsedMmMask, filament_mm);
1360 ret |= process_tag(gcode_line, PrintStatistics::FilamentUsedGMask, filament_g);
1361 ret |= process_tag(gcode_line, PrintStatistics::TotalFilamentUsedGMask, { filament_total_g });
1362 ret |= process_tag(gcode_line, PrintStatistics::FilamentUsedCm3Mask, filament_cm3);
1363 ret |= process_tag(gcode_line, PrintStatistics::FilamentCostMask, filament_cost);
1364 ret |= process_tag(gcode_line, PrintStatistics::TotalFilamentCostMask, { filament_total_cost });
1365 return ret;
1366 };
1367
1368 // Process inline placeholders (print_time_*, used_filament_length and the print statistics known only after export)
1369 auto process_inline_placeholders = [&](std::string& gcode_line) {
1370 bool processed = false;
1371 // Every inline placeholder contains '@', so a line without one has nothing to replace.
1372 if (gcode_line.find('@') == std::string::npos)
1373 return processed;
1374
1375 auto replace_tag = [&gcode_line, &processed](ETags tag, const std::string& value) {
1376 const std::string& placeholder = reserved_tag(tag);
1377 size_t pos = gcode_line.find(placeholder);
1378 while (pos != std::string::npos) {
1379 gcode_line.replace(pos, placeholder.length(), value);
1380 processed = true;
1381 pos = gcode_line.find(placeholder, pos + value.length());
1382 }
1383 };
1384
1385 double print_time_total_sec = m_time_processor.machines[static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Normal)].time;
1386 if (print_time_total_sec < 0.0)
1387 print_time_total_sec = 0.0;
1388
1389 int total_seconds = static_cast<int>(print_time_total_sec);
1390 int print_time_day = total_seconds / 86400;
1391 int day_remainder_seconds = total_seconds % 86400;
1392 int print_time_hour = day_remainder_seconds / 3600;
1393 int print_time_minute = (day_remainder_seconds % 3600) / 60;
1394 int print_time_sec = day_remainder_seconds % 60;
1395
1396 double total_filament_mm = 0.0;
1397 for (const auto& mm : filament_mm) {
1398 total_filament_mm += mm;
1399 }
1400
1402 replace_tag(ETags::Print_Time_Day_Placeholder, std::to_string(print_time_day));
1403 replace_tag(ETags::Print_Time_Hour_Placeholder, std::to_string(print_time_hour));
1404 replace_tag(ETags::Print_Time_Minute_Placeholder, std::to_string(print_time_minute));
1405 replace_tag(ETags::Print_Time_Sec_Placeholder, std::to_string(print_time_sec));
1407 Slic3r::float_to_string_decimal_point(total_filament_mm / 1000.0, 2)); // Convert mm to m
1408 // Same values as the print statistics that filename_format gets (PrintStatistics::config(), filled in by
1409 // update_print_estimated_stats() in GCode.cpp), which runs only after this post-processing.
1413 short_time("N/A"));
1414 const double total_cost = filament_total_cost + m_print->config().time_cost.value * print_time_total_sec / 3600.0;
1418 Slic3r::float_to_string_decimal_point(m_print->print_statistics().total_wipe_tower_cost, 2));
1420 Slic3r::float_to_string_decimal_point(m_print->print_statistics().total_wipe_tower_filament, 2));
1421
1422 return processed;
1423 };
1424
1425 // check for temporary lines
1426 auto is_temporary_decoration = [](const std::string_view gcode_line) {
1427 // remove trailing '\n'
1428 assert(! gcode_line.empty());
1429 assert(gcode_line.back() == '\n');
1430
1431 // return true for decorations which are used in processing the gcode but that should not be exported into the final gcode
1432 // i.e.:
1433 // bool ret = gcode_line.substr(0, gcode_line.length() - 1) == ";" + Layer_Change_Tag;
1434 // ...
1435 // return ret;
1436 return false;
1437 };
1438
1439 // Iterators for the normal and silent cached time estimate entry recently processed, used by process_line_G1.
1440 auto g1_times_cache_it = Slic3r::reserve_vector<std::vector<TimeMachine::G1LinesCacheItem>::const_iterator>(m_time_processor.machines.size());
1441 for (const auto& machine : m_time_processor.machines)
1442 g1_times_cache_it.emplace_back(machine.g1_times_cache.begin());
1443
1444 // add lines M73 to exported gcode
1445 auto process_line_move = [
1446 // Lambdas, mostly for string formatting, all with an empty capture block.
1447 time_in_minutes, format_time_float, format_line_M73_main, format_line_M73_stop_int, format_line_M73_stop_float, time_in_last_minute,
1448 &self = std::as_const(m_time_processor),
1449 // Caches, to be modified
1450 &g1_times_cache_it, &last_exported_main, &last_exported_stop,
1451 // String output
1452 &export_line]
1453 (const size_t g1_lines_counter) {
1454 for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
1455 const TimeMachine& machine = self.machines[i];
1456 if (machine.enabled) {
1457 // export pair <percent, remaining time>
1458 // Skip all machine.g1_times_cache below g1_lines_counter.
1459 auto& it = g1_times_cache_it[i];
1460 while (it != machine.g1_times_cache.end() && it->id < g1_lines_counter)
1461 ++it;
1462 if (it != machine.g1_times_cache.end() && it->id == g1_lines_counter) {
1463 std::pair<int, int> to_export_main = { int(100.0f * it->elapsed_time / machine.time),
1464 time_in_minutes(machine.time - it->elapsed_time) };
1465
1466 if (last_exported_main[i] != to_export_main) {
1467 export_line.append_line(format_line_M73_main(machine.line_m73_main_mask.c_str(),
1468 to_export_main.first, to_export_main.second), true);
1469 last_exported_main[i] = to_export_main;
1470 }
1471 // export remaining time to next printer stop
1472 auto it_stop = std::upper_bound(machine.stop_times.begin(), machine.stop_times.end(), it->elapsed_time,
1473 [](float value, const TimeMachine::StopTime& t) { return value < t.elapsed_time; });
1474 if (it_stop != machine.stop_times.end()) {
1475 int to_export_stop = time_in_minutes(it_stop->elapsed_time - it->elapsed_time);
1476 if (last_exported_stop[i] != to_export_stop) {
1477 if (to_export_stop > 0) {
1478 if (last_exported_stop[i] != to_export_stop) {
1479 export_line.append_line(format_line_M73_stop_int(machine.line_m73_stop_mask.c_str(), to_export_stop), true);
1480 last_exported_stop[i] = to_export_stop;
1481 }
1482 }
1483 else {
1484 bool is_last = false;
1485 auto next_it = it + 1;
1486 is_last |= (next_it == machine.g1_times_cache.end());
1487
1488 if (next_it != machine.g1_times_cache.end()) {
1489 auto next_it_stop = std::upper_bound(machine.stop_times.begin(), machine.stop_times.end(), next_it->elapsed_time,
1490 [](float value, const TimeMachine::StopTime& t) { return value < t.elapsed_time; });
1491 is_last |= (next_it_stop != it_stop);
1492
1493 std::string time_float_str = format_time_float(time_in_last_minute(it_stop->elapsed_time - it->elapsed_time));
1494 std::string next_time_float_str = format_time_float(time_in_last_minute(it_stop->elapsed_time - next_it->elapsed_time));
1495 is_last |= (string_to_double_decimal_point(time_float_str) > 0. && string_to_double_decimal_point(next_time_float_str) == 0.);
1496 }
1497
1498 if (is_last) {
1499 if (std::distance(machine.stop_times.begin(), it_stop) == static_cast<ptrdiff_t>(machine.stop_times.size() - 1))
1500 export_line.append_line(format_line_M73_stop_int(machine.line_m73_stop_mask.c_str(), to_export_stop), true);
1501 else
1502 export_line.append_line(format_line_M73_stop_float(machine.line_m73_stop_mask.c_str(), time_in_last_minute(it_stop->elapsed_time - it->elapsed_time)), true);
1503
1504 last_exported_stop[i] = to_export_stop;
1505 }
1506 }
1507 }
1508 }
1509 }
1510 }
1511 }
1512 };
1513
1514 // Orca: track the current layer during the post-processing pass so that preheat M104s emitted
1515 // for tool changes on the first layer use the correct first-layer temperature. The member
1516 // m_layer_id is populated during the analysis pass and ends at the total layer count, so it
1517 // cannot be used here — it would always select the "other layers" temperature for multi-layer
1518 // prints.
1519 unsigned int current_layer_id = 0;
1520
1521 // add lines M104 to exported gcode
1522 auto process_line_T = [this, &export_line, &current_layer_id](const std::string& gcode_line, const size_t g1_lines_counter, const ExportLines::Backtrace& backtrace) {
1523 const std::string cmd = GCodeReader::GCodeLine::extract_cmd(gcode_line);
1524
1525 int tool_number = -1;
1526 if (!parse_number(std::string_view(cmd).substr(1), tool_number)){
1527 // invalid T<n> command, such as the "TIMELAPSE_TAKE_FRAME" gcode, just ignore
1528 return;
1529 }
1530 if (cmd.size() >= 2) {
1531 if (tool_number != -1) {
1532 if (tool_number < 0 || (int)m_filament_nozzle_temp.size() <= tool_number) {
1533 // found an invalid value, clamp it to a valid one
1534 tool_number = std::clamp<int>(0, m_filament_nozzle_temp.size() - 1, tool_number);
1535 // emit warning
1536 std::string warning = _u8L("The G-code post-processor encountered an invalid tool change, maybe from custom G-code:");
1537 warning += "\n> ";
1538 warning += gcode_line;
1539 warning += _u8L("Generated M104 lines may be incorrect.");
1540 BOOST_LOG_TRIVIAL(error) << warning;
1541 // Orca todo
1542 if (m_print != nullptr)
1543 m_print->active_step_add_warning(PrintStateBase::WarningLevel::CRITICAL, warning);
1544 }
1545 export_line.insert_lines(
1546 backtrace, cmd,
1547 // line inserter
1548 [tool_number, this, &current_layer_id](unsigned int id, const std::vector<float>& time_diffs) {
1549 // Orca: use the locally-tracked layer index (current_layer_id) rather than
1550 // the stale m_layer_id from the analysis pass. current_layer_id == 0 means
1551 // we haven't reached the first ;LAYER_CHANGE marker yet (e.g. tool change
1552 // inside start gcode); == 1 means we are inside the first printed layer.
1553 // Both cases should use the first-layer nozzle temperature.
1554 const int temperature = int(current_layer_id > 1 ? m_filament_nozzle_temp[tool_number] :
1556 // Orca: M104.1 for XL printers, I can't find the documentation for this so I copied the C++ comments from
1557 // Prusa-Firmware-Buddy here
1569 if (this->m_is_XL_printer) {
1570 std::string out = "M104.1 T" + std::to_string(tool_number);
1571 if (time_diffs.size() > 0)
1572 out += " P" + std::to_string(int(std::round(time_diffs[0])));
1573 if (time_diffs.size() > 1)
1574 out += " Q" + std::to_string(int(std::round(time_diffs[1])));
1575 out += " S" + std::to_string(temperature) + "\n";
1576 return out;
1577 } else {
1578 const int real_tool = tool_number < m_physical_extruder_map.size() ? m_physical_extruder_map[tool_number] : tool_number;
1579 std::string comment = "preheat T" + std::to_string(real_tool) +
1580 " time: " + std::to_string((int) std::round(time_diffs[0])) + "s";
1581 return GCodeWriter::set_temperature(temperature, this->m_flavor, false, real_tool, comment);
1582 }
1583 },
1584 // line replacer
1585 [this, tool_number](const std::string& line) {
1586 if (GCodeReader::GCodeLine::cmd_is(line, "M104")) {
1587 GCodeReader::GCodeLine gline;
1588 GCodeReader reader;
1589 reader.parse_line(line, [&gline](GCodeReader& reader, const GCodeReader::GCodeLine& l) { gline = l; });
1590
1591 float val;
1592 if (gline.has_value('T', val) && gline.raw().find("cooldown") != std::string::npos) {
1593 if (static_cast<int>(val) == (tool_number < m_physical_extruder_map.size() ? m_physical_extruder_map[tool_number] : tool_number))
1594 return std::string("; removed M104\n");
1595 }
1596 }
1597 return line;
1598 }
1599 );
1600 }
1601 }
1602 };
1603
1604 // Orca: freshly collect SKIPPABLE ranges each post-process pass. The ranges are stored on the
1605 // member (rather than a local) so the injection pass can consume them, hence the clear here to
1606 // avoid stale ranges on re-invocation.
1607 m_skippable_blocks.clear();
1608
1609 unsigned int line_id = 0;
1610 // Backtrace data for Tx gcode lines
1611 const ExportLines::Backtrace backtrace_T = { m_preheat_time, m_preheat_steps };
1612 // In case there are multiple sources of backtracing, keeps track of the longest backtrack time needed
1613 // to flush the backtrace cache accordingly
1614 float max_backtrace_time = 120.0f;
1615
1616 // First-pass usage-block builder. Reconstructs, from the emitted g-code, which filament/extruder
1617 // is active over each output-line span so the pre-heat injector can locate idle-hotend windows.
1618 // Gated behind m_enable_pre_heating: the byte-frozen fleet (X1/P1/A1/H2S, which never set the
1619 // flag) runs none of this. It is pure data construction — it only fills m_filament_blocks /
1620 // m_extruder_blocks / m_machine_*_gcode_*_line_id and never touches the exported g-code, so even
1621 // the enable_pre_heating fleet stays byte-identical (nothing reads the blocks until the injection
1622 // pass). The wipe tower emits the NOZZLE_CHANGE_* (ramming) and CP_TOOLCHANGE_WIPE markers this
1623 // builder keys off; the MACHINE_*_GCODE_* markers come from the machine g-code templates.
1624 m_filament_blocks.clear();
1625 m_extruder_blocks.clear();
1626 m_machine_start_gcode_end_line_id = (unsigned int) (-1);
1627 m_machine_end_gcode_start_line_id = (unsigned int) (-1);
1628 // the first use of an extruder emits no nozzle-change tag, so seed a dummy leading block
1630 m_extruder_blocks.push_back(ExtruderPreHeating::ExtruderUsageBlcok());
1631 // Resolve the concrete layer-aware grouping: get_nozzle_id/get_extruder_id are not on the base
1632 // interface. May be null on slicing paths that never populated it, in which case the builder
1633 // degrades to empty blocks (every dereference below is nil-guarded).
1634 auto layered_ngr = std::dynamic_pointer_cast<MultiNozzleUtils::LayeredNozzleGroupResult>(m_result.nozzle_group_result);
1635 ExtruderPreHeating::ExtruderUsageBlcok temp_construct_block; // constructed, then pushed after init
1636
1637 // Append a per-filament usage block at a filament change.
1638 auto handle_filament_change = [&](int filament_id, int cur_line_id, int nozzle_id) {
1639 // Skip filament changes emitted inside the machine start / end gcode. One forward pass assigns
1640 // the tag ids and tests them in the same loop, so inside the start gcode the end tag is unseen
1641 // and the id still holds the sentinel. That is why the first clause tests == and the second !=.
1642 if ((m_machine_start_gcode_end_line_id == (unsigned int) (-1) && (unsigned int) (cur_line_id) < m_machine_start_gcode_end_line_id) ||
1643 (m_machine_end_gcode_start_line_id != (unsigned int) (-1) && (unsigned int) (cur_line_id) > m_machine_end_gcode_start_line_id))
1644 return;
1645 if (!m_filament_blocks.empty())
1646 m_filament_blocks.back().upper_gcode_id = cur_line_id;
1647 if (nozzle_id == -1 && layered_ngr)
1648 nozzle_id = layered_ngr->get_nozzle_id(filament_id, current_layer_id);
1649 int extruder_id = 0;
1650 if (layered_ngr) {
1651 // Orca: nil-guard the optional nozzle lookup.
1652 if (auto nozzle_info = layered_ngr->get_nozzle_from_id(nozzle_id))
1653 extruder_id = nozzle_info->extruder_id;
1654 }
1655 m_filament_blocks.emplace_back(filament_id, extruder_id, nozzle_id, cur_line_id, (unsigned int) (-1));
1656 };
1657
1658 // Parse a "; NOZZLE_CHANGE_* OF<of> NF<nf> ON<on> NN<nn>" line. The get_nozzle_from_id optional
1659 // is nil-guarded here.
1660 auto handle_nozzle_change_line = [&](const std::string& line, int& old_filament, int& next_filament, int& extruder_id, int gcode_id, int& old_nozzle_id, int& new_nozzle_id) -> bool {
1661 std::regex re(R"(OF(\d+)\s+NF(\d+)\s+ON(\d+)\s+NN(\d+))");
1662 std::smatch match;
1663 if (!std::regex_search(line, match, re))
1664 return false;
1665 old_filament = std::stoi(match[1]);
1666 next_filament = std::stoi(match[2]);
1667 old_nozzle_id = std::stoi(match[3]);
1668 new_nozzle_id = std::stoi(match[4]);
1669 std::optional<MultiNozzleUtils::NozzleInfo> nozzle_info;
1670 if (layered_ngr)
1671 nozzle_info = layered_ngr->get_nozzle_from_id(new_nozzle_id);
1672 extruder_id = nozzle_info ? nozzle_info->extruder_id : -1;
1673 return true;
1674 };
1675
1676 // Parse a "; CP_TOOLCHANGE_WIPE CT<contact> [FL<first_layer>]" line.
1677 auto handle_toolchange_wipe_line = [](const std::string& line, bool& is_contact, bool& is_first_layer) -> bool {
1678 std::regex re(R"(CT(\d)(?:\s+FL(\d))?)");
1679 std::smatch match;
1680 if (!std::regex_search(line, match, re))
1681 return false;
1682 is_contact = std::stoi(match[1]) != 0;
1683 is_first_layer = match[2].matched ? std::stoi(match[2]) != 0 : false;
1684 return true;
1685 };
1686
1687 // Inspect one output line and update the usage-block state. Called only when m_enable_pre_heating;
1688 // never modifies gcode_line.
1689 auto build_usage_blocks = [&](const std::string& gcode_line, int line_id) {
1690 using GLine = GCodeReader::GCodeLine;
1691 // leading-whitespace count (GCodeReader::skip_whitespaces is private; is_whitespace == space|tab)
1692 size_t skips = 0;
1693 while (skips < gcode_line.size() && (gcode_line[skips] == ' ' || gcode_line[skips] == '\t'))
1694 ++skips;
1695
1696 // whole-line machine start / end gcode markers
1697 if (gcode_line.size() > 1 && gcode_line.front() == ';') {
1698 std::string_view tag(gcode_line);
1699 while (!tag.empty() && (tag.back() == '\n' || tag.back() == '\r'))
1700 tag.remove_suffix(1);
1701 tag.remove_prefix(1); // strip leading ';'
1702 if (tag == Machine_Start_GCode_End_Tag) { m_machine_start_gcode_end_line_id = line_id; return; }
1703 if (tag == Machine_End_GCode_Start_Tag) { m_machine_end_gcode_start_line_id = line_id; return; }
1704 }
1705
1706 // filament-change commands: T<fid>, ;VT<fid>, M1020 S<fid>, each optionally " H<nozzle_id>"
1707 if (GLine::cmd_starts_with(gcode_line, "T")) {
1708 std::istringstream str(gcode_line.substr(skips + 1)); // skip whitespace and 'T'
1709 int fid;
1710 str >> fid;
1711 if (!str.fail() && 0 <= fid && fid < 255) {
1712 int nozzle_id = -1; char param;
1713 while (str >> param) { if (param == 'H') { if (!(str >> nozzle_id)) BOOST_LOG_TRIVIAL(warning) << "Invalid nozzle id format in T command: " << gcode_line; break; } }
1714 handle_filament_change(fid, line_id, nozzle_id);
1715 }
1716 return;
1717 }
1718 if (GLine::cmd_starts_with(gcode_line, ";VT")) {
1719 std::istringstream str(gcode_line.substr(skips + 3)); // skip whitespace and ";VT"
1720 int fid;
1721 str >> fid;
1722 if (!str.fail() && 0 <= fid && fid < 255) {
1723 int nozzle_id = -1; char param;
1724 while (str >> param) { if (param == 'H') { if (!(str >> nozzle_id)) BOOST_LOG_TRIVIAL(warning) << "Invalid nozzle id format in VT command: " << gcode_line; break; } }
1725 handle_filament_change(fid, line_id, nozzle_id);
1726 }
1727 return;
1728 }
1729 if (GLine::cmd_starts_with(gcode_line, "M1020")) {
1730 size_t s_pos = gcode_line.find('S');
1731 if (s_pos != std::string::npos) {
1732 std::istringstream str(gcode_line.substr(s_pos + 1));
1733 int fid;
1734 str >> fid;
1735 if (!str.fail() && 0 <= fid && fid < 255) {
1736 int nozzle_id = -1; char param;
1737 while (str >> param) { if (param == 'H') { if (!(str >> nozzle_id)) BOOST_LOG_TRIVIAL(warning) << "Invalid nozzle id format in M1020 command: " << gcode_line; break; } }
1738 handle_filament_change(fid, line_id, nozzle_id);
1739 }
1740 }
1741 return;
1742 }
1743
1744 // extruder usage blocks are delimited by the NOZZLE_CHANGE_START/END markers
1745 if (GLine::cmd_starts_with(gcode_line, (std::string(";") + Nozzle_Change_Start_Tag).c_str())) {
1746 int prev_filament{-1}, next_filament{-1}, extruder_id{-1}, prev_nozzle_id{-1}, next_nozzle_id{-1};
1747 handle_nozzle_change_line(gcode_line, prev_filament, next_filament, extruder_id, line_id, prev_nozzle_id, next_nozzle_id);
1748 if (!m_extruder_blocks.empty())
1749 m_extruder_blocks.back().initialize_step_2(line_id);
1750 return;
1751 }
1752 if (GLine::cmd_starts_with(gcode_line, (std::string(";") + Nozzle_Change_End_Tag).c_str())) {
1753 int prev_filament{-1}, next_filament{-1}, extruder_id{-1}, prev_nozzle_id{-1}, next_nozzle_id{-1};
1754 handle_nozzle_change_line(gcode_line, prev_filament, next_filament, extruder_id, line_id, prev_nozzle_id, next_nozzle_id);
1755 if (!m_extruder_blocks.empty())
1756 m_extruder_blocks.back().initialize_step_3(line_id, prev_filament, line_id, prev_nozzle_id);
1757 temp_construct_block.initialize_step_1(extruder_id, line_id, next_filament, next_nozzle_id);
1758 m_extruder_blocks.emplace_back(temp_construct_block);
1759 temp_construct_block.reset();
1760 return;
1761 }
1762 // CP_TOOLCHANGE_WIPE records whether the upcoming tower wipe contacts the model / is on the
1763 // first layer, which later suppresses pre-cooling before the tower.
1764 if (GLine::cmd_starts_with(gcode_line, (std::string(";") + Toolchange_Wipe_Tag).c_str())) {
1765 bool is_contact = false, is_first_layer = false;
1766 handle_toolchange_wipe_line(gcode_line, is_contact, is_first_layer);
1767 if (!m_extruder_blocks.empty())
1768 m_extruder_blocks.back().ignore_cooling_before_tower = is_contact || is_first_layer;
1769 return;
1770 }
1771 };
1772
1773 {
1774 // Read the input stream 64kB at a time, extract lines and process them.
1775 std::vector<char> buffer(65536 * 10, 0);
1776 // Line buffer.
1777 assert(gcode_line.empty());
1778 for (;;) {
1779 size_t cnt_read = ::fread(buffer.data(), 1, buffer.size(), in.f);
1780 if (::ferror(in.f))
1781 throw Slic3r::RuntimeError(_u8L("G-code processor post-process export failed.\nError while reading from file.\n"));
1782 bool eof = cnt_read == 0;
1783 auto it = buffer.begin();
1784 auto it_bufend = buffer.begin() + cnt_read;
1785 while (it != it_bufend || (eof && ! gcode_line.empty())) {
1786 // Find end of line.
1787 bool eol = false;
1788 auto it_end = it;
1789 for (; it_end != it_bufend && ! (eol = *it_end == '\r' || *it_end == '\n'); ++ it_end) ;
1790 // End of line is indicated also if end of file was reached.
1791 eol |= eof && it_end == it_bufend;
1792 gcode_line.insert(gcode_line.end(), it, it_end);
1793
1794 it = it_end;
1795 // append EOL.
1796 if (it != it_bufend && *it == '\r') {
1797 gcode_line += *it++;
1798 }
1799 if (it != it_bufend && *it == '\n') {
1800 gcode_line += *it++;
1801 }
1802
1803 if (eol) {
1804 ++line_id;
1805 const unsigned int internal_g1_lines_counter = export_line.update(gcode_line, line_id, g1_lines_counter);
1806 // Orca: track the current layer for preheat temperature selection.
1807 // The line is ";" + reserved_tag(Layer_Change) + EOL; match it independent of
1808 // BBL vs. compatible flavor (which differ in the tag text).
1809 if (gcode_line.size() > 1 && gcode_line.front() == ';') {
1810 std::string_view tag_line(gcode_line);
1811 // strip trailing CR/LF
1812 while (!tag_line.empty() && (tag_line.back() == '\n' || tag_line.back() == '\r'))
1813 tag_line.remove_suffix(1);
1814 // strip leading ';'
1815 tag_line.remove_prefix(1);
1816 if (tag_line == reserved_tag(ETags::Layer_Change))
1817 ++current_layer_id;
1818 // Collect [start,end] output-line-id ranges of each SKIPPABLE region for the
1819 // pre-heat injector. The `!empty()` guard on END avoids dereferencing .back()
1820 // on an empty vector. The shipping time_lapse_gcode template emits SKIPPABLE_*
1821 // fleet-wide, so this records ~100 ranges per timelapse-on slice; output stays
1822 // byte-identical because it only records line-ids (comment lines pass through
1823 // unmodified) and nothing reads the ranges until the injection pass.
1824 else if (tag_line == Skippable_Start_Tag)
1825 m_skippable_blocks.emplace_back(line_id, 0);
1826 else if (tag_line == Skippable_End_Tag && !m_skippable_blocks.empty())
1827 m_skippable_blocks.back().second = line_id;
1828 }
1829 // Build the first-pass usage blocks off the raw line (before any placeholder
1830 // replacement/clear below). Gated on m_enable_pre_heating so the byte-frozen fleet
1831 // executes nothing; pure data construction, so the output is untouched regardless.
1833 build_usage_blocks(gcode_line, line_id);
1834 // replace placeholder lines
1835 bool processed = process_placeholders(gcode_line);
1836 if (processed)
1837 gcode_line.clear();
1838 if (!processed)
1839 processed = process_used_filament(gcode_line);
1840 if (!gcode_line.empty())
1841 process_inline_placeholders(gcode_line);
1842 if (!processed && !is_temporary_decoration(gcode_line)) {
1843 if (GCodeReader::GCodeLine::cmd_is(gcode_line, "G0") || GCodeReader::GCodeLine::cmd_is(gcode_line, "G1")) {
1844 export_line.append_line(gcode_line);
1845 // add lines M73 where needed
1846 process_line_move(g1_lines_counter++);
1847 gcode_line.clear();
1848 }
1849 else if (GCodeReader::GCodeLine::cmd_is(gcode_line, "G2") || GCodeReader::GCodeLine::cmd_is(gcode_line, "G3")) {
1850 export_line.append_line(gcode_line);
1851 // add lines M73 where needed
1852 process_line_move(g1_lines_counter + internal_g1_lines_counter);
1853 g1_lines_counter += (1 + internal_g1_lines_counter);
1854 gcode_line.clear();
1855 }
1856 else if (GCodeReader::GCodeLine::cmd_is(gcode_line, "G28")) {
1857 ++g1_lines_counter;
1858 }
1859 else if (m_result.backtrace_enabled && GCodeReader::GCodeLine::cmd_starts_with(gcode_line, "T")) {
1860 // add lines M104 where needed
1861 process_line_T(gcode_line, g1_lines_counter, backtrace_T);
1862 max_backtrace_time = std::max(max_backtrace_time, backtrace_T.time);
1863 }
1864 }
1865
1866 if (!gcode_line.empty())
1867 export_line.append_line(gcode_line);
1868 export_line.write(1.1f * max_backtrace_time);
1869 gcode_line.clear();
1870 }
1871 }
1872 if (eof)
1873 break;
1874 }
1875 }
1876
1877 // Close out the usage blocks after the stream. The trailing filament block runs to the end-gcode
1878 // start; the seeded first extruder block gets its start filled from the first filament, and the
1879 // open last extruder block is completed with the trailing filament/nozzle. Gated + pure data —
1880 // no effect on the exported g-code.
1882 if (!m_filament_blocks.empty())
1884
1885 if (!m_extruder_blocks.empty()) {
1886 int first_filament = 0;
1887 int last_filament = 0;
1888 if (!m_filament_blocks.empty()) {
1889 first_filament = m_filament_blocks.front().filament_id;
1890 last_filament = m_filament_blocks.back().filament_id;
1891 }
1892 {
1893 int extruder_id = -1;
1894 std::optional<MultiNozzleUtils::NozzleInfo> nozzle_info;
1895 if (layered_ngr)
1896 nozzle_info = layered_ngr->get_first_nozzle_for_filament(first_filament);
1897 if (nozzle_info)
1898 extruder_id = nozzle_info->extruder_id;
1899 int start_nozzle_id = nozzle_info ? nozzle_info->group_id : -1;
1900 m_extruder_blocks.front().initialize_step_1(extruder_id, m_machine_start_gcode_end_line_id, first_filament, start_nozzle_id);
1901 }
1902 m_extruder_blocks.back().initialize_step_2(m_machine_end_gcode_start_line_id);
1903 int last_nozzle_id = -1;
1904 if (!m_filament_blocks.empty())
1905 last_nozzle_id = m_filament_blocks.back().nozzle_id;
1906 m_extruder_blocks.back().initialize_step_3(m_machine_end_gcode_start_line_id, last_filament, m_machine_end_gcode_start_line_id, last_nozzle_id);
1907 }
1908 }
1909
1910 export_line.flush();
1911
1912 out.close();
1913 in.close();
1914
1915 const std::string result_filename = m_result.filename;
1916 export_line.synchronize_moves(m_result);
1917
1918 // Rebase the first-pass usage/skippable blocks + the machine start/end gcode line ids from the
1919 // pre-M73 input-line-id space into the final output-line-id space, so they share one coordinate
1920 // system with the moves (whose gcode_ids synchronize_moves() just rebased) and with the
1921 // second-pass line_id. This is the block-side counterpart to synchronize_moves, which does the
1922 // same rebasing for the moves. Gated on m_enable_pre_heating so the byte-frozen fleet skips it
1923 // entirely; on the flag-true fleet it writes only the (inert) block members, so the emitted
1924 // g-code is unaffected either way.
1926 auto remap = [&export_line](unsigned int& id) { id = export_line.remap_gcode_id(id); };
1927 for (auto& b : m_filament_blocks) {
1928 remap(b.lower_gcode_id);
1929 remap(b.upper_gcode_id);
1930 }
1931 for (auto& b : m_extruder_blocks) {
1932 remap(b.start_id);
1933 remap(b.end_id);
1934 remap(b.post_extrusion_start_id);
1935 remap(b.post_extrusion_end_id);
1936 }
1937 for (auto& b : m_skippable_blocks) {
1938 remap(b.first);
1939 remap(b.second);
1940 }
1943 }
1944
1945 if (rename_file(out_path, result_filename))
1946 // TRN %1% is the temporary file path, %2% the output file path.
1947 throw Slic3r::RuntimeError(Slic3r::format(_u8L("Failed to rename the output G-code file from %1% to %2%.\nIs %1% locked?"),
1948 out_path, result_filename) + '\n');
1949}
@ ByTime
Definition GCodeProcessor.cpp:910
@ BySize
Definition GCodeProcessor.cpp:910
Print * m_print
Definition GCodeProcessor.hpp:1379
static const std::string Nozzle_Change_Start_Tag
Definition GCodeProcessor.hpp:598
static const std::string Toolchange_Wipe_Tag
Definition GCodeProcessor.hpp:600
ETags
Definition GCodeProcessor.hpp:603
@ First_Line_M73_Placeholder
Definition GCodeProcessor.hpp:613
@ Normal_Print_Time_Placeholder
Definition GCodeProcessor.hpp:628
@ Total_Weight_Placeholder
Definition GCodeProcessor.hpp:630
@ Estimated_Printing_Time_Placeholder
Definition GCodeProcessor.hpp:615
@ Print_Time_Sec_Placeholder
Definition GCodeProcessor.hpp:626
@ Total_Layer_Number_Placeholder
Definition GCodeProcessor.hpp:616
@ Print_Time_Hour_Placeholder
Definition GCodeProcessor.hpp:624
@ Total_Wipe_Tower_Cost_Placeholder
Definition GCodeProcessor.hpp:632
@ Used_Filament_Length_Placeholder
Definition GCodeProcessor.hpp:627
@ Print_Time_Total_Sec_Placeholder
Definition GCodeProcessor.hpp:622
@ Silent_Print_Time_Placeholder
Definition GCodeProcessor.hpp:629
@ Total_Cost_Placeholder
Definition GCodeProcessor.hpp:631
@ Total_Wipe_Tower_Filament_Placeholder
Definition GCodeProcessor.hpp:633
@ Last_Line_M73_Placeholder
Definition GCodeProcessor.hpp:614
@ Print_Time_Minute_Placeholder
Definition GCodeProcessor.hpp:625
@ Print_Time_Day_Placeholder
Definition GCodeProcessor.hpp:623
static const std::string Machine_Start_GCode_End_Tag
Definition GCodeProcessor.hpp:596
static const std::string Nozzle_Change_End_Tag
Definition GCodeProcessor.hpp:599
friend class ExportLines
Definition GCodeProcessor.hpp:751
std::string get_time_dhm(PrintEstimatedStatistics::ETimeMode mode) const
Definition GCodeProcessor.cpp:4021
bool is_stealth_time_estimator_enabled() const
Definition GCodeProcessor.hpp:1428
static bool cmd_starts_with(const std::string &gcode_line, const char *cmd_test)
Definition GCodeReader.hpp:92
static std::string extract_cmd(const std::string &gcode_line)
Definition GCodeReader.hpp:96
bool cmd_is(const char *cmd_test) const
Definition GCodeReader.hpp:58
static std::string set_temperature(unsigned int temperature, GCodeFlavor flavor, bool wait=false, int tool=-1, std::string comment=std::string())
Definition GCodeWriter.cpp:317
@ CRITICAL
Definition PrintBase.hpp:63
std::string float_to_string_decimal_point(double value, int precision)
Definition LocalesUtils.cpp:108
std::error_code rename_file(const std::string &from, const std::string &to)
Definition utils.cpp:745
std::string format(const char *fmt, TArgs &&... args)
Definition format.hpp:45
zaa_minimize_perimeter_height filament_cost((ConfigOptionStrings, default_filament_colour))((ConfigOptionInts
#define _u8L(s)
Definition I18N.hpp:11
Definition GCodeProcessor.hpp:824
static const std::string FilamentUsedCm3Mask
Definition Print.hpp:995
static const std::string FilamentUsedMmMask
Definition Print.hpp:997
static const std::string FilamentUsedGMask
Definition Print.hpp:990
static const std::string FilamentCostMask
Definition Print.hpp:999
static const std::string TotalFilamentCostMask
Definition Print.hpp:1001
static const std::string TotalFilamentUsedGMask
Definition Print.hpp:992

References _u8L, Slic3r::ExportLines::append_line(), Slic3r::ExportLines::BySize, Slic3r::ExportLines::ByTime, Slic3r::FilePtr::close(), Slic3r::GCodeReader::GCodeLine::cmd_is(), Slic3r::GCodeReader::GCodeLine::cmd_starts_with(), Slic3r::PrintEstimatedStatistics::Count, Slic3r::PrintStateBase::CRITICAL, Slic3r::GCodeProcessor::TimeMachine::enabled, Estimated_Printing_Time_Placeholder, ExportLines, Slic3r::GCodeReader::GCodeLine::extract_cmd(), Slic3r::FilePtr::f, Slic3r::filament_cost(), Slic3r::PrintStatistics::FilamentCostMask, Slic3r::PrintStatistics::FilamentUsedCm3Mask, Slic3r::PrintStatistics::FilamentUsedGMask, Slic3r::PrintStatistics::FilamentUsedMmMask, First_Line_M73_Placeholder, Slic3r::float_to_string_decimal_point(), Slic3r::ExportLines::flush(), Slic3r::format(), Slic3r::GCodeProcessor::TimeMachine::g1_times_cache, get_time_dhm(), Slic3r::get_time_dhms(), Slic3r::GCodeReader::GCodeLine::has_value(), Slic3r::ExtruderPreHeating::ExtruderUsageBlcok::initialize_step_1(), Slic3r::ExportLines::insert_lines(), is_stealth_time_estimator_enabled(), Last_Line_M73_Placeholder, Layer_Change, Slic3r::GCodeProcessor::TimeMachine::line_m73_main_mask, Slic3r::GCodeProcessor::TimeMachine::line_m73_stop_mask, m_disable_m73, m_enable_pre_heating, m_extruder_blocks, m_filament_blocks, m_filament_nozzle_temp, m_filament_nozzle_temp_first_layer, m_flavor, m_is_XL_printer, m_layer_id, m_line_id, m_machine_end_gcode_start_line_id, m_machine_start_gcode_end_line_id, m_physical_extruder_map, M_PI, m_preheat_steps, m_preheat_time, m_print, m_result, m_skippable_blocks, m_time_processor, Machine_End_GCode_Start_Tag, Machine_Start_GCode_End_Tag, Slic3r::PrintEstimatedStatistics::Normal, Normal_Print_Time_Placeholder, Nozzle_Change_End_Tag, Nozzle_Change_Start_Tag, Slic3r::GCodeReader::parse_line(), Slic3r::parse_number(), Slic3r::GCodeProcessor::TimeMachine::prepare_time, Print_Time_Day_Placeholder, Print_Time_Hour_Placeholder, Print_Time_Minute_Placeholder, Print_Time_Sec_Placeholder, Print_Time_Total_Sec_Placeholder, Slic3r::GCodeReader::GCodeLine::raw(), Slic3r::ExportLines::remap_gcode_id(), Slic3r::rename_file(), Slic3r::ExportLines::reserve(), Slic3r::reserve_vector(), reserved_tag(), Slic3r::ExtruderPreHeating::ExtruderUsageBlcok::reset(), s_IsBBLPrinter, Slic3r::GCodeWriter::set_temperature(), Slic3r::short_time(), Silent_Print_Time_Placeholder, Skippable_End_Tag, Skippable_Start_Tag, Slic3r::sqr(), Slic3r::PrintEstimatedStatistics::Stealth, Slic3r::GCodeProcessor::TimeMachine::stop_times, Slic3r::string_to_double_decimal_point(), Slic3r::ExportLines::synchronize_moves(), Slic3r::ExportLines::Backtrace::time, Slic3r::GCodeProcessor::TimeMachine::time, Toolchange_Wipe_Tag, Total_Cost_Placeholder, Total_Layer_Number_Placeholder, Total_Weight_Placeholder, Total_Wipe_Tower_Cost_Placeholder, Total_Wipe_Tower_Filament_Placeholder, Slic3r::PrintStatistics::TotalFilamentCostMask, Slic3r::PrintStatistics::TotalFilamentUsedGMask, Slic3r::ExportLines::update(), Used_Filament_Length_Placeholder, and Slic3r::ExportLines::write().

Referenced by finalize().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ run_second_pass_injection()

void Slic3r::GCodeProcessor::run_second_pass_injection ( )
private
1961{
1962 // The ordered map of M632/M400/M104/M633 lines to splice into the finished g-code, keyed on the
1963 // final output line id. Populated by the PreCoolingInjector below. If the injector produces
1964 // nothing (no idle windows / no usage blocks), the map stays empty and the rewrite below is a
1965 // byte-for-byte identity pass.
1966 TimeProcessor::InsertedLinesMap inserted_operation_lines;
1967
1968 // The enable_pre_heating orchestration block. Build the injector from the reconciled first-pass
1969 // usage/skippable blocks (now in the final output-line-id space, sharing one coordinate with the
1970 // moves' synchronized gcode_ids) and the per-move time substrate, then have it populate
1971 // inserted_operation_lines. Runs under the same m_enable_pre_heating gate finalize() already
1972 // applied, so the byte-frozen fleet (X1/P1/A1/H2S) never reaches here.
1973 {
1974 // Pick the active time mode (Normal/Stealth) whose move.time[] the injector reads.
1975 int valid_machine_id = 0;
1976 for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
1977 if (m_time_processor.machines[i].enabled) {
1978 valid_machine_id = (int) i;
1979 break;
1980 }
1981 }
1982 // Reach the concrete layer-aware grouping (get_nozzle_from_id / is_support_dynamic_nozzle_map
1983 // are not on the base interface). Orca: nil-guard it — on a slicing path that never populated
1984 // the grouping, skip injection → empty map → identity rewrite. The shared_ptr local keeps the
1985 // object alive for the injector's const ref.
1986 auto layered_ngr = std::dynamic_pointer_cast<MultiNozzleUtils::LayeredNozzleGroupResult>(m_result.nozzle_group_result);
1987 if (layered_ngr) {
1988 constexpr float inject_time_threshold = 0.f; // threshold hardcoded to 0
1989 // Orca: nozzle temps are stored as float (ExtruderTemps) but the injector signature takes
1990 // std::vector<int>, so convert to int locals that outlive the injector (they are
1991 // int-valued floats — see apply_config).
1992 std::vector<int> filament_nozzle_temps(m_filament_nozzle_temp.begin(), m_filament_nozzle_temp.end());
1993 std::vector<int> filament_nozzle_temps_initial(m_filament_nozzle_temp_first_layer.begin(), m_filament_nozzle_temp_first_layer.end());
1994 // filament_max_temperature_drop_when_ec is inert (default {0}, never read by the injector);
1995 // pass the same inert default (the config is registered but unwired).
1996 const std::vector<double> filament_max_temperature_drop_when_ec{ 0.f };
1997
1998 // Orca: MoveVertex.time[mode] stores the per-move DURATION (calculate_time: `= block_time`),
1999 // but the injector's algorithm reads move.time[] as CUMULATIVE print time (idle-window gap =
2000 // upper.time - prev(lower).time; heating_start back-solve = upper.time - delta/rate). Build a
2001 // cumulative view of the active mode IN PLACE (prefix-sum in gcode-id/move order — moves are
2002 // sorted by gcode_id), run the injector, then RESTORE the per-move durations so every
2003 // downstream consumer (and the byte output) is unperturbed. Only the single active-mode
2004 // column is touched.
2005 std::vector<float> saved_time;
2006 saved_time.reserve(m_result.moves.size());
2007 {
2008 float acc = 0.f;
2009 for (auto& mv : m_result.moves) {
2010 saved_time.push_back(mv.time[valid_machine_id]);
2011 acc += mv.time[valid_machine_id];
2012 mv.time[valid_machine_id] = acc;
2013 }
2014 }
2015
2016 PreCoolingInjector injector(
2017 m_result.moves,
2019 *layered_ngr,
2020 filament_nozzle_temps,
2021 filament_nozzle_temps_initial,
2023 valid_machine_id,
2024 inject_time_threshold,
2033 filament_max_temperature_drop_when_ec,
2036 m_result.extruder_types,
2038 injector.build_extruder_free_blocks(m_filament_blocks, m_extruder_blocks);
2039 injector.process_pre_cooling_and_heating(inserted_operation_lines);
2040
2041 // Restore the per-move durations (leave the moves exactly as run_post_process produced them).
2042 for (size_t i = 0; i < m_result.moves.size(); ++i)
2043 m_result.moves[i].time[valid_machine_id] = saved_time[i];
2044 }
2045 }
2046
2047 FilePtr in{ boost::nowide::fopen(m_result.filename.c_str(), "rb") };
2048 if (in.f == nullptr)
2049 throw Slic3r::RuntimeError(_u8L("G-code processor pre-heat injection pass failed.\nCannot open file for reading.\n"));
2050
2051 const std::string out_path = m_result.filename + ".preheat";
2052 FilePtr out{ boost::nowide::fopen(out_path.c_str(), "wb") };
2053 if (out.f == nullptr)
2054 throw Slic3r::RuntimeError(_u8L("G-code processor pre-heat injection pass failed.\nCannot open file for writing.\n"));
2055
2056 // The rewrite may shift byte positions (once the injector inserts lines), so rebuild lines_ends from scratch.
2057 // With an empty map the scanned '\n' offsets reproduce the current lines_ends exactly.
2058 m_result.lines_ends.clear();
2059 GCodeFileWriter writer(out, out_path, m_result.lines_ends, "GCode processor pre-heat injection pass failed.\nIs the disk full?\n");
2060
2061 // Orca: read/split lines with EOL-preserving semantics (keep the original \r and \n bytes, and
2062 // synthesize no trailing newline). This is required for the empty-map identity: normalizing every
2063 // line ending to "\n" would not be byte-identical if the finished file used \r\n or lacked a
2064 // final newline.
2065 std::string gcode_line;
2066 unsigned int line_id = 0;
2067 auto op_it = inserted_operation_lines.begin();
2068 std::vector<char> buffer(65536 * 10, 0);
2069 for (;;) {
2070 size_t cnt_read = ::fread(buffer.data(), 1, buffer.size(), in.f);
2071 if (::ferror(in.f))
2072 throw Slic3r::RuntimeError(_u8L("G-code processor pre-heat injection pass failed.\nError while reading from file.\n"));
2073 bool eof = cnt_read == 0;
2074 auto it = buffer.begin();
2075 auto it_bufend = buffer.begin() + cnt_read;
2076 while (it != it_bufend || (eof && !gcode_line.empty())) {
2077 bool eol = false;
2078 auto it_end = it;
2079 for (; it_end != it_bufend && !(eol = *it_end == '\r' || *it_end == '\n'); ++it_end);
2080 eol |= eof && it_end == it_bufend;
2081 gcode_line.insert(gcode_line.end(), it, it_end);
2082 it = it_end;
2083 if (it != it_bufend && *it == '\r')
2084 gcode_line += *it++;
2085 if (it != it_bufend && *it == '\n')
2086 gcode_line += *it++;
2087 if (eol) {
2088 ++line_id;
2089 // Splice any injector lines registered at this output line id. They are appended to the
2090 // end of the current line's text (which already carries its EOL), so they land AFTER
2091 // this line. PlaceholderReplace / TimePredict / ExtruderChangePredict are handled in the
2092 // first pass and skipped here.
2093 if (op_it != inserted_operation_lines.end() && line_id == op_it->first) {
2094 for (const auto& elem : op_it->second) {
2095 switch (elem.second) {
2099 gcode_line += elem.first;
2100 break;
2101 default:
2102 break;
2103 }
2104 }
2105 ++op_it;
2106 }
2107 writer.append(gcode_line);
2108 gcode_line.clear();
2109 }
2110 }
2111 if (eof)
2112 break;
2113 }
2114 writer.flush();
2115
2116 out.close();
2117 in.close();
2118
2119 // Re-shift the moves by the inserted-line counts (no-op with an empty map).
2120 handle_offsets_of_second_process(inserted_operation_lines);
2121
2122 if (rename_file(out_path, m_result.filename))
2123 // TRN %1% is the temporary file path, %2% the output file path.
2124 throw Slic3r::RuntimeError(Slic3r::format(_u8L("Failed to rename the output G-code file from %1% to %2%.\nIs %1% locked?"),
2125 out_path, m_result.filename) + '\n');
2126}
Definition GCodeProcessor.hpp:962
void handle_offsets_of_second_process(const TimeProcessor::InsertedLinesMap &inserted_operation_lines)
Definition GCodeProcessor.cpp:2130
@ FilamentChangePredict
Definition GCodeProcessor.hpp:917
@ PreCooling
Definition GCodeProcessor.hpp:919
@ PreHeating
Definition GCodeProcessor.hpp:920
std::map< unsigned int, std::vector< std::pair< std::string, InsertLineType > > > InsertedLinesMap
Definition GCodeProcessor.hpp:924

References _u8L, Slic3r::GCodeProcessor::PreCoolingInjector::build_extruder_free_blocks(), Slic3r::FilePtr::close(), Slic3r::PrintEstimatedStatistics::Count, Slic3r::FilePtr::f, Slic3r::GCodeProcessor::TimeProcessor::FilamentChangePredict, Slic3r::format(), handle_offsets_of_second_process(), m_extruder_blocks, m_extruder_max_nozzle_count, m_filament_blocks, m_filament_nozzle_temp, m_filament_nozzle_temp_first_layer, m_filament_pre_cooling_temp, m_filament_preheat_temperature_delta, m_filament_types, m_handle_hotend_as_extruder, m_has_filament_switcher, m_hotend_cooling_rate, m_hotend_heating_rate, m_machine_end_gcode_start_line_id, m_machine_start_gcode_end_line_id, m_nozzle_diameter, m_physical_extruder_map, m_result, m_skippable_blocks, m_time_processor, Slic3r::GCodeProcessor::TimeProcessor::PreCooling, Slic3r::GCodeProcessor::TimeProcessor::PreHeating, Slic3r::GCodeProcessor::PreCoolingInjector::process_pre_cooling_and_heating(), and Slic3r::rename_file().

Referenced by finalize().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_acceleration()

void Slic3r::GCodeProcessor::set_acceleration ( PrintEstimatedStatistics::ETimeMode mode,
float value )
private
7966{
7967 size_t id = static_cast<size_t>(mode);
7968 if (id < m_time_processor.machines.size()) {
7969 m_time_processor.machines[id].acceleration = (m_time_processor.machines[id].max_acceleration == 0.0f) ? value :
7970 // Clamp the acceleration with the maximum.
7971 std::min(value, m_time_processor.machines[id].max_acceleration);
7972 }
7973}

References Slic3r::GCodeProcessorResult::id, and m_time_processor.

Referenced by process_M204().

Here is the caller graph for this function:

◆ set_extrusion_role()

void Slic3r::GCodeProcessor::set_extrusion_role ( ExtrusionRole role)
private
7667{
7668 m_used_filaments.process_role_cache(this);
7669 m_extrusion_role = role;
7670}

References m_extrusion_role, and m_used_filaments.

Referenced by process_craftware_tags(), process_cura_tags(), process_ideamaker_tags(), process_kissslicer_tags(), process_simplify3d_tags(), and process_tags().

Here is the caller graph for this function:

◆ set_mass_locator()

void Slic3r::GCodeProcessor::set_mass_locator ( MassLocator locator,
std::vector< GCodeProcessorResult::ObjectMass > objects )
inline
1415 {
1416 m_mass_locator = std::move(locator);
1417 m_result.support_masses.assign(objects.size(), {});
1418 m_result.object_masses = std::move(objects);
1419 }

References m_mass_locator, and m_result.

Referenced by Slic3r::set_mass_locator().

Here is the caller graph for this function:

◆ set_print()

void Slic3r::GCodeProcessor::set_print ( Print * print)
inline
1412{ m_print = print; }

References m_print.

◆ set_retract_acceleration()

void Slic3r::GCodeProcessor::set_retract_acceleration ( PrintEstimatedStatistics::ETimeMode mode,
float value )
private
7950{
7951 size_t id = static_cast<size_t>(mode);
7952 if (id < m_time_processor.machines.size()) {
7953 m_time_processor.machines[id].retract_acceleration = (m_time_processor.machines[id].max_retract_acceleration == 0.0f) ? value :
7954 // Clamp the acceleration with the maximum.
7955 std::min(value, m_time_processor.machines[id].max_retract_acceleration);
7956 }
7957}

References Slic3r::GCodeProcessorResult::id, and m_time_processor.

Referenced by process_M204().

Here is the caller graph for this function:

◆ set_skippable_type()

void Slic3r::GCodeProcessor::set_skippable_type ( const std::string_view type)
private
7674{
7675 if (!m_skippable) {
7677 return;
7678 }
7679 auto iter = skip_type_map.find(type);
7680 if (iter != skip_type_map.end()) {
7681 m_skippable_type = iter->second;
7682 } else {
7684 }
7685}
@ stOther
Definition GCodeProcessor.hpp:76
const std::unordered_map< std::string_view, SkipType > skip_type_map
Definition GCodeProcessor.hpp:80

References m_skippable, m_skippable_type, Slic3r::skip_type_map, Slic3r::stNone, and Slic3r::stOther.

Referenced by process_tags().

Here is the caller graph for this function:

◆ set_travel_acceleration()

void Slic3r::GCodeProcessor::set_travel_acceleration ( PrintEstimatedStatistics::ETimeMode mode,
float value )
private
7982{
7983 size_t id = static_cast<size_t>(mode);
7984 if (id < m_time_processor.machines.size()) {
7985 m_time_processor.machines[id].travel_acceleration = (m_time_processor.machines[id].max_travel_acceleration == 0.0f) ? value :
7986 // Clamp the acceleration with the maximum.
7987 std::min(value, m_time_processor.machines[id].max_travel_acceleration);
7988 }
7989}

References Slic3r::GCodeProcessorResult::id, and m_time_processor.

Referenced by process_M204().

Here is the caller graph for this function:

◆ set_xy_offset()

void Slic3r::GCodeProcessor::set_xy_offset ( double x,
double y )
inline
1461{ m_x_offset = x; m_y_offset = y; }

References m_x_offset, and m_y_offset.

Referenced by Slic3r::Print::export_gcode_from_previous_file(), and Slic3r::Print::reload_gcode_moves().

Here is the caller graph for this function:

◆ simulate_st_synchronize()

void Slic3r::GCodeProcessor::simulate_st_synchronize ( float additional_time = 0.0f,
EMoveType target_move_type = EMoveType::Noop )
private
8136{
8137 calculate_time(m_result, 0, additional_time, target_move_type);
8138 if (m_flavor == gcfKlipper) {
8139 // ToolHead overrides the normal look-ahead window with BUFFER_TIME_HIGH
8140 // at startup and after synchronization: 2 s on legacy, 1 s on modern Klipper.
8141 for (TimeMachine& machine : m_time_processor.machines) {
8142 machine.klipper_junction_flush = machine.requested_accel_to_decel >= 0.0f ? 2.0f : 1.0f;
8143 machine.klipper_queue_priming = true;
8144 }
8145 }
8146}

References calculate_time(), Slic3r::gcfKlipper, Slic3r::GCodeProcessor::TimeMachine::klipper_junction_flush, Slic3r::GCodeProcessor::TimeMachine::klipper_queue_priming, m_flavor, m_result, m_time_processor, and Slic3r::GCodeProcessor::TimeMachine::requested_accel_to_decel.

Referenced by process_custom_gcode_time(), process_filament_change(), process_filament_change(), process_G29(), process_G4(), process_G92(), process_M1(), process_M109(), process_M190(), process_M191(), process_M400(), process_M702(), and process_SYNC().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ store_move_vertex()

void Slic3r::GCodeProcessor::store_move_vertex ( EMoveType type,
EMovePathType path_type = EMovePathType::Noop_move,
bool internal_only = false )
private
7494{
7495 int filament_id = get_filament_id();
7496 const auto normal_mode = PrintEstimatedStatistics::ETimeMode::Normal;
7497 const size_t normal_mode_id = static_cast<size_t>(normal_mode);
7498 const float delta_x = std::abs(m_end_position[X] - m_start_position[X]);
7499 const float delta_y = std::abs(m_end_position[Y] - m_start_position[Y]);
7500 const float delta_z = std::abs(m_end_position[Z] - m_start_position[Z]);
7501 const float delta_e = std::abs(m_end_position[E] - m_start_position[E]);
7502 const bool has_x = delta_x > 0.0f;
7503 const bool has_y = delta_y > 0.0f;
7504 const bool has_z = delta_z > 0.0f;
7505 const bool has_e = delta_e > 0.0f;
7506 const float move_acceleration =
7507 (type == EMoveType::Travel) ? get_travel_acceleration(normal_mode) :
7508 ((type == EMoveType::Retract || type == EMoveType::Unretract) ? get_retract_acceleration(normal_mode) :
7509 get_acceleration(normal_mode));
7510 const float junction_deviation = get_option_value(m_time_processor.machine_limits.machine_max_junction_deviation, normal_mode_id);
7511 const bool use_jd_jerk = (m_flavor == gcfMarlinFirmware && junction_deviation > 0.0f);
7512 const auto axis_jerk_for_preview = [this, use_jd_jerk, move_acceleration](Axis axis) {
7513 return use_jd_jerk ? get_axis_max_jerk_with_jd(normal_mode, axis, move_acceleration) : get_axis_max_jerk(normal_mode, axis);
7514 };
7515 const float jerk_x = axis_jerk_for_preview(X);
7516 const float jerk_y = axis_jerk_for_preview(Y);
7517 const float jerk_z = axis_jerk_for_preview(Z);
7518 const float jerk_e = axis_jerk_for_preview(E);
7519 const float move_jerk =
7520 (has_e && !has_x && !has_y && !has_z) ? jerk_e :
7521 (has_z && !has_x && !has_y) ? jerk_z :
7522 (has_x && has_y) ? std::min(jerk_x, jerk_y) :
7523 has_x ? jerk_x :
7524 has_y ? jerk_y :
7525 has_z ? jerk_z :
7526 std::min(jerk_x, jerk_y);
7528 m_line_id + 1 :
7530
7531 if (type == EMoveType::Travel) {
7532 m_result.print_statistics.total_travel_moves++;
7533 m_result.print_statistics.total_travel_distance += m_travel_dist;
7534 }
7535
7536 // During the start G-code "prepare" stage the toolhead Z is not yet a real
7537 // print height on a normal printer, so it is pinned to the first-layer height
7538 // to keep the preview tidy. Belt printers are the exception: there the Z is
7539 // written explicitly by the belt kinematics and the designed-view back-transform
7540 // couples machine Z into the rendered model Y (the belt tilt mixes the height
7541 // and belt-feed axes). Overriding Z therefore back-transforms the last
7542 // prepare-stage move (the unretract before the first extrusion) to model
7543 // Y ~= 0, and the libvgcode path builder then draws a phantom extrusion
7544 // segment from Y ~= 0 to the first real toolpath. Keep the real Z for belt
7545 // printers so prepare-stage moves map correctly. Gated on belt_tilt_angle (set
7546 // from the G-code header before the body is processed) so non-belt processing
7547 // is byte-identical.
7548 const float store_z = (m_processing_start_custom_gcode && m_result.belt_tilt_angle == 0.f)
7551
7552 m_result.moves.push_back({
7554 type,
7556 static_cast<unsigned char>(filament_id),
7557 m_cp_color.current,
7558 //BBS: add plate's offset to the rendering vertices
7560 static_cast<float>(m_end_position[E] - m_start_position[E]),
7561 m_feedrate,
7562 0.0f, // actual feedrate
7563 m_width,
7564 m_height,
7568 m_extruder_temps[filament_id],
7569// ORCA: Add Pressure Advance visualization support
7571 // ORCA: Add Acceleration visualization support
7572 move_acceleration,
7573 // ORCA: Add Jerk visualization support
7574 move_jerk,
7575 { 0.0f, 0.0f }, // time
7576 static_cast<float>(m_layer_id), //layer_duration: set later
7577 std::max<unsigned int>(1, m_layer_id) - 1,
7578 internal_only,
7580 m_print_z
7581 });
7582
7583 if (type == EMoveType::Seam) {
7584 m_seams_count++;
7585 }
7586
7587 // stores stop time placeholders for later use
7588 if (type == EMoveType::Color_change || type == EMoveType::Pause_Print) {
7589 for (size_t i = 0; i < static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Count); ++i) {
7590 TimeMachine& machine = m_time_processor.machines[i];
7591 if (!machine.enabled)
7592 continue;
7593
7594 machine.stop_times.push_back({ m_g1_line_id, 0.0f });
7595 }
7596 }
7597}

References Slic3r::Color_change, Slic3r::PrintEstimatedStatistics::Count, Slic3r::Custom_GCode, Slic3r::E, Slic3r::GCodeProcessor::TimeMachine::enabled, Slic3r::gcfMarlinFirmware, get_acceleration(), get_axis_max_jerk(), get_axis_max_jerk_with_jd(), get_filament_id(), Slic3r::get_option_value(), get_retract_acceleration(), get_travel_acceleration(), m_cp_color, m_end_position, m_extruder_offsets, m_extruder_temps, m_extrusion_role, m_fan_speed, m_feedrate, m_first_layer_height, m_flavor, m_g1_line_id, m_height, m_last_line_id, m_layer_id, m_line_id, m_mm3_per_mm, m_object_label_id, m_pressure_advance, m_print_z, m_processing_start_custom_gcode, m_result, m_seams_count, m_start_position, m_time_processor, m_travel_dist, m_width, m_x_offset, m_y_offset, m_z_offset, Slic3r::PrintEstimatedStatistics::Normal, Slic3r::Pause_Print, Slic3r::Retract, Slic3r::Seam, Slic3r::GCodeProcessor::TimeMachine::stop_times, Slic3r::Travel, Slic3r::Unretract, Slic3r::X, Slic3r::Y, and Slic3r::Z.

Referenced by process_filament_change(), process_filament_change(), process_G1(), process_G22(), process_G23(), and process_tags().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ update_estimated_times_stats()

void Slic3r::GCodeProcessor::update_estimated_times_stats ( )
private
8149{
8150 auto update_mode = [this](PrintEstimatedStatistics::ETimeMode mode) {
8151 PrintEstimatedStatistics::Mode& data = m_result.print_statistics.modes[static_cast<size_t>(mode)];
8152 data.time = get_time(mode);
8153 data.prepare_time = get_prepare_time(mode);
8154 data.custom_gcode_times = get_custom_gcode_times(mode, true);
8155 };
8156
8158 if (m_time_processor.machines[static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Stealth)].enabled)
8160 else
8161 m_result.print_statistics.modes[static_cast<size_t>(PrintEstimatedStatistics::ETimeMode::Stealth)].reset();
8162
8163 m_result.print_statistics.volumes_per_color_change = m_used_filaments.volumes_per_color_change;
8164 m_result.print_statistics.model_volumes_per_extruder = m_used_filaments.model_volumes_per_filament;
8165 m_result.print_statistics.wipe_tower_volumes_per_extruder = m_used_filaments.wipe_tower_volumes_per_filament;
8166 m_result.print_statistics.support_volumes_per_extruder = m_used_filaments.support_volumes_per_filament;
8167 m_result.print_statistics.flush_per_filament = m_used_filaments.flush_per_filament;
8168 m_result.print_statistics.used_filaments_per_role = m_used_filaments.filaments_per_role;
8169 m_result.print_statistics.total_volumes_per_extruder = m_used_filaments.total_volumes_per_filament;
8170}
float get_prepare_time(PrintEstimatedStatistics::ETimeMode mode) const
Definition GCodeProcessor.cpp:4016
double get_time(PrintEstimatedStatistics::ETimeMode mode) const
Definition GCodeProcessor.cpp:4011
std::vector< std::pair< CustomGCode::Type, std::pair< float, float > > > get_custom_gcode_times(PrintEstimatedStatistics::ETimeMode mode, bool include_remaining) const
Definition GCodeProcessor.cpp:4026

References Slic3r::PrintEstimatedStatistics::Mode::custom_gcode_times, get_custom_gcode_times(), get_prepare_time(), get_time(), m_result, m_time_processor, m_used_filaments, Slic3r::PrintEstimatedStatistics::Normal, Slic3r::PrintEstimatedStatistics::Mode::prepare_time, Slic3r::GCodeProcessorResult::reset(), Slic3r::PrintEstimatedStatistics::Stealth, and Slic3r::PrintEstimatedStatistics::Mode::time.

Referenced by finalize().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ update_exclusion_volume_path_check_result()

void Slic3r::GCodeProcessor::update_exclusion_volume_path_check_result ( )
private
3946{
3947 m_result.exclusion_volume_path_checked = m_exclusion_volume_path_checker.configured();
3948 const ExclusionVolumePathCheckResult &check = m_exclusion_volume_path_checker.result();
3949 m_result.exclusion_volume_path_conflict = check.has_any_conflict;
3950 m_result.exclusion_volume_travel_conflict = check.has_travel_conflict;
3951 m_result.exclusion_volume_extrusion_conflict = check.has_extrusion_conflict;
3952 m_result.exclusion_volume_other_motion_conflict = check.has_other_motion_conflict;
3953
3954 if (!check.first_hit)
3955 return;
3956
3957 const ExclusionVolumePathHit &hit = *check.first_hit;
3958 m_result.exclusion_volume_conflict_gcode_id = hit.gcode_id;
3959 m_result.exclusion_volume_conflict_move_id = hit.move_id;
3960 m_result.exclusion_volume_conflict_move_type = static_cast<EMoveType>(hit.source_move_type);
3961 m_result.exclusion_volume_conflict_extruder_id = hit.extruder_id;
3962 m_result.exclusion_volume_conflict_region_id = hit.region_id;
3963 m_result.exclusion_volume_conflict_used_unknown_z = hit.used_unknown_z;
3964}
bool check(ModelVolumeType volume_type)
Definition GLGizmoEmboss.cpp:515

References Slic3r::ExclusionVolumePathHit::extruder_id, Slic3r::ExclusionVolumePathHit::gcode_id, m_exclusion_volume_path_checker, m_result, Slic3r::ExclusionVolumePathHit::move_id, Slic3r::ExclusionVolumePathHit::region_id, Slic3r::ExclusionVolumePathHit::source_move_type, and Slic3r::ExclusionVolumePathHit::used_unknown_z.

Referenced by finalize().

Here is the caller graph for this function:

◆ update_position_known_from_move() [1/2]

void Slic3r::GCodeProcessor::update_position_known_from_move ( const GCodeReader::GCodeLine & line)
private
5175{
5177 return;
5178
5179 for (unsigned char axis = X; axis <= Z; ++axis) {
5180 if (line.has(static_cast<Axis>(axis)))
5182 }
5183}

References Absolute, Slic3r::GCodeReader::GCodeLine::has(), m_axis_origin_known, m_axis_position_known, m_global_positioning_type, Slic3r::X, and Slic3r::Z.

Here is the call graph for this function:

◆ update_position_known_from_move() [2/2]

void Slic3r::GCodeProcessor::update_position_known_from_move ( const std::array< std::optional< double >, 4 > & axes,
G1DiscretizationOrigin origin )
private
5164{
5166 return;
5167
5168 for (unsigned char axis = X; axis <= Z; ++axis) {
5169 if (axes[axis].has_value())
5171 }
5172}

References Absolute, G1, m_axis_origin_known, m_axis_position_known, m_global_positioning_type, Slic3r::X, and Slic3r::Z.

Referenced by process_G1(), and process_G2_G3().

Here is the caller graph for this function:

◆ update_slice_warnings()

void Slic3r::GCodeProcessor::update_slice_warnings ( )
private
8191{
8192 m_result.warnings.clear();
8193
8194 auto get_used_filaments = [this]() {
8195 std::vector<size_t> used_filaments;
8196 used_filaments.reserve(m_used_filaments.total_volumes_per_filament.size());
8197 for (auto item : m_used_filaments.total_volumes_per_filament) {
8198 used_filaments.push_back(item.first);
8199 }
8200 return used_filaments;
8201 };
8202
8203 auto used_filaments = get_used_filaments();
8204 assert(!used_filaments.empty());
8205 GCodeProcessorResult::SliceWarning warning;
8206 warning.level = 1;
8207 if (m_highest_bed_temp != 0) {
8208 for (size_t i = 0; i < used_filaments.size(); i++) {
8209 int temperature = get_filament_vitrification_temperature(used_filaments[i]);
8210 if (temperature != 0 && m_highest_bed_temp >= temperature)
8211 warning.params.push_back(std::to_string(used_filaments[i]));
8212 }
8213 }
8214
8215 if (!warning.params.empty()) {
8216 warning.level = 3;
8217 warning.msg = BED_TEMP_TOO_HIGH_THAN_FILAMENT;
8218 warning.error_code = "1000C001";
8219 m_result.warnings.push_back(warning);
8220 }
8221
8222 //bbs:HRC checker
8223 warning.params.clear();
8224 warning.level=1;
8225
8226 std::vector<int> nozzle_hrc_lists(m_result.nozzle_type.size(), 0);
8227 // store the nozzle hrc of each extruder
8228 for (size_t idx = 0; idx < m_result.nozzle_type.size(); ++idx) {
8229 nozzle_hrc_lists[idx] = m_result.nozzle_hrc;
8230 if(nozzle_hrc_lists[idx] <= 0)
8231 nozzle_hrc_lists[idx] = Print::get_hrc_by_nozzle_type(m_result.nozzle_type[idx]);
8232 }
8233
8234 for (size_t idx = 0; idx < used_filaments.size(); ++idx) {
8235 int filament_hrc = 0;
8236
8237 if (used_filaments[idx] < m_result.required_nozzle_HRC.size())
8238 filament_hrc = m_result.required_nozzle_HRC[used_filaments[idx]];
8239
8240 int filament_extruder_id = used_filaments[idx] < m_filament_maps.size() ? m_filament_maps[used_filaments[idx]] : -1;
8241 int extruder_hrc = (filament_extruder_id >= 0 && (size_t) filament_extruder_id < nozzle_hrc_lists.size()) ? nozzle_hrc_lists[filament_extruder_id] : 0;
8242
8243 BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(": Check HRC: filament:%1%, hrc=%2%, extruder:%3%, hrc:%4%") % used_filaments[idx] % filament_hrc % filament_extruder_id % extruder_hrc;
8244
8245 if (extruder_hrc!=0 && extruder_hrc < filament_hrc)
8246 warning.params.push_back(std::to_string(used_filaments[idx]));
8247 }
8248
8249 if (!warning.params.empty()) {
8250 warning.level = 3;
8251 warning.msg = NOZZLE_HRC_CHECKER;
8252 warning.error_code = "1000C002";
8253 m_result.warnings.push_back(warning);
8254 }
8255
8256 // bbs:HRC checker
8257 warning.params.clear();
8258 warning.level = 1;
8259 if (!m_result.support_traditional_timelapse) {
8260 warning.level = 2;
8262 warning.error_code = "10018003";
8263 m_result.warnings.push_back(warning);
8264
8265 // Compatible with older version for A series
8266 warning.level = 3;
8267 warning.error_code = "1000C003";
8268 m_result.warnings.push_back(warning);
8269 }
8270
8271 if (m_result.timelapse_warning_code != 0) {
8272 if (m_result.timelapse_warning_code & 1) {
8273 warning.level = 1;
8274 warning.msg = NOT_GENERATE_TIMELAPSE;
8275 warning.error_code = "10014001";
8276 m_result.warnings.push_back(warning);
8277 }
8278 if ((m_result.timelapse_warning_code >> 1) & 1) {
8279 warning.level = 1;
8280 warning.msg = NOT_GENERATE_TIMELAPSE;
8281 warning.error_code = "10014002";
8282 m_result.warnings.push_back(warning);
8283 }
8284 if ((m_result.timelapse_warning_code >> 2) & 1) {
8285 warning.level = 2;
8287 warning.error_code = "10018004";
8288 m_result.warnings.push_back(warning);
8289 }
8290 }
8291
8292 m_result.warnings.shrink_to_fit();
8293}
#define SMOOTH_TIMELAPSE_WITHOUT_PRIME_TOWER
Definition GCodeProcessor.hpp:49
#define NOT_SUPPORT_TRADITIONAL_TIMELAPSE
Definition GCodeProcessor.hpp:47
#define BED_TEMP_TOO_HIGH_THAN_FILAMENT
Definition GCodeProcessor.hpp:46
#define NOT_GENERATE_TIMELAPSE
Definition GCodeProcessor.hpp:48
#define NOZZLE_HRC_CHECKER
Definition GCodeProcessor.hpp:45
int get_filament_vitrification_temperature(size_t extrude_id)
Definition GCodeProcessor.cpp:8010
static int get_hrc_by_nozzle_type(const NozzleType &type)
Definition Print.cpp:4570

References BED_TEMP_TOO_HIGH_THAN_FILAMENT, Slic3r::GCodeProcessorResult::SliceWarning::error_code, get_filament_vitrification_temperature(), Slic3r::Print::get_hrc_by_nozzle_type(), Slic3r::GCodeProcessorResult::SliceWarning::level, m_filament_maps, m_highest_bed_temp, m_result, m_used_filaments, Slic3r::GCodeProcessorResult::SliceWarning::msg, NOT_GENERATE_TIMELAPSE, NOT_SUPPORT_TRADITIONAL_TIMELAPSE, NOZZLE_HRC_CHECKER, Slic3r::GCodeProcessorResult::SliceWarning::params, and SMOOTH_TIMELAPSE_WITHOUT_PRIME_TOWER.

Referenced by finalize().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ use_multi_nozzle_change_time_model()

bool Slic3r::GCodeProcessor::use_multi_nozzle_change_time_model ( ) const
private
7212{
7213 // Multi-nozzle context = a printer that can incur nozzle-change events the single-arg model
7214 // cannot distinguish: either a multi-extruder machine (nozzle_diameter has >1 physical extruder,
7215 // e.g. H2D/X2D/H2D-Pro) or an extruder that carries a nozzle cluster (extruder_max_nozzle_count>1,
7216 // e.g. H2C's {1,6}). Every single-extruder single-nozzle printer (X1/P1/A1/H2S/A2L) fails both
7217 // tests → false → they keep the byte-frozen single-arg time model. Both members are populated by
7218 // apply_config (each overload) and cleared in reset(), so this is stream-time safe.
7219 if (m_nozzle_diameter.size() > 1)
7220 return true;
7222 if (count > 1)
7223 return true;
7224 return false;
7225}

References count, m_extruder_max_nozzle_count, and m_nozzle_diameter.

Referenced by process_filament_change().

Here is the caller graph for this function:

◆ ExportLines

friend class ExportLines
friend

References ExportLines.

Referenced by ExportLines, and run_post_process().

Member Data Documentation

◆ External_Purge_Tag

const std::string Slic3r::GCodeProcessor::External_Purge_Tag = " EXTERNAL_PURGE"
staticprivate

Referenced by process_tags().

◆ Flush_End_Tag

const std::string Slic3r::GCodeProcessor::Flush_End_Tag = " FLUSH_END"
staticprivate

Referenced by process_tags().

◆ Flush_Start_Tag

const std::string Slic3r::GCodeProcessor::Flush_Start_Tag = " FLUSH_START"
staticprivate

Referenced by process_tags().

◆ m_actual_speed_id_map

std::vector<std::pair<unsigned int, unsigned int> > Slic3r::GCodeProcessor::m_actual_speed_id_map
private

Referenced by calculate_time().

◆ m_axis_origin_known

std::array<bool, 3> Slic3r::GCodeProcessor::m_axis_origin_known { true, true, true }
private

◆ m_axis_position_known

std::array<bool, 3> Slic3r::GCodeProcessor::m_axis_position_known { false, false, false }
private

◆ m_belt_printer

bool Slic3r::GCodeProcessor::m_belt_printer { false }
private

◆ m_belt_render_config

DynamicConfig Slic3r::GCodeProcessor::m_belt_render_config
private

◆ m_cached_position

CachedPosition Slic3r::GCodeProcessor::m_cached_position
private

Referenced by process_M401(), process_M402(), and reset().

◆ m_command_processor

CommandProcessor Slic3r::GCodeProcessor::m_command_processor
private

◆ m_cp_color

CpColor Slic3r::GCodeProcessor::m_cp_color
private

◆ m_detect_layer_based_on_tag

bool Slic3r::GCodeProcessor::m_detect_layer_based_on_tag {false}
private

◆ m_disable_m73

bool Slic3r::GCodeProcessor::m_disable_m73
private

Referenced by apply_config(), and run_post_process().

◆ m_e_local_positioning_type

EPositioningType Slic3r::GCodeProcessor::m_e_local_positioning_type
private

◆ m_enable_pre_heating

bool Slic3r::GCodeProcessor::m_enable_pre_heating { false }
private
1266{ false };

Referenced by apply_config(), apply_config(), finalize(), reset(), and run_post_process().

◆ m_end_position

◆ m_exclusion_volume_path_checker

ExclusionVolumePathChecker Slic3r::GCodeProcessor::m_exclusion_volume_path_checker
private

◆ m_extruded_last_z

float Slic3r::GCodeProcessor::m_extruded_last_z
private

Referenced by process_G1(), and reset().

◆ m_extruder_blocks

std::vector<ExtruderPreHeating::ExtruderUsageBlcok> Slic3r::GCodeProcessor::m_extruder_blocks
private

◆ m_extruder_colors

ExtruderColors Slic3r::GCodeProcessor::m_extruder_colors
private

◆ m_extruder_id

unsigned char Slic3r::GCodeProcessor::m_extruder_id
private

◆ m_extruder_max_nozzle_count

std::vector<int> Slic3r::GCodeProcessor::m_extruder_max_nozzle_count {1}
private

◆ m_extruder_offsets

std::vector<Vec3f> Slic3r::GCodeProcessor::m_extruder_offsets
private

◆ m_extruder_temps

ExtruderTemps Slic3r::GCodeProcessor::m_extruder_temps
private

◆ m_extrusion_role

◆ m_fan_speed

float Slic3r::GCodeProcessor::m_fan_speed
private

◆ m_feedrate

float Slic3r::GCodeProcessor::m_feedrate
private

◆ m_filament_blocks

std::vector<ExtruderPreHeating::FilamentUsageBlock> Slic3r::GCodeProcessor::m_filament_blocks
private

◆ m_filament_id

std::vector<unsigned char> Slic3r::GCodeProcessor::m_filament_id
private

◆ m_filament_maps

◆ m_filament_nozzle_temp

ExtruderTemps Slic3r::GCodeProcessor::m_filament_nozzle_temp
private

◆ m_filament_nozzle_temp_first_layer

ExtruderTemps Slic3r::GCodeProcessor::m_filament_nozzle_temp_first_layer
private

◆ m_filament_pre_cooling_temp

std::vector<int> Slic3r::GCodeProcessor::m_filament_pre_cooling_temp { 0 }
private

◆ m_filament_preheat_temperature_delta

std::vector<double> Slic3r::GCodeProcessor::m_filament_preheat_temperature_delta
private

◆ m_filament_types

std::vector<std::string> Slic3r::GCodeProcessor::m_filament_types
private

◆ m_first_layer_height

float Slic3r::GCodeProcessor::m_first_layer_height
private

◆ m_flavor

◆ m_flushing

bool Slic3r::GCodeProcessor::m_flushing
private

Referenced by process_G1(), process_tags(), and reset().

◆ m_forced_height

float Slic3r::GCodeProcessor::m_forced_height
private

◆ m_forced_width

float Slic3r::GCodeProcessor::m_forced_width
private

◆ m_g1_line_id

unsigned int Slic3r::GCodeProcessor::m_g1_line_id
private

◆ m_g29_time_added

bool Slic3r::GCodeProcessor::m_g29_time_added {false}
private
1349{false};

Referenced by process_G29(), and reset().

◆ m_global_positioning_type

◆ m_handle_hotend_as_extruder

bool Slic3r::GCodeProcessor::m_handle_hotend_as_extruder { false }
private
1267{ false };

Referenced by apply_config(), reset(), and run_second_pass_injection().

◆ m_has_filament_switcher

bool Slic3r::GCodeProcessor::m_has_filament_switcher { false }
private
1268{ false };

Referenced by apply_config(), apply_config(), reset(), and run_second_pass_injection().

◆ m_height

float Slic3r::GCodeProcessor::m_height
private

◆ m_highest_bed_temp

int Slic3r::GCodeProcessor::m_highest_bed_temp
private

◆ m_hotend_cooling_rate

std::vector<double> Slic3r::GCodeProcessor::m_hotend_cooling_rate { 2.f }
private

◆ m_hotend_heating_rate

std::vector<double> Slic3r::GCodeProcessor::m_hotend_heating_rate { 2.f }
private

◆ m_in_config_block

bool Slic3r::GCodeProcessor::m_in_config_block
private

Referenced by process_tags(), and reset().

◆ m_is_XL_printer

bool Slic3r::GCodeProcessor::m_is_XL_printer = false
private

Referenced by apply_config(), and run_post_process().

◆ m_last_default_color_id

size_t Slic3r::GCodeProcessor::m_last_default_color_id
private

Referenced by process_tags(), and reset().

◆ m_last_filament_id

std::vector<unsigned char> Slic3r::GCodeProcessor::m_last_filament_id
private

◆ m_last_line_id

unsigned int Slic3r::GCodeProcessor::m_last_line_id
private

Referenced by reset(), and store_move_vertex().

◆ m_layer_id

◆ m_line_id

unsigned int Slic3r::GCodeProcessor::m_line_id
private

◆ m_machine_config_idx

int Slic3r::GCodeProcessor::m_machine_config_idx {0}
private

◆ m_machine_end_gcode_start_line_id

unsigned int Slic3r::GCodeProcessor::m_machine_end_gcode_start_line_id { (unsigned int) (-1) }
private
1282{ (unsigned int) (-1) };

Referenced by reset(), run_post_process(), and run_second_pass_injection().

◆ m_machine_frame_transform

MachineFrameTransform Slic3r::GCodeProcessor::m_machine_frame_transform
private

◆ m_machine_start_gcode_end_line_id

unsigned int Slic3r::GCodeProcessor::m_machine_start_gcode_end_line_id { (unsigned int) (-1) }
private
1281{ (unsigned int) (-1) };

Referenced by reset(), run_post_process(), and run_second_pass_injection().

◆ m_manual_filament_change

bool Slic3r::GCodeProcessor::m_manual_filament_change { false }
private
1297{ false };

Referenced by apply_config(), apply_config(), and process_tags().

◆ m_mass_locator

MassLocator Slic3r::GCodeProcessor::m_mass_locator
private

◆ m_measure_g29_time

bool Slic3r::GCodeProcessor::m_measure_g29_time {false}
private
1348{false};

Referenced by process_G29(), process_M622(), and process_M623().

◆ m_mm3_per_mm

float Slic3r::GCodeProcessor::m_mm3_per_mm
private

◆ m_nozzle_diameter

std::vector<double> Slic3r::GCodeProcessor::m_nozzle_diameter
private

◆ m_nozzle_group_result

std::shared_ptr<MultiNozzleUtils::NozzleGroupResultBase> Slic3r::GCodeProcessor::m_nozzle_group_result
private

◆ m_nozzle_status_recorder

MultiNozzleUtils::NozzleStatusRecorder Slic3r::GCodeProcessor::m_nozzle_status_recorder
private

◆ m_nozzle_volume

std::vector<float> Slic3r::GCodeProcessor::m_nozzle_volume
private

◆ m_object_label_id

int Slic3r::GCodeProcessor::m_object_label_id {-1}
private
1246{-1};

Referenced by process_tags(), and store_move_vertex().

◆ m_options_z_corrector

OptionsZCorrector Slic3r::GCodeProcessor::m_options_z_corrector
private

◆ m_origin

AxisCoords Slic3r::GCodeProcessor::m_origin
private

◆ m_parser

◆ m_physical_extruder_map

std::vector<int> Slic3r::GCodeProcessor::m_physical_extruder_map
private

◆ m_preheat_steps

int Slic3r::GCodeProcessor::m_preheat_steps
private

◆ m_preheat_time

float Slic3r::GCodeProcessor::m_preheat_time
private

◆ m_pressure_advance

float Slic3r::GCodeProcessor::m_pressure_advance
private

◆ m_print

Print* Slic3r::GCodeProcessor::m_print { nullptr }
private
1379{ nullptr };

Referenced by run_post_process(), and set_print().

◆ m_print_z

float Slic3r::GCodeProcessor::m_print_z {0.0f}
private
1248{0.0f};

Referenced by process_tags(), and store_move_vertex().

◆ m_printer_model

std::string Slic3r::GCodeProcessor::m_printer_model
private

◆ m_processing_homing_move

bool Slic3r::GCodeProcessor::m_processing_homing_move { false }
private
1234{ false };

Referenced by process_G1(), process_G28(), and reset().

◆ m_processing_start_custom_gcode

bool Slic3r::GCodeProcessor::m_processing_start_custom_gcode
private

◆ m_producer

EProducer Slic3r::GCodeProcessor::m_producer
private

◆ m_remaining_volume

std::vector<float> Slic3r::GCodeProcessor::m_remaining_volume
private

◆ m_result

◆ m_seams_count

int Slic3r::GCodeProcessor::m_seams_count
private

Referenced by reset(), and store_move_vertex().

◆ m_seams_detector

◆ m_single_extruder_multi_material

bool Slic3r::GCodeProcessor::m_single_extruder_multi_material
private

Referenced by apply_config().

◆ m_skip_end_gcode_delays

bool Slic3r::GCodeProcessor::m_skip_end_gcode_delays { false }
private
1286{ false };

Referenced by process_M400(), process_tags(), and reset().

◆ m_skippable

bool Slic3r::GCodeProcessor::m_skippable {false}
private
1244{false};

Referenced by process_tags(), reset(), and set_skippable_type().

◆ m_skippable_blocks

std::vector<std::pair<unsigned int, unsigned int> > Slic3r::GCodeProcessor::m_skippable_blocks
private

◆ m_skippable_type

◆ m_start_position

◆ m_time_processor

◆ m_travel_dist

float Slic3r::GCodeProcessor::m_travel_dist
private

◆ m_units

◆ m_used_filaments

◆ m_virtual_flushing

bool Slic3r::GCodeProcessor::m_virtual_flushing
private

Referenced by process_tags(), process_VG1(), and reset().

◆ m_width

float Slic3r::GCodeProcessor::m_width
private

◆ m_wipe_tower

bool Slic3r::GCodeProcessor::m_wipe_tower
private

Referenced by process_tags(), and reset().

◆ m_wiping

bool Slic3r::GCodeProcessor::m_wiping
private

◆ m_x_offset

double Slic3r::GCodeProcessor::m_x_offset { 0 }
private

◆ m_y_offset

double Slic3r::GCodeProcessor::m_y_offset { 0 }
private

◆ m_z_offset

◆ m_zero_layer_height

float Slic3r::GCodeProcessor::m_zero_layer_height
private

Referenced by reset().

◆ Machine_End_GCode_Start_Tag

const std::string Slic3r::GCodeProcessor::Machine_End_GCode_Start_Tag = " MACHINE_END_GCODE_START"
static

◆ Machine_Start_GCode_End_Tag

const std::string Slic3r::GCodeProcessor::Machine_Start_GCode_End_Tag = " MACHINE_START_GCODE_END"
static

◆ Nozzle_Change_End_Tag

const std::string Slic3r::GCodeProcessor::Nozzle_Change_End_Tag = " NOZZLE_CHANGE_END"
static

◆ Nozzle_Change_Start_Tag

const std::string Slic3r::GCodeProcessor::Nozzle_Change_Start_Tag = " NOZZLE_CHANGE_START"
static

◆ Output_Block_Size

size_t Slic3r::GCodeProcessor::Output_Block_Size = 65536
staticconstexpr

◆ Producers

const std::vector< std::pair< GCodeProcessor::EProducer, std::string > > Slic3r::GCodeProcessor::Producers
staticprivate
Initial value:
= {
{ EProducer::OrcaSlicer, SLIC3R_APP_NAME },
{ EProducer::OrcaSlicer, "generated by OrcaSlicer" },
{ EProducer::OrcaSlicer, "generated by BambuStudio" },
{ EProducer::OrcaSlicer, "BambuStudio" }
}

Referenced by detect_producer().

◆ Reserved_Tags

const std::vector< std::string > Slic3r::GCodeProcessor::Reserved_Tags
staticprivate

◆ Reserved_Tags_compatible

const std::vector< std::string > Slic3r::GCodeProcessor::Reserved_Tags_compatible
staticprivate

◆ s_IsBBLPrinter

◆ s_result_id

unsigned int Slic3r::GCodeProcessor::s_result_id = 0
staticprivate

Referenced by initialize(), process_file(), and reset().

◆ Skippable_End_Tag

const std::string Slic3r::GCodeProcessor::Skippable_End_Tag = " SKIPPABLE_END"
static

Referenced by process_tags(), and run_post_process().

◆ Skippable_Start_Tag

const std::string Slic3r::GCodeProcessor::Skippable_Start_Tag = " SKIPPABLE_START"
static

Referenced by process_tags(), and run_post_process().

◆ Skippable_Type_Tag

const std::string Slic3r::GCodeProcessor::Skippable_Type_Tag = " SKIPTYPE: "
static

Referenced by process_tags().

◆ Toolchange_Wipe_Tag

const std::string Slic3r::GCodeProcessor::Toolchange_Wipe_Tag = " CP_TOOLCHANGE_WIPE"
static

◆ VFlush_End_Tag

const std::string Slic3r::GCodeProcessor::VFlush_End_Tag = " VFLUSH_END"
staticprivate

Referenced by process_tags().

◆ VFlush_Start_Tag

const std::string Slic3r::GCodeProcessor::VFlush_Start_Tag = " VFLUSH_START"
staticprivate

Referenced by process_tags().

◆ Wipe_Height

const float Slic3r::GCodeProcessor::Wipe_Height = 0.05f
static

Referenced by finalize().

◆ Wipe_Width

const float Slic3r::GCodeProcessor::Wipe_Width = 0.05f
static

Referenced by finalize().


The documentation for this class was generated from the following files: