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

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

Collaboration diagram for Slic3r::WipeTower2:

Classes

struct  FilamentParameters
struct  WipeTowerInfo

Public Member Functions

WipeTower::ToolChangeResult construct_tcr (WipeTowerWriter2 &writer, bool priming, size_t old_tool, bool is_finish, bool is_contact=false) const
 WipeTower2 (const PrintConfig &config, const PrintRegionConfig &default_region_config, int plate_idx, Vec3d plate_origin, const std::vector< std::vector< float > > &wiping_matrix, size_t initial_tool)
void set_extruder (size_t idx, const PrintConfig &config)
void plan_toolchange (float z_par, float layer_height_par, unsigned int old_tool, unsigned int new_tool, float wipe_volume=0.f)
void generate (std::vector< std::vector< WipeTower::ToolChangeResult > > &result)
float get_depth () const
std::vector< std::pair< float, float > > get_z_and_depth_pairs () const
float get_brim_width () const
float get_wipe_tower_height () const
BoundingBoxf get_bbx () const
Vec2f get_rib_offset () const
float get_rib_width () const
float get_rib_length () const
void set_layer (float print_z, float layer_height, size_t max_tool_changes, bool, bool is_last_layer)
const Vec2f & position () const
float width () const
bool finished () const
std::vector< WipeTower::ToolChangeResult > prime (float first_layer_height, const std::vector< unsigned int > &tools, bool last_wipe_inside_wipe_tower)
WipeTower::ToolChangeResult tool_change (size_t new_tool)
WipeTower::ToolChangeResult finish_layer ()
bool layer_finished () const
std::vector< float > get_used_filament () const
std::vector< std::pair< float, std::vector< float > > > get_used_filament_until_layer () const
int get_number_of_toolchanges () const

Static Public Member Functions

static const std::string never_skip_tag ()
static const std::string wait_for_temp_tag ()
static std::pair< double, double > get_wipe_tower_cone_base (double width, double height, double depth, double angle_deg)
static Polygon cone_base_polygon (double width, double depth, double height, double angle_deg)
static std::vector< std::vector< float > > extract_wipe_volumes (const ConfigBase &config)
static float estimate_semm_flush_volume (const ConfigBase &config, size_t filaments_cnt)
static bool use_gap_wall (const PrintConfig &config)
static bool wait_for_temp_enabled (const PrintConfig &config)

Private Types

enum  wipe_shape { SHAPE_NORMAL = 1 , SHAPE_REVERSED = -1 }
enum  { RectangularBed , CircularBed , CustomBed }

Private Member Functions

float filament_area () const
bool is_first_layer () const
float wipe_row_spacing (bool first_layer) const
float wipe_line_width () const
bool tool_ramming_enabled (size_t tool) const
bool boundary_wipe_start_enabled (size_t tool) const
float wipe_start_offset_after_ram (float ramming_depth, bool first_layer) const
Vec2f toolchange_entry_pos (float depth_traversed, float ramming_depth, bool first_layer) const
float extrusion_flow (float layer_height=-1.f) const
void plan_tower ()
void save_on_last_wipe ()
int first_toolchange_to_nonsoluble_nonsupport (const std::vector< WipeTowerInfo::ToolChange > &tool_changes) const
void toolchange_Unload (WipeTowerWriter2 &writer, const WipeTower::box_coordinates &cleaning_box, const std::string &current_material, const int old_temperature, const int new_temperature)
void toolchange_Change (WipeTowerWriter2 &writer, const size_t new_tool, const std::string &new_material, const int wait_for_temp, const bool wait_beside_tower)
void toolchange_Load (WipeTowerWriter2 &writer, const WipeTower::box_coordinates &cleaning_box)
void toolchange_Wipe (WipeTowerWriter2 &writer, const WipeTower::box_coordinates &cleaning_box, float wipe_volume, bool interface_layer, bool priming=false, bool fill_box=false)
Polygon generate_support_rib_wall (WipeTowerWriter2 &writer, const WipeTower::box_coordinates &wt_box, double feedrate, bool first_layer, bool rib_wall, bool extrude_perimeter)
Polygon generate_support_cone_wall (WipeTowerWriter2 &writer, const WipeTower::box_coordinates &wt_box, double feedrate, bool infill_cone, float spacing)
Polygon generate_rib_polygon (const WipeTower::box_coordinates &wt_box)
void compute_wall_skip_points ()
WipeTowerInfo::ToolChange set_toolchange (size_t old_tool, size_t new_tool, float layer_height, float wipe_volume, bool first_layer_plan)

Private Attributes

const float Width_To_Nozzle_Ratio = 1.25f
const float WT_EPSILON = 1e-3f
bool m_semm = true
bool m_enable_filament_ramming = true
bool m_is_mk4mmu3 = false
int m_wipe_tower_filament = 0
Vec2f m_wipe_tower_pos
float m_wipe_tower_width
float m_wipe_tower_depth = 0.f
float m_wipe_tower_height = 0.f
float m_wipe_tower_cone_angle = 0.f
float m_wipe_tower_brim_width = 0.f
float m_wipe_tower_brim_width_real = 0.f
BoundingBoxf m_first_layer_bbx
float m_wipe_tower_rotation_angle = 0.f
float m_internal_rotation = 0.f
float m_y_shift = 0.f
float m_z_pos = 0.f
float m_layer_height = 0.f
size_t m_max_color_changes = 0
int m_old_temperature = -1
float m_travel_speed = 0.f
float m_infill_speed = 0.f
float m_wipe_tower_max_purge_speed = 90.f
float m_perimeter_speed = 0.f
float m_first_layer_speed = 0.f
size_t m_first_layer_idx = size_t(-1)
bool m_enable_tower_interface_features = false
bool m_enable_tower_interface_cooldown_during_tower = false
bool m_wait_for_temp_on_wipe_tower = false
bool m_prev_layer_had_interface = false
bool m_current_layer_has_interface = false
int m_wall_type
bool m_used_fillet = true
float m_rib_width = 10
float m_extra_rib_length = 0
float m_rib_length = 0
Vec2f m_rib_offset = Vec2f::Zero()
bool m_use_gap_wall = false
std::vector< std::vector< Vec2f > > m_wall_skip_points
bool m_enable_arc_fitting = false
float m_cooling_tube_retraction = 0.f
float m_cooling_tube_length = 0.f
float m_parking_pos_retraction = 0.f
float m_extra_loading_move = 0.f
float m_bridging = 0.f
bool m_sparse_layers_skipped = false
bool m_sparse_layers_combined = false
bool m_set_extruder_trimpot = false
bool m_adhesion = true
GCodeFlavor m_gcode_flavor
enum Slic3r::WipeTower2:: { ... }  m_bed_shape
float m_bed_width
Vec2f m_bed_bottom_left
Polygon m_bed_polygon
float m_perimeter_width = 0.4f * Width_To_Nozzle_Ratio
float m_extrusion_flow = 0.038f
std::vector< FilamentParameters > m_filpar
unsigned int m_num_layer_changes = 0
unsigned int m_num_tool_changes = 0
wipe_shape m_current_shape = SHAPE_NORMAL
size_t m_current_tool = 0
const std::vector< std::vector< float > > wipe_volumes
float m_depth_traversed = 0.f
bool m_current_layer_finished = false
bool m_left_to_right = true
float m_extra_flow = 1.f
float m_extra_spacing_wipe = 1.f
float m_extra_spacing_ramming = 1.f
std::vector< WipeTowerInfo > m_plan
std::vector< WipeTowerInfo >::iterator m_layer_info = m_plan.end()
float m_current_height = 0.f
std::vector< float > m_used_filament_length
std::vector< std::pair< float, std::vector< float > > > m_used_filament_length_until_layer

Detailed Description


Class Documentation

◆ Slic3r::WipeTower2::FilamentParameters

struct Slic3r::WipeTower2::FilamentParameters
Collaboration diagram for Slic3r::WipeTower2::FilamentParameters:
Class Members
float cooling_final_speed = 0.f
float cooling_initial_speed = 0.f
int cooling_moves = 0
float delay = 0.f
float filament_area
float filament_minimal_purge_on_wipe_tower = 0.f
float filament_stamping_distance = 0.f
float filament_stamping_loading_speed = 0.f
int first_layer_temperature = 0
int interface_print_temperature = 0
bool is_soluble = false
bool is_support = false
float loading_speed = 0.f
float loading_speed_start = 0.f
string material = "PLA"
float max_e_speed = std::numeric_limits<float>::max()
float max_layer_height = 0.f
bool multitool_ramming
float multitool_ramming_time = 0.f
float nozzle_diameter
float ramming_line_width_multiplicator = 1.f
vector< float > ramming_speed
float ramming_step_multiplicator = 1.f
float retract_length
float retract_speed
int temperature = 0
float tower_interface_pre_extrusion_dist = 0.f
float tower_interface_pre_extrusion_length = 0.f
float tower_interface_purge_length = 0.f
float tower_ironing_area = 4.f
float unloading_speed = 0.f
float unloading_speed_start = 0.f

Member Enumeration Documentation

◆ anonymous enum

anonymous enum
private
Enumerator
RectangularBed 
CircularBed 
CustomBed 
285 {
289 } m_bed_shape;
enum Slic3r::WipeTower2::@205320035102056302177355300070045133270164132047 m_bed_shape
@ CircularBed
Definition WipeTower2.hpp:287
@ CustomBed
Definition WipeTower2.hpp:288
@ RectangularBed
Definition WipeTower2.hpp:286

◆ wipe_shape

Enumerator
SHAPE_NORMAL 
SHAPE_REVERSED 
215 {
216 SHAPE_NORMAL = 1,
217 SHAPE_REVERSED = -1
218 };
@ SHAPE_REVERSED
Definition WipeTower2.hpp:217
@ SHAPE_NORMAL
Definition WipeTower2.hpp:216

Constructor & Destructor Documentation

◆ WipeTower2()

Slic3r::WipeTower2::WipeTower2 ( const PrintConfig & config,
const PrintRegionConfig & default_region_config,
int plate_idx,
Vec3d plate_origin,
const std::vector< std::vector< float > > & wiping_matrix,
size_t initial_tool )
1042 :
1043 m_semm(config.single_extruder_multi_material.value),
1044 m_enable_filament_ramming(config.enable_filament_ramming.value),
1045 m_wipe_tower_filament(config.wipe_tower_filament.value),
1046 m_wipe_tower_pos(config.wipe_tower_x.get_at(plate_idx), config.wipe_tower_y.get_at(plate_idx)),
1047 m_wipe_tower_width(float(config.prime_tower_width)),
1048 m_wipe_tower_rotation_angle(float(config.wipe_tower_rotation_angle)),
1049 m_wipe_tower_brim_width(float(config.prime_tower_brim_width)),
1050 m_wipe_tower_cone_angle(float(config.wipe_tower_cone_angle)),
1051 m_extra_flow(float(config.wipe_tower_extra_flow/100.)),
1052 m_extra_spacing_wipe(float(config.wipe_tower_extra_spacing/100. * config.wipe_tower_extra_flow/100.)),
1053 m_extra_spacing_ramming(float(config.wipe_tower_extra_spacing/100.)),
1054 m_y_shift(0.f),
1055 m_z_pos(0.f),
1056 m_bridging(float(config.wipe_tower_bridging)),
1059 m_gcode_flavor(config.gcode_flavor),
1060 m_travel_speed(config.travel_speed.get_at(get_extruder_index(config, (unsigned int)initial_tool))),
1061 m_infill_speed(default_region_config.sparse_infill_speed.get_at(get_extruder_index(config, (unsigned int)initial_tool))),
1062 m_perimeter_speed(default_region_config.inner_wall_speed.get_at(get_extruder_index(config, (unsigned int)initial_tool))),
1063 m_current_tool(initial_tool),
1064 wipe_volumes(wiping_matrix), m_wipe_tower_max_purge_speed(float(config.wipe_tower_max_purge_speed)),
1065 m_enable_arc_fitting(config.enable_arc_fitting.value == ArcFittingMode::Enabled),
1066 m_used_fillet(config.wipe_tower_fillet_wall),
1067 m_rib_width(config.wipe_tower_rib_width),
1068 m_extra_rib_length(config.wipe_tower_extra_rib_length),
1069 m_wall_type((int)config.wipe_tower_wall_type),
1071 m_enable_tower_interface_features(config.enable_tower_interface_features.value),
1072 m_enable_tower_interface_cooldown_during_tower(config.enable_tower_interface_cooldown_during_tower.value),
1074{
1075 // Read absolute value of first layer speed, if given as percentage,
1076 // it is taken over following default. Speeds from config are not
1077 // easily accessible here.
1078 const float default_speed = 60.f;
1079 m_first_layer_speed = config.initial_layer_speed.get_at(get_extruder_index(config, (unsigned int)initial_tool));
1080 if (m_first_layer_speed == 0.f) // just to make sure autospeed doesn't break it.
1081 m_first_layer_speed = default_speed / 2.f;
1082
1083 // Autospeed may be used...
1084 if (m_infill_speed == 0.f)
1085 m_infill_speed = 80.f;
1086 if (m_perimeter_speed == 0.f)
1087 m_perimeter_speed = 80.f;
1088
1089
1090 // If this is a single extruder MM printer, we will use all the SE-specific config values.
1091 // Otherwise, the defaults will be used to turn off the SE stuff.
1092 if (m_semm) {
1093 m_cooling_tube_retraction = float(config.cooling_tube_retraction);
1094 m_cooling_tube_length = float(config.cooling_tube_length);
1095 m_parking_pos_retraction = float(config.parking_pos_retraction);
1096 m_extra_loading_move = float(config.extra_loading_move);
1097 m_set_extruder_trimpot = config.high_current_on_filament_swap;
1098 }
1099
1100 m_is_mk4mmu3 = boost::icontains(config.printer_notes.value, "PRINTER_MODEL_MK4") && boost::icontains(config.printer_notes.value, "MMU");
1101
1102 // Calculate where the priming lines should be - very naive test not detecting parallelograms etc.
1103 const std::vector<Vec2d>& bed_points = config.printable_area.values;
1104 BoundingBoxf bb(bed_points);
1105 m_bed_width = float(bb.size().x());
1106 m_bed_shape = (bed_points.size() == 4 ? RectangularBed : CircularBed);
1107
1108 if (m_bed_shape == CircularBed) {
1109 // this may still be a custom bed, check that the points are roughly on a circle
1110 double r2 = std::pow(m_bed_width/2., 2.);
1111 double lim2 = std::pow(m_bed_width/10., 2.);
1112 Vec2d center = bb.center();
1113 for (const Vec2d& pt : bed_points)
1114 if (std::abs(std::pow(pt.x()-center.x(), 2.) + std::pow(pt.y()-center.y(), 2.) - r2) > lim2) {
1116 break;
1117 }
1118 }
1119
1121 ? Vec2f(bed_points.front().x(), bed_points.front().y())
1122 : Vec2f::Zero();
1123 m_bed_polygon = Polygon::new_scale(bed_points);
1124}
static Polygon new_scale(const std::vector< Vec2d > &points)
Definition Polygon.hpp:38
float m_extra_flow
Definition WipeTower2.hpp:312
float m_wipe_tower_rotation_angle
Definition WipeTower2.hpp:239
bool m_is_mk4mmu3
Definition WipeTower2.hpp:229
Vec2f m_wipe_tower_pos
Definition WipeTower2.hpp:231
float m_extra_rib_length
Definition WipeTower2.hpp:261
bool m_sparse_layers_skipped
Definition WipeTower2.hpp:278
float m_cooling_tube_retraction
Definition WipeTower2.hpp:273
Polygon m_bed_polygon
Definition WipeTower2.hpp:292
float m_extra_loading_move
Definition WipeTower2.hpp:276
float m_parking_pos_retraction
Definition WipeTower2.hpp:275
GCodeFlavor m_gcode_flavor
Definition WipeTower2.hpp:282
float m_bed_width
Definition WipeTower2.hpp:290
float m_wipe_tower_cone_angle
Definition WipeTower2.hpp:235
float m_cooling_tube_length
Definition WipeTower2.hpp:274
bool m_enable_filament_ramming
Definition WipeTower2.hpp:228
bool m_use_gap_wall
Definition WipeTower2.hpp:264
Vec2f m_bed_bottom_left
Definition WipeTower2.hpp:291
float m_z_pos
Definition WipeTower2.hpp:242
bool m_enable_tower_interface_cooldown_during_tower
Definition WipeTower2.hpp:253
bool m_semm
Definition WipeTower2.hpp:227
bool m_wait_for_temp_on_wipe_tower
Definition WipeTower2.hpp:254
float m_first_layer_speed
Definition WipeTower2.hpp:250
float m_perimeter_speed
Definition WipeTower2.hpp:249
size_t m_current_tool
Definition WipeTower2.hpp:306
float m_extra_spacing_wipe
Definition WipeTower2.hpp:313
float m_travel_speed
Definition WipeTower2.hpp:246
static bool wait_for_temp_enabled(const PrintConfig &config)
Definition WipeTower2.cpp:1035
bool m_used_fillet
Definition WipeTower2.hpp:259
float m_wipe_tower_width
Definition WipeTower2.hpp:232
bool m_sparse_layers_combined
Definition WipeTower2.hpp:279
float m_y_shift
Definition WipeTower2.hpp:241
bool m_enable_tower_interface_features
Definition WipeTower2.hpp:252
bool m_set_extruder_trimpot
Definition WipeTower2.hpp:280
float m_rib_width
Definition WipeTower2.hpp:260
float m_wipe_tower_max_purge_speed
Definition WipeTower2.hpp:248
int m_wall_type
Definition WipeTower2.hpp:258
bool m_enable_arc_fitting
Definition WipeTower2.hpp:270
float m_extra_spacing_ramming
Definition WipeTower2.hpp:314
float m_infill_speed
Definition WipeTower2.hpp:247
float m_bridging
Definition WipeTower2.hpp:277
int m_wipe_tower_filament
Definition WipeTower2.hpp:230
const std::vector< std::vector< float > > wipe_volumes
Definition WipeTower2.hpp:307
static bool use_gap_wall(const PrintConfig &config)
Definition WipeTower2.cpp:1029
float m_wipe_tower_brim_width
Definition WipeTower2.hpp:236
size_t get_extruder_index(const GCodeConfig &config, unsigned int filament_id)
Definition PrintConfig.cpp:140
@ Enabled
Definition PrintConfig.hpp:240
void center(ExPolygonsWithIds &e)
Definition Emboss.cpp:1382
bool wipe_tower_sparse_layers_skipped(const PrintConfig &config)
Definition WipeTower.cpp:53
Eigen::Matrix< float, 2, 1, Eigen::DontAlign > Vec2f
Definition Point.hpp:64
Eigen::Matrix< double, 2, 1, Eigen::DontAlign > Vec2d
Definition Point.hpp:67
bool wipe_tower_sparse_layers_combined(const PrintConfig &config)
Definition WipeTower.cpp:77

References Slic3r::BoundingBoxBase< PointType, APointsType >::center(), Slic3r::center(), CircularBed, CustomBed, Slic3r::enable_filament_ramming(), Slic3r::enable_tower_interface_features(), Slic3r::gcode_flavor(), Slic3r::get_extruder_index(), Slic3r::inner_wall_speed(), m_bed_bottom_left, m_bed_polygon, m_bed_shape, m_bed_width, m_bridging, m_cooling_tube_length, m_cooling_tube_retraction, m_current_tool, m_enable_arc_fitting, m_enable_filament_ramming, m_enable_tower_interface_cooldown_during_tower, m_enable_tower_interface_features, m_extra_flow, m_extra_loading_move, m_extra_rib_length, m_extra_spacing_ramming, m_extra_spacing_wipe, m_first_layer_speed, m_gcode_flavor, m_infill_speed, m_is_mk4mmu3, m_parking_pos_retraction, m_perimeter_speed, m_rib_width, m_semm, m_set_extruder_trimpot, m_sparse_layers_combined, m_sparse_layers_skipped, m_travel_speed, m_use_gap_wall, m_used_fillet, m_wait_for_temp_on_wipe_tower, m_wall_type, m_wipe_tower_brim_width, m_wipe_tower_cone_angle, m_wipe_tower_filament, m_wipe_tower_max_purge_speed, m_wipe_tower_pos, m_wipe_tower_rotation_angle, m_wipe_tower_width, m_y_shift, m_z_pos, Slic3r::Polygon::new_scale(), Slic3r::prime_tower_brim_width(), Slic3r::PrintRegionConfig, RectangularBed, Slic3r::single_extruder_multi_material(), Slic3r::BoundingBoxBase< PointType, APointsType >::size(), Slic3r::sparse_infill_speed(), Slic3r::travel_speed(), use_gap_wall(), wait_for_temp_enabled(), Slic3r::wipe_tower_bridging(), Slic3r::wipe_tower_cone_angle(), Slic3r::wipe_tower_extra_rib_length(), Slic3r::wipe_tower_fillet_wall(), Slic3r::wipe_tower_max_purge_speed(), Slic3r::wipe_tower_sparse_layers_combined(), Slic3r::wipe_tower_sparse_layers_skipped(), Slic3r::wipe_tower_y(), and wipe_volumes.

Here is the call graph for this function:

Member Function Documentation

◆ boundary_wipe_start_enabled()

bool Slic3r::WipeTower2::boundary_wipe_start_enabled ( size_t tool) const
inlineprivate
327{ return tool_ramming_enabled(tool) && !m_semm && m_use_gap_wall; }
bool tool_ramming_enabled(size_t tool) const
Definition WipeTower2.hpp:323

References m_semm, m_use_gap_wall, and tool_ramming_enabled().

Referenced by set_toolchange(), tool_change(), and toolchange_Unload().

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

◆ compute_wall_skip_points()

void Slic3r::WipeTower2::compute_wall_skip_points ( )
private
2454{
2455 m_wall_skip_points.assign(m_plan.size(), std::vector<Vec2f>());
2456 for (size_t layer_id = 0; layer_id < m_plan.size(); ++layer_id) {
2457 float depth_traversed = 0.f;
2458 for (const auto& toolchange : m_plan[layer_id].tool_changes) {
2459 m_wall_skip_points[layer_id].emplace_back(
2460 toolchange_entry_pos(depth_traversed, toolchange.ramming_depth, layer_id == m_first_layer_idx));
2461 depth_traversed += toolchange.required_depth;
2462 }
2463 }
2464}
Vec2f toolchange_entry_pos(float depth_traversed, float ramming_depth, bool first_layer) const
Definition WipeTower2.hpp:341
std::vector< std::vector< Vec2f > > m_wall_skip_points
Definition WipeTower2.hpp:268
std::vector< WipeTowerInfo > m_plan
Definition WipeTower2.hpp:390
size_t m_first_layer_idx
Definition WipeTower2.hpp:251

References m_first_layer_idx, m_plan, m_wall_skip_points, and toolchange_entry_pos().

Referenced by generate().

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

◆ cone_base_polygon()

Polygon Slic3r::WipeTower2::cone_base_polygon ( double width,
double depth,
double height,
double angle_deg )
static
2168{
2170 Point::new_scale(Vec2d(width, depth)), Point::new_scale(Vec2d(0., depth))});
2171 if (angle_deg <= EPSILON || height <= EPSILON || width <= EPSILON || depth <= EPSILON)
2172 return box;
2173 const auto [R, x_scale] = get_wipe_tower_cone_base(width, height, depth, angle_deg);
2174 if (R <= EPSILON)
2175 return box;
2176 const Vec2d center(width / 2., depth / 2.);
2177 Polygon ellipse;
2178 for (double alpha = 0.; alpha < 2. * M_PI; alpha += M_PI / 20.)
2179 ellipse.points.push_back(Point::new_scale(center + R * Vec2d(std::cos(alpha) / x_scale, std::sin(alpha))));
2180 Polygons u = union_({box, ellipse});
2181 return u.empty() ? box : u.front();
2182}
#define EPSILON
Definition ColorUtils.cpp:64
#define M_PI
Definition ExtrusionSimulator.cpp:31
Points points
Definition MultiPoint.hpp:22
static Point new_scale(coordf_t x, coordf_t y)
Definition Point.hpp:214
static std::pair< double, double > get_wipe_tower_cone_base(double width, double height, double depth, double angle_deg)
Definition WipeTower2.cpp:2151
float width() const
Definition WipeTower2.hpp:144
Slic3r::Polygons union_(const Slic3r::Polygons &subject)
Definition ClipperUtils.cpp:801
std::vector< Polygon, PointsAllocator< Polygon > > Polygons
Definition Polygon.hpp:22
Slic3r::Polygon Polygon
Definition Emboss.cpp:101

References Slic3r::center(), EPSILON, get_wipe_tower_cone_base(), M_PI, Slic3r::Point::new_scale(), Slic3r::MultiPoint::points, Slic3r::union_(), and width().

Referenced by Slic3r::WipeTowerData::construct_mesh(), and Slic3r::estimate_wipe_tower_first_layer_outline().

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

◆ construct_tcr()

WipeTower::ToolChangeResult Slic3r::WipeTower2::construct_tcr ( WipeTowerWriter2 & writer,
bool priming,
size_t old_tool,
bool is_finish,
bool is_contact = false ) const
1005{
1006 WipeTower::ToolChangeResult result;
1007 result.priming = priming;
1008 result.initial_tool = int(old_tool);
1009 result.new_tool = int(m_current_tool);
1010 result.print_z = m_z_pos;
1011 result.layer_height = m_layer_height;
1012 result.elapsed_time = writer.elapsed_time();
1013 result.start_pos = writer.start_pos_rotated();
1014 result.end_pos = priming ? writer.pos() : writer.pos_rotated();
1015 result.gcode = std::move(writer.gcode());
1016 result.extrusions = std::move(writer.extrusions());
1017 result.wipe_path = std::move(writer.wipe_path());
1018 result.is_finish_first = is_finish;
1019 result.is_contact = is_contact;
1020 // ORCA: Always initialize the tool_change_start_pos with a valid position
1021 // to avoid undefined variable travel on X in Gcode.cpp function std::string WipeTowerIntegration::post_process_wipe_tower_moves
1022 result.tool_change_start_pos = result.start_pos; // always valid fallback
1023
1024 return result;
1025}
float m_layer_height
Definition WipeTower2.hpp:243

References Slic3r::WipeTower::ToolChangeResult::elapsed_time, Slic3r::WipeTowerWriter2::elapsed_time(), Slic3r::WipeTower::ToolChangeResult::end_pos, Slic3r::WipeTower::ToolChangeResult::extrusions, Slic3r::WipeTowerWriter2::extrusions(), Slic3r::WipeTower::ToolChangeResult::gcode, Slic3r::WipeTowerWriter2::gcode(), Slic3r::WipeTower::ToolChangeResult::initial_tool, Slic3r::WipeTower::ToolChangeResult::is_contact, Slic3r::WipeTower::ToolChangeResult::is_finish_first, Slic3r::WipeTower::ToolChangeResult::layer_height, m_current_tool, m_layer_height, m_z_pos, Slic3r::WipeTower::ToolChangeResult::new_tool, Slic3r::WipeTowerWriter2::pos(), Slic3r::WipeTowerWriter2::pos_rotated(), Slic3r::WipeTower::ToolChangeResult::priming, Slic3r::WipeTower::ToolChangeResult::print_z, Slic3r::WipeTower::ToolChangeResult::start_pos, Slic3r::WipeTowerWriter2::start_pos_rotated(), Slic3r::WipeTower::ToolChangeResult::tool_change_start_pos, Slic3r::WipeTower::ToolChangeResult::wipe_path, and Slic3r::WipeTowerWriter2::wipe_path().

Referenced by finish_layer(), prime(), and tool_change().

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

◆ estimate_semm_flush_volume()

float Slic3r::WipeTower2::estimate_semm_flush_volume ( const ConfigBase & config,
size_t filaments_cnt )
static
2233{
2234 const std::vector<std::vector<float>> wipe_volumes = extract_wipe_volumes(config);
2235 if (wipe_volumes.empty()) // an empty flush matrix would make the average below 0/0
2236 return 0.f;
2237 float maximum = 0.f;
2238 for (const std::vector<float> &v : wipe_volumes)
2239 maximum += *std::max_element(v.begin(), v.end());
2240 maximum = maximum * filaments_cnt / wipe_volumes.size();
2241
2242 // Orca: it's overshooting a bit, so let's reduce it a bit
2243 maximum *= 0.6;
2244 return maximum;
2245}
static std::vector< std::vector< float > > extract_wipe_volumes(const ConfigBase &config)
Definition WipeTower2.cpp:2187

References extract_wipe_volumes(), and wipe_volumes.

Referenced by Slic3r::estimate_wipe_tower_footprint().

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

◆ extract_wipe_volumes()

std::vector< std::vector< float > > Slic3r::WipeTower2::extract_wipe_volumes ( const ConfigBase & config)
static
2188{
2189 // flush_volumes_matrix holds one filaments x filaments block per nozzle (written by
2190 // PresetBundle::update_multi_material_filament_presets), so the filament count is
2191 // sqrt(size / nozzles). One tower serves every nozzle and the filament to nozzle assignment is
2192 // only decided later by ToolOrdering, so fold the blocks with std::max: the depth reserved here
2193 // has to cover the worst nozzle. With a single nozzle the fold has one term.
2194 const std::vector<double> &raw_matrix = config.option<ConfigOptionFloats>("flush_volumes_matrix")->values;
2195 const auto *nozzle_diameter = config.option<ConfigOptionFloats>("nozzle_diameter");
2196 size_t nozzle_nums = (nozzle_diameter == nullptr || nozzle_diameter->values.empty()) ? 1 : nozzle_diameter->values.size();
2197 unsigned int number_of_extruders = (unsigned int)(sqrt(raw_matrix.size() / nozzle_nums) + EPSILON);
2198 if (size_t(number_of_extruders) * number_of_extruders * nozzle_nums != raw_matrix.size()) {
2199 // Saved for a different nozzle count (older project, or the printer was just switched):
2200 // fall back to reading the whole option as one block, as this did before.
2201 nozzle_nums = 1;
2202 number_of_extruders = (unsigned int)(sqrt(raw_matrix.size()) + EPSILON);
2203 }
2204
2205 // The values shall only be used when SEMM is enabled. The purging for other printers
2206 // is determined by filament_minimal_purge_on_wipe_tower.
2207 const bool purge = config.option<ConfigOptionBool>("purge_in_prime_tower")->value
2208 && config.option<ConfigOptionBool>("single_extruder_multi_material")->value;
2209
2210 // Extract purging volumes for each extruder pair, each nozzle's block scaled by its own multiplier:
2211 std::vector<std::vector<float>> wipe_volumes(number_of_extruders, std::vector<float>(number_of_extruders, 0.f));
2212 if (purge) {
2213 const auto *multiplier = config.option<ConfigOptionFloats>("flush_multiplier");
2214 for (size_t nozzle_id = 0; nozzle_id < nozzle_nums; ++nozzle_id) {
2215 const std::vector<double> block = get_flush_volumes_matrix(raw_matrix, nozzle_id, nozzle_nums);
2216 const double scale = multiplier->get_at(nozzle_id);
2217 for (unsigned int i = 0; i<number_of_extruders; ++i)
2218 for (unsigned int j = 0; j<number_of_extruders; ++j)
2219 wipe_volumes[i][j] = std::max<float>(wipe_volumes[i][j], float(block[size_t(i) * number_of_extruders + j]) * scale);
2220 }
2221 }
2222
2223 // Also include filament_minimal_purge_on_wipe_tower. This is needed for the preview.
2224 const auto *minimal_purge = config.option<ConfigOptionFloats>("filament_minimal_purge_on_wipe_tower");
2225 for (unsigned int i = 0; i<number_of_extruders; ++i)
2226 for (unsigned int j = 0; j<number_of_extruders; ++j)
2227 wipe_volumes[i][j] = std::max<float>(wipe_volumes[i][j], minimal_purge->get_at(j));
2228
2229 return wipe_volumes;
2230}
int scale(const int val)
Definition WipeTowerDialog.cpp:58
std::vector< double > values
Definition Config.hpp:418
zaa_minimize_perimeter_height nozzle_diameter((ConfigOptionBool, reduce_infill_retraction))((ConfigOptionBool
static std::vector< T > get_flush_volumes_matrix(const std::vector< T > &fv_matrix, size_t extruder_id=-1, size_t nozzle_nums=1)
Definition PrintConfig.hpp:2685
ConfigOptionFloatsTempl< false > ConfigOptionFloats
Definition Config.hpp:1015

References EPSILON, Slic3r::get_flush_volumes_matrix(), Slic3r::nozzle_diameter(), Slic3r::ConfigBase::option(), scale(), Slic3r::ConfigOptionSingle< T >::value, and wipe_volumes.

Referenced by estimate_semm_flush_volume().

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

◆ extrusion_flow()

float Slic3r::WipeTower2::extrusion_flow ( float layer_height = -1.f) const
inlineprivate
351 {
352 if ( layer_height < 0 )
353 return m_extrusion_flow;
354 return layer_height * ( m_perimeter_width - layer_height * (1.f-float(M_PI)/4.f)) / filament_area();
355 }
float m_perimeter_width
Definition WipeTower2.hpp:294
float filament_area() const
Definition WipeTower2.hpp:222
float m_extrusion_flow
Definition WipeTower2.hpp:295
layer_height((ConfigOptionInt, faded_layers))((ConfigOptionFloat

References filament_area(), Slic3r::layer_height(), m_extrusion_flow, m_perimeter_width, and M_PI.

Referenced by set_layer().

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

◆ filament_area()

float Slic3r::WipeTower2::filament_area ( ) const
inlineprivate
222 {
223 return m_filpar[0].filament_area; // all extruders are assumed to have the same filament diameter at this point
224 }
std::vector< FilamentParameters > m_filpar
Definition WipeTower2.hpp:298

References m_filpar.

Referenced by extrusion_flow(), set_extruder(), and toolchange_Unload().

Here is the caller graph for this function:

◆ finish_layer()

WipeTower::ToolChangeResult Slic3r::WipeTower2::finish_layer ( )
1991{
1992 assert(! this->layer_finished());
1994
1995 size_t old_tool = m_current_tool;
1996
1998 writer.set_extrusion_flow(m_extrusion_flow)
1999 .set_z(m_z_pos)
2000 .set_initial_tool(m_current_tool)
2001 .set_y_shift(m_y_shift - (m_current_shape == SHAPE_REVERSED ? m_layer_info->toolchanges_depth() : 0.f));
2002
2003
2004 // Slow down on the 1st layer.
2005 // If spare layers are excluded -> if 1 or less toolchange has been done, it must be still the first layer, too. So slow down.
2006 bool first_layer = is_first_layer() || (m_num_tool_changes <= 1 && m_sparse_layers_skipped);
2007 float feedrate = first_layer ? m_first_layer_speed * 60.f : std::min(m_wipe_tower_max_purge_speed * 60.f, m_infill_speed * 60.f);
2009 feedrate = std::min(feedrate, 20.f * 60.f);
2010 float current_depth = m_layer_info->depth - m_layer_info->toolchanges_depth();
2011 WipeTower::box_coordinates fill_box(Vec2f(m_perimeter_width, m_layer_info->depth-(current_depth-m_perimeter_width)),
2013
2014
2015 writer.set_initial_position((m_left_to_right ? fill_box.ru : fill_box.lu), // so there is never a diagonal travel
2017
2018 bool toolchanges_on_layer = m_layer_info->toolchanges_depth() > WT_EPSILON;
2019
2020 // inner perimeter of the sparse section, if there is space for it:
2021 if (fill_box.ru.y() - fill_box.rd.y() > m_perimeter_width - WT_EPSILON)
2022 writer.rectangle(fill_box.ld, fill_box.rd.x()-fill_box.ld.x(), fill_box.ru.y()-fill_box.rd.y(), feedrate);
2023
2024 // we are in one of the corners, travel to ld along the perimeter:
2025 if (writer.x() > fill_box.ld.x()+EPSILON) writer.travel(fill_box.ld.x(),writer.y());
2026 if (writer.y() > fill_box.ld.y()+EPSILON) writer.travel(writer.x(),fill_box.ld.y());
2027
2028 // Extrude infill to support the material to be printed above.
2029 const float dy = (fill_box.lu.y() - fill_box.ld.y() - m_perimeter_width);
2030 float left = fill_box.lu.x() + 2*m_perimeter_width;
2031 float right = fill_box.ru.x() - 2 * m_perimeter_width;
2032 if (dy > m_perimeter_width)
2033 {
2034 writer.travel(fill_box.ld + Vec2f(m_perimeter_width * 2, 0.f))
2035 .append(";--------------------\n"
2036 "; CP EMPTY GRID START\n")
2037 .comment_with_value(" layer #", m_num_layer_changes + 1);
2038
2039 // Is there a soluble filament wiped/rammed at the next layer?
2040 // If so, the infill should not be sparse.
2041 bool solid_infill = m_layer_info+1 == m_plan.end()
2042 ? false
2043 : std::any_of((m_layer_info+1)->tool_changes.begin(),
2044 (m_layer_info+1)->tool_changes.end(),
2045 [this](const WipeTowerInfo::ToolChange& tch) {
2046 return m_filpar[tch.new_tool].is_soluble
2047 || m_filpar[tch.old_tool].is_soluble;
2048 });
2049 solid_infill |= first_layer && m_adhesion;
2050
2051 if (solid_infill) {
2052 float sparse_factor = 1.5f; // 1=solid, 2=every other line, etc.
2053 if (first_layer) { // the infill should touch perimeters
2056 sparse_factor = 1.f;
2057 }
2058 float y = fill_box.ld.y() + m_perimeter_width;
2059 int n = dy / (m_perimeter_width * sparse_factor);
2060 float spacing = (dy-m_perimeter_width)/(n-1);
2061 int i=0;
2062 for (i=0; i<n; ++i) {
2063 writer.extrude(writer.x(), y, feedrate)
2064 .extrude(i%2 ? left : right, y);
2065 y = y + spacing;
2066 }
2067 writer.extrude(writer.x(), fill_box.lu.y());
2068 } else {
2069 // Extrude an inverse U at the left of the region and the sparse infill.
2070 writer.extrude(fill_box.lu + Vec2f(m_perimeter_width * 2, 0.f), feedrate);
2071
2072 const int n = 1+int((right-left)/m_bridging);
2073 const float dx = (right-left)/n;
2074 for (int i=1;i<=n;++i) {
2075 float x=left+dx*i;
2076 writer.travel(x,writer.y());
2077 writer.extrude(x,i%2 ? fill_box.rd.y() : fill_box.ru.y());
2078 }
2079 }
2080
2081 writer.append("; CP EMPTY GRID END\n"
2082 ";------------------\n\n\n\n\n\n\n");
2083 }
2084
2085 const float spacing = m_perimeter_width - m_layer_height*float(1.-M_PI_4);
2086 feedrate = first_layer ? m_first_layer_speed * 60.f : std::min(m_wipe_tower_max_purge_speed * 60.f, m_perimeter_speed * 60.f);
2087
2088 Polygon poly;
2089 if (m_wall_type == (int)wtwCone) {
2090 WipeTower::box_coordinates wt_box(Vec2f(0.f, (m_current_shape == SHAPE_REVERSED ? m_layer_info->toolchanges_depth() : 0.f)),
2092 // outer contour (always)
2093 bool infill_cone = first_layer && m_wipe_tower_width > 2 * spacing && m_wipe_tower_depth > 2 * spacing;
2094 poly = generate_support_cone_wall(writer, wt_box, feedrate, infill_cone, spacing);
2095 } else {
2096 WipeTower::box_coordinates wt_box(Vec2f(0.f, 0.f), m_wipe_tower_width, m_layer_info->depth + m_perimeter_width);
2097 poly = generate_support_rib_wall(writer, wt_box, feedrate, first_layer, m_wall_type == (int)wtwRib, true);
2098 }
2099
2100 // brim (first layer only)
2101 if (first_layer) {
2102 writer.append("; WIPE_TOWER_BRIM_START\n");
2103 float brim_width = m_wipe_tower_brim_width;
2104 if (brim_width < 0.f)
2106
2107 size_t loops_num = (brim_width + spacing / 2.f) / spacing;
2108
2109 for (size_t i = 0; i < loops_num; ++ i) {
2110 poly = offset(poly, scale_(spacing)).front();
2111 int cp = poly.closest_point_index(Point::new_scale(writer.x(), writer.y()));
2112 writer.travel(unscale(poly.points[cp]).cast<float>());
2113 for (int i=cp+1; true; ++i ) {
2114 if (i==int(poly.points.size()))
2115 i = 0;
2116 writer.extrude(unscale(poly.points[i]).cast<float>());
2117 if (i == cp)
2118 break;
2119 }
2120 }
2121 writer.append("; WIPE_TOWER_BRIM_END\n");
2122 // Save actual brim width to be later passed to the Print object, which will use it
2123 // for skirt calculation and pass it to GLCanvas for precise preview box
2124 m_wipe_tower_brim_width_real = loops_num * spacing;
2125
2126 // Compute actual first-layer bounding box from the outermost brim polygon,
2127 // matching how WipeTower::get_bbx() uses m_outer_wall extents.
2128 BoundingBox first_layer_box = get_extents(poly);
2129 m_first_layer_bbx = BoundingBoxf(unscale(first_layer_box.min), unscale(first_layer_box.max));
2130 }
2131
2132 // Now prepare future wipe.
2133 int i = poly.closest_point_index(Point::new_scale(writer.x(), writer.y()));
2134 writer.add_wipe_point(writer.pos());
2135 writer.add_wipe_point(unscale(poly.points[i==0 ? int(poly.points.size())-1 : i-1]).cast<float>());
2136
2137 // Ask our writer about how much material was consumed.
2138 // Skip this in case the layer is sparse and config option to not print sparse layers is enabled.
2139 // A folded layer prints nothing, so it consumes nothing and adds no height of its own.
2140 const bool combined_away = m_layer_info != m_plan.end() && m_layer_info->combined_away;
2141 if ((! m_sparse_layers_skipped || toolchanges_on_layer || first_layer) && ! combined_away) {
2143 m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length();
2144 m_current_height += m_layer_info->height;
2145 }
2146
2147 return construct_tcr(writer, false, old_tool, true, false);
2148}
bool m_left_to_right
Definition WipeTower2.hpp:311
std::vector< float > m_used_filament_length
Definition WipeTower2.hpp:398
float m_wipe_tower_depth
Definition WipeTower2.hpp:233
float m_current_height
Definition WipeTower2.hpp:395
WipeTower::ToolChangeResult construct_tcr(WipeTowerWriter2 &writer, bool priming, size_t old_tool, bool is_finish, bool is_contact=false) const
Definition WipeTower2.cpp:1000
wipe_shape m_current_shape
Definition WipeTower2.hpp:305
unsigned int m_num_layer_changes
Definition WipeTower2.hpp:301
bool layer_finished() const
Definition WipeTower2.hpp:167
unsigned int m_num_tool_changes
Definition WipeTower2.hpp:302
float m_wipe_tower_height
Definition WipeTower2.hpp:234
float m_internal_rotation
Definition WipeTower2.hpp:240
const float WT_EPSILON
Definition WipeTower2.hpp:221
std::vector< WipeTowerInfo >::iterator m_layer_info
Definition WipeTower2.hpp:391
bool m_prev_layer_had_interface
Definition WipeTower2.hpp:255
Polygon generate_support_rib_wall(WipeTowerWriter2 &writer, const WipeTower::box_coordinates &wt_box, double feedrate, bool first_layer, bool rib_wall, bool extrude_perimeter)
Definition WipeTower2.cpp:2638
bool m_adhesion
Definition WipeTower2.hpp:281
float m_wipe_tower_brim_width_real
Definition WipeTower2.hpp:237
bool is_first_layer() const
Definition WipeTower2.hpp:316
bool m_current_layer_finished
Definition WipeTower2.hpp:310
BoundingBoxf m_first_layer_bbx
Definition WipeTower2.hpp:238
Polygon generate_support_cone_wall(WipeTowerWriter2 &writer, const WipeTower::box_coordinates &wt_box, double feedrate, bool infill_cone, float spacing)
Definition WipeTower2.cpp:2692
static float get_auto_brim_by_height(float max_height)
Definition WipeTower.cpp:1733
#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
BoundingBox get_extents(const ExPolygonsWithIds &e)
Definition Emboss.cpp:1374
Slic3r::Polygons offset(const Slic3r::Polygon &polygon, const float delta, JoinType joinType, double miterLimit)
Definition ClipperUtils.cpp:582
T unscale(Q v)
Definition libslic3r.h:138
@ wtwRib
Definition PrintConfig.hpp:608
@ wtwCone
Definition PrintConfig.hpp:607
@ right
Definition MarchingSquares.hpp:190
@ left
Definition MarchingSquares.hpp:188

References Slic3r::WipeTowerWriter2::add_wipe_point(), Slic3r::WipeTowerWriter2::append(), Slic3r::WipeTowerWriter2::comment_with_value(), construct_tcr(), EPSILON, Slic3r::WipeTowerWriter2::extrude(), generate_support_cone_wall(), generate_support_rib_wall(), Slic3r::WipeTowerWriter2::get_and_reset_used_filament_length(), Slic3r::WipeTower::get_auto_brim_by_height(), Slic3r::get_extents(), is_first_layer(), layer_finished(), Slic3r::WipeTower::box_coordinates::ld, Slic3r::WipeTower::box_coordinates::lu, m_adhesion, m_bridging, m_current_height, m_current_layer_finished, m_current_shape, m_current_tool, m_enable_arc_fitting, m_enable_tower_interface_features, m_extrusion_flow, m_filpar, m_first_layer_bbx, m_first_layer_speed, m_gcode_flavor, m_infill_speed, m_internal_rotation, m_layer_height, m_layer_info, m_left_to_right, m_num_layer_changes, m_num_tool_changes, m_perimeter_speed, m_perimeter_width, m_plan, m_prev_layer_had_interface, m_sparse_layers_skipped, m_used_filament_length, m_wall_type, m_wipe_tower_brim_width, m_wipe_tower_brim_width_real, m_wipe_tower_depth, m_wipe_tower_height, m_wipe_tower_max_purge_speed, m_wipe_tower_width, m_y_shift, m_z_pos, Slic3r::BoundingBoxBase< PointType, APointsType >::max, Slic3r::BoundingBoxBase< PointType, APointsType >::min, Slic3r::Point::new_scale(), Slic3r::offset(), Slic3r::WipeTowerWriter2::pos(), Slic3r::WipeTower::box_coordinates::rd, Slic3r::WipeTowerWriter2::rectangle(), Slic3r::WipeTower::box_coordinates::ru, scale_, Slic3r::WipeTowerWriter2::set_extrusion_flow(), Slic3r::WipeTowerWriter2::set_initial_position(), Slic3r::WipeTowerWriter2::set_initial_tool(), Slic3r::WipeTowerWriter2::set_y_shift(), Slic3r::WipeTowerWriter2::set_z(), SHAPE_REVERSED, Slic3r::WipeTowerWriter2::travel(), Slic3r::unscale(), WT_EPSILON, Slic3r::wtwCone, Slic3r::wtwRib, Slic3r::WipeTowerWriter2::x(), and Slic3r::WipeTowerWriter2::y().

Referenced by generate(), and save_on_last_wipe().

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

◆ finished()

bool Slic3r::WipeTower2::finished ( ) const
inline
146{ return m_max_color_changes == 0; }
size_t m_max_color_changes
Definition WipeTower2.hpp:244

References m_max_color_changes.

◆ first_toolchange_to_nonsoluble_nonsupport()

int Slic3r::WipeTower2::first_toolchange_to_nonsoluble_nonsupport ( const std::vector< WipeTowerInfo::ToolChange > & tool_changes) const
private
2401{
2402 if (tool_changes.empty())
2403 return -1;
2404
2405 // If a specific wipe tower filament is forced, use it to decide where to finish the layer.
2406 if (m_wipe_tower_filament > 0) {
2407 for (size_t idx = 0; idx < tool_changes.size(); ++idx) {
2408 if (!m_filpar[tool_changes[idx].new_tool].is_soluble)
2409 return idx;
2410 }
2411 return -1;
2412 }
2413
2414 auto is_wall_filament = [this](size_t tool) {
2415 return !m_filpar[tool].is_soluble && !m_filpar[tool].is_support;
2416 };
2417 for (size_t idx = 0; idx < tool_changes.size(); ++idx)
2418 if (is_wall_filament(tool_changes[idx].new_tool))
2419 return idx;
2420 if (is_wall_filament(tool_changes.front().old_tool))
2421 return -1;
2422 // Only support/soluble filaments on this layer: keep the first toolchange so the
2423 // finish-layer saving and the minimal-purge clamp still apply to it (Orca depth
2424 // and wipe volume accounting, see save_on_last_wipe()).
2425 return 0;
2426}

References m_filpar, and m_wipe_tower_filament.

Referenced by generate(), and save_on_last_wipe().

Here is the caller graph for this function:

◆ generate()

void Slic3r::WipeTower2::generate ( std::vector< std::vector< WipeTower::ToolChangeResult > > & result)
2469{
2470 if (m_plan.empty())
2471 return;
2472
2473 // Before planning: the layer heights this rewrites feed the extrusion flow of every later pass.
2476
2477 plan_tower();
2478#if 1
2479 for (int i=0;i<5;++i) {
2481 plan_tower();
2482 }
2483#endif
2484
2485 if (m_wall_type == (int)wtwRib) {
2486 // Rib wall: force a square tower like WipeTower::plan_tower_new(), ignoring the
2487 // configured prime_tower_width (the GUI greys it out in rib mode). The planned depths
2488 // already include the extra-spacing factors, so sqrt(depth * width) preserves the
2489 // purge area. Replan every toolchange for the new width, then re-derive the depths.
2490 float max_depth = 0.f;
2491 for (const auto& current_plan : m_plan)
2492 max_depth = std::max(max_depth, current_plan.depth);
2493 if (max_depth > EPSILON) {
2495 for (size_t idx = 0; idx < m_plan.size(); ++idx)
2496 for (auto& toolchange : m_plan[idx].tool_changes)
2497 toolchange = set_toolchange(toolchange.old_tool, toolchange.new_tool,
2498 m_plan[idx].height, toolchange.wipe_volume,
2499 idx == m_first_layer_idx);
2500 plan_tower();
2501 }
2502
2503 // Like WipeTower::plan_tower_new(): extend the ribs instead of the tower when the
2504 // tower is smaller than the height-based stability minimum.
2506 if (m_wipe_tower_depth + EPSILON < min_depth)
2507 m_rib_length = std::max(m_rib_length, min_depth * (float)std::sqrt(2.f));
2508 }
2509
2510 const float diagonal = std::sqrt(m_wipe_tower_depth * m_wipe_tower_depth + m_wipe_tower_width * m_wipe_tower_width);
2511 m_rib_length = std::max(m_rib_length, diagonal);
2513 m_rib_length = std::max(diagonal, m_rib_length); // a negative extra length must not shrink the ribs below the diagonal
2515 2.f); // Ensure that the rib wall of the wipetower are attached to the infill.
2516
2517 if (m_use_gap_wall)
2519
2520 m_layer_info = m_plan.begin();
2521 m_current_height = 0.f;
2522
2523 // we don't know which extruder to start with - we'll set it according to the first toolchange
2524 for (const auto& layer : m_plan) {
2525 if (!layer.tool_changes.empty()) {
2526 m_current_tool = layer.tool_changes.front().old_tool;
2527 break;
2528 }
2529 }
2530
2531 m_used_filament_length.assign(m_used_filament_length.size(), 0.f); // reset used filament stats
2532 assert(m_used_filament_length_until_layer.empty());
2534
2535 m_old_temperature = -1; // reset last temperature written in the gcode
2536
2537 for (const WipeTower2::WipeTowerInfo& layer : m_plan)
2538 {
2539 std::vector<WipeTower::ToolChangeResult> layer_result;
2540 set_layer(layer.z, layer.height, 0, false/*layer.z == m_plan.front().z*/, layer.z == m_plan.back().z);
2541 m_internal_rotation += 180.f;
2542
2545
2546 int idx = first_toolchange_to_nonsoluble_nonsupport(layer.tool_changes);
2547 WipeTower::ToolChangeResult finish_layer_tcr;
2548
2549 if (idx == -1) {
2550 // if there is no toolchange switching to non-soluble, finish layer
2551 // will be called at the very beginning. That's the last possibility
2552 // where a nonsoluble tool can be.
2553 finish_layer_tcr = finish_layer();
2554 }
2555
2556 for (int i=0; i<int(layer.tool_changes.size()); ++i) {
2557 layer_result.emplace_back(tool_change(layer.tool_changes[i].new_tool));
2558 if (i == idx) // finish_layer will be called after this toolchange
2559 finish_layer_tcr = finish_layer();
2560 }
2561
2562 if (layer_result.empty()) {
2563 // there is nothing to merge finish_layer with
2564 layer_result.emplace_back(std::move(finish_layer_tcr));
2565 }
2566 else {
2567 if (idx == -1) {
2568 layer_result[0] = merge_tcr(finish_layer_tcr, layer_result[0]);
2569 layer_result[0].force_travel = true;
2570 }
2571 else
2572 layer_result[idx] = merge_tcr(layer_result[idx], finish_layer_tcr);
2573 }
2574
2575 if (layer.combined_away)
2576 for (WipeTower::ToolChangeResult &tcr : layer_result)
2577 tcr.combined_away = true;
2578
2579 result.emplace_back(std::move(layer_result));
2580
2581 if (m_used_filament_length_until_layer.empty() || m_used_filament_length_until_layer.back().first != layer.z)
2583 m_used_filament_length_until_layer.back() = std::make_pair(layer.z, m_used_filament_length);
2584 }
2585}
void set_layer(float print_z, float layer_height, size_t max_tool_changes, bool, bool is_last_layer)
Definition WipeTower2.hpp:105
int first_toolchange_to_nonsoluble_nonsupport(const std::vector< WipeTowerInfo::ToolChange > &tool_changes) const
Definition WipeTower2.cpp:2399
void save_on_last_wipe()
Definition WipeTower2.cpp:2339
WipeTower::ToolChangeResult finish_layer()
Definition WipeTower2.cpp:1990
WipeTower::ToolChangeResult tool_change(size_t new_tool)
Definition WipeTower2.cpp:1330
int m_old_temperature
Definition WipeTower2.hpp:245
void plan_tower()
Definition WipeTower2.cpp:2314
WipeTowerInfo::ToolChange set_toolchange(size_t old_tool, size_t new_tool, float layer_height, float wipe_volume, bool first_layer_plan)
Definition WipeTower2.cpp:2275
std::vector< std::pair< float, std::vector< float > > > m_used_filament_length_until_layer
Definition WipeTower2.hpp:399
void compute_wall_skip_points()
Definition WipeTower2.cpp:2453
float m_rib_length
Definition WipeTower2.hpp:262
static float get_limit_depth_by_height(float max_height)
Definition WipeTower.cpp:1697
float align_ceil(float value, float base)
Definition WipeTower.cpp:124
void combine_sparse_wipe_tower_plan(PlanLayers &plan, const FilamentParams &filpar, size_t first_layer_idx, size_t initial_tool)
Definition WipeTower.hpp:747
static WipeTower::ToolChangeResult merge_tcr(WipeTower::ToolChangeResult &first, WipeTower::ToolChangeResult &second)
Definition WipeTower2.cpp:2428

References Slic3r::align_ceil(), Slic3r::combine_sparse_wipe_tower_plan(), Slic3r::WipeTower::ToolChangeResult::combined_away, compute_wall_skip_points(), EPSILON, finish_layer(), first_toolchange_to_nonsoluble_nonsupport(), Slic3r::WipeTower::get_limit_depth_by_height(), m_current_height, m_current_tool, m_extra_rib_length, m_filpar, m_first_layer_idx, m_internal_rotation, m_layer_info, m_old_temperature, m_perimeter_width, m_plan, m_rib_length, m_rib_width, m_sparse_layers_combined, m_use_gap_wall, m_used_filament_length, m_used_filament_length_until_layer, m_wall_type, m_wipe_tower_depth, m_wipe_tower_height, m_wipe_tower_width, m_y_shift, Slic3r::merge_tcr(), plan_tower(), save_on_last_wipe(), set_layer(), set_toolchange(), tool_change(), and Slic3r::wtwRib.

Referenced by Slic3r::Print::_make_wipe_tower().

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

◆ generate_rib_polygon()

Polygon Slic3r::WipeTower2::generate_rib_polygon ( const WipeTower::box_coordinates & wt_box)
private
2604{
2605
2606 auto get_current_layer_rib_len = [](float cur_height, float max_height, float max_len) -> float {
2607 return std::abs(max_height - cur_height) / max_height * max_len;
2608 };
2609 coord_t diagonal_width = scaled(m_rib_width) / 2;
2610 float a = this->m_wipe_tower_width, b = this->m_wipe_tower_depth;
2611 Line line_1(Point::new_scale(Vec2f{0, 0}), Point::new_scale(Vec2f{a, b}));
2612 Line line_2(Point::new_scale(Vec2f{a, 0}), Point::new_scale(Vec2f{0, b}));
2613 float diagonal_extra_length = std::max(0.f, m_rib_length - (float) unscaled(line_1.length())) / 2.f;
2614 diagonal_extra_length = scaled(get_current_layer_rib_len(this->m_z_pos, this->m_wipe_tower_height, diagonal_extra_length));
2615 Point y_shift{0, scaled(this->m_y_shift)};
2616
2617 line_1.extend(double(diagonal_extra_length));
2618 line_2.extend(double(diagonal_extra_length));
2619 line_1.translate(-y_shift);
2620 line_2.translate(-y_shift);
2621
2622 Polygon poly_1 = generate_rectange(line_1, diagonal_width);
2623 Polygon poly_2 = generate_rectange(line_2, diagonal_width);
2624 Polygon poly;
2625 poly.points.push_back(Point::new_scale(wt_box.ld));
2626 poly.points.push_back(Point::new_scale(wt_box.rd));
2627 poly.points.push_back(Point::new_scale(wt_box.ru));
2628 poly.points.push_back(Point::new_scale(wt_box.lu));
2629
2630 Polygons p_1_2 = union_({poly_1, poly_2, poly});
2631 // Polygon res_poly = p_1_2.front();
2632 // for (auto &p : res_poly.points) res.push_back(unscale(p).cast<float>());
2633 /*if (p_1_2.front().points.size() != 16)
2634 std::cout << "error " << std::endl;*/
2635 return p_1_2.front();
2636};
int64_t coord_t
Definition libslic3r.h:48
Kernel::Point_3 Point
Definition MeshRepair.cpp:81
BoundingBox scaled(const BoundingBoxf &bb)
Definition BoundingBox.hpp:284
constexpr Eigen::Matrix< Tout, 2, EigenArgs... > unscaled(const Slic3r::Point &v) noexcept
Definition Arrange.cpp:81
Polygon generate_rectange(const Line &line, coord_t offset)
Definition WipeTower.cpp:359

References Slic3r::Line::extend(), Slic3r::generate_rectange(), Slic3r::WipeTower::box_coordinates::ld, Slic3r::Line::length(), Slic3r::WipeTower::box_coordinates::lu, m_rib_length, m_rib_width, m_wipe_tower_depth, m_wipe_tower_height, m_wipe_tower_width, m_y_shift, m_z_pos, Slic3r::Point::new_scale(), Slic3r::WipeTower::box_coordinates::rd, Slic3r::WipeTower::box_coordinates::ru, Slic3r::scaled(), Slic3r::Line::translate(), Slic3r::union_(), and Slic3r::unscaled().

Referenced by generate_support_rib_wall(), and toolchange_Change().

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

◆ generate_support_cone_wall()

Polygon Slic3r::WipeTower2::generate_support_cone_wall ( WipeTowerWriter2 & writer,
const WipeTower::box_coordinates & wt_box,
double feedrate,
bool infill_cone,
float spacing )
private
2693 {
2694
2697
2698 double z = m_sparse_layers_skipped ?
2699 (m_current_height + m_layer_info->height) :
2700 m_layer_info->z; // the former should actually work in both cases, but let's stay on the safe side (the 2.6.0 is close)
2701
2702 double r = std::tan(Geometry::deg2rad(m_wipe_tower_cone_angle / 2.f)) * (m_wipe_tower_height - z);
2703 Vec2f center = (wt_box.lu + wt_box.rd) / 2.;
2704 double w = wt_box.lu.y() - wt_box.ld.y();
2705 enum Type { Arc, Corner, ArcStart, ArcEnd };
2706
2707 // First generate vector of annotated point which form the boundary.
2708 std::vector<std::pair<Vec2f, Type>> pts = {{wt_box.ru, Corner}};
2709 if (double alpha_start = std::asin((0.5 * w) / r); !std::isnan(alpha_start) && r > 0.5 * w + 0.01) {
2710 for (double alpha = alpha_start; alpha < M_PI - alpha_start + 0.001; alpha += (M_PI - 2 * alpha_start) / 40.)
2711 pts.emplace_back(Vec2f(center.x() + r * std::cos(alpha) / support_scale, center.y() + r * std::sin(alpha)),
2712 alpha == alpha_start ? ArcStart : Arc);
2713 pts.back().second = ArcEnd;
2714 }
2715 pts.emplace_back(wt_box.lu, Corner);
2716 pts.emplace_back(wt_box.ld, Corner);
2717 for (int i = int(pts.size()) - 3; i > 0; --i)
2718 pts.emplace_back(Vec2f(pts[i].first.x(), 2 * center.y() - pts[i].first.y()), i == int(pts.size()) - 3 ? ArcStart :
2719 i == 1 ? ArcEnd :
2720 Arc);
2721 pts.emplace_back(wt_box.rd, Corner);
2722
2723 // Create a Polygon from the points.
2724 Polygon poly;
2725 for (const auto& [pt, tag] : pts)
2726 poly.points.push_back(Point::new_scale(pt));
2727
2728 // Prepare polygons to be filled by infill.
2729 Polylines polylines;
2730 if (infill_cone && m_wipe_tower_width > 2 * spacing && m_wipe_tower_depth > 2 * spacing) {
2731 ExPolygons infill_areas;
2732 ExPolygon wt_contour(poly);
2733 Polygon wt_rectangle(
2734 Points{Point::new_scale(wt_box.ld), Point::new_scale(wt_box.rd), Point::new_scale(wt_box.ru), Point::new_scale(wt_box.lu)});
2735 wt_rectangle = offset(wt_rectangle, scale_(-spacing / 2.)).front();
2736 wt_contour = offset_ex(wt_contour, scale_(-spacing / 2.)).front();
2737 infill_areas = diff_ex(wt_contour, wt_rectangle);
2738 if (infill_areas.size() == 2) {
2739 ExPolygon& bottom_expoly = infill_areas.front().contour.points.front().y() < infill_areas.back().contour.points.front().y() ?
2740 infill_areas[0] :
2741 infill_areas[1];
2742 std::unique_ptr<Fill> filler(Fill::new_from_type(ipMonotonicLine));
2743 filler->angle = Geometry::deg2rad(45.f);
2744 filler->spacing = spacing;
2745 FillParams params;
2746 params.density = 1.f;
2747 Surface surface(stBottom, bottom_expoly);
2748 filler->bounding_box = get_extents(bottom_expoly);
2749 polylines = filler->fill_surface(&surface, params);
2750 if (!polylines.empty()) {
2751 if (polylines.front().points.front().x() > polylines.back().points.back().x()) {
2752 std::reverse(polylines.begin(), polylines.end());
2753 for (Polyline& p : polylines)
2754 p.reverse();
2755 }
2756 }
2757 }
2758 }
2759
2760 // Find the closest corner and travel to it.
2761 int start_i = 0;
2762 double min_dist = std::numeric_limits<double>::max();
2763 for (int i = 0; i < int(pts.size()); ++i) {
2764 if (pts[i].second == Corner) {
2765 double dist = (pts[i].first - Vec2f(writer.x(), writer.y())).squaredNorm();
2766 if (dist < min_dist) {
2767 min_dist = dist;
2768 start_i = i;
2769 }
2770 }
2771 }
2772 writer.travel(pts[start_i].first);
2773
2774 // Now actually extrude the boundary (and possibly infill):
2775 int i = start_i + 1 == int(pts.size()) ? 0 : start_i + 1;
2776 while (i != start_i) {
2777 writer.extrude(pts[i].first, feedrate);
2778 if (pts[i].second == ArcEnd) {
2779 // Extrude the infill.
2780 if (!polylines.empty()) {
2781 // Extrude the infill and travel back to where we were.
2782 bool mirror = ((pts[i].first.y() - center.y()) * (unscale(polylines.front().points.front()).y() - center.y())) < 0.;
2783 for (const Polyline& line : polylines) {
2784 writer.travel(center - (mirror ? 1.f : -1.f) * (unscale(line.points.front()).cast<float>() - center));
2785 for (size_t i = 0; i < line.points.size(); ++i)
2786 writer.extrude(center - (mirror ? 1.f : -1.f) * (unscale(line.points[i]).cast<float>() - center));
2787 }
2788 writer.travel(pts[i].first);
2789 }
2790 }
2791 if (++i == int(pts.size()))
2792 i = 0;
2793 }
2794 writer.extrude(pts[start_i].first, feedrate);
2795 return poly;
2796}
static Fill * new_from_type(const InfillPattern type)
Definition FillBase.cpp:65
Type
Definition CustomGCode.hpp:18
T dist(const boost::polygon::point_data< T > &p1, const boost::polygon::point_data< T > &p2)
Definition Geometry.cpp:298
constexpr T deg2rad(const T angle)
Definition Geometry.hpp:312
@ ipMonotonicLine
Definition PrintConfig.hpp:127
Slic3r::ExPolygons diff_ex(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset)
Definition ClipperUtils.cpp:831
std::vector< ExPolygon > ExPolygons
Definition ExPolygon.hpp:20
std::vector< Polyline > Polylines
Definition Polyline.hpp:22
Slic3r::ExPolygons offset_ex(const Slic3r::Polygons &polygons, const float delta, JoinType joinType, double miterLimit)
Definition ClipperUtils.cpp:605
std::vector< Point, PointsAllocator< Point > > Points
Definition Point.hpp:73
@ stBottom
Definition Surface.hpp:20

References Slic3r::center(), Slic3r::Geometry::deg2rad(), Slic3r::FillParams::density, Slic3r::diff_ex(), Slic3r::Geometry::dist(), Slic3r::WipeTowerWriter2::extrude(), Slic3r::get_extents(), get_wipe_tower_cone_base(), Slic3r::ipMonotonicLine, Slic3r::WipeTower::box_coordinates::ld, Slic3r::WipeTower::box_coordinates::lu, m_current_height, m_layer_info, M_PI, m_sparse_layers_skipped, m_wipe_tower_cone_angle, m_wipe_tower_depth, m_wipe_tower_height, m_wipe_tower_width, Slic3r::Fill::new_from_type(), Slic3r::Point::new_scale(), Slic3r::offset(), Slic3r::offset_ex(), Slic3r::WipeTower::box_coordinates::rd, Slic3r::WipeTower::box_coordinates::ru, scale_, Slic3r::stBottom, Slic3r::WipeTowerWriter2::travel(), Slic3r::unscale(), Slic3r::WipeTowerWriter2::x(), and Slic3r::WipeTowerWriter2::y().

Referenced by finish_layer().

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

◆ generate_support_rib_wall()

Polygon Slic3r::WipeTower2::generate_support_rib_wall ( WipeTowerWriter2 & writer,
const WipeTower::box_coordinates & wt_box,
double feedrate,
bool first_layer,
bool rib_wall,
bool extrude_perimeter )
private
2644{
2645
2646 float retract_length = m_filpar[m_current_tool].retract_length;
2647 float retract_speed = m_filpar[m_current_tool].retract_speed * 60;
2648 Polygon wall_polygon = rib_wall ? generate_rib_polygon(wt_box) : generate_rectange_polygon(wt_box.ld, wt_box.ru);
2649 Polylines result_wall;
2650 Polygon insert_skip_polygon;
2651 if (m_used_fillet) {
2652 if (!rib_wall && m_y_shift > EPSILON) // do nothing because the fillet will cause it to be suspended.
2653 {
2654 } else {
2655 wall_polygon = rib_wall ? rounding_polygon(wall_polygon) : wall_polygon; // rectangle_wall do nothing
2656 Polygon wt_box_polygon = generate_rectange_polygon(wt_box.ld, wt_box.ru);
2657 wall_polygon = union_({wall_polygon, wt_box_polygon}).front();
2658 }
2659 }
2660 if (!extrude_perimeter)
2661 return wall_polygon;
2662
2663 if (m_use_gap_wall) {
2664 // Cut the wall open at each toolchange's entry (see compute_wall_skip_points()).
2665 // The vector is empty during the save_on_last_wipe planning passes, which therefore
2666 // measure the un-gapped wall — same approximation as the BBL tower.
2667 static const std::vector<Vec2f> no_skip_points;
2668 const size_t layer_id = size_t(m_layer_info - m_plan.begin());
2669 const std::vector<Vec2f>& layer_skip_points =
2670 layer_id < m_wall_skip_points.size() ? m_wall_skip_points[layer_id] : no_skip_points;
2671 result_wall = construct_gap_for_skip_points(wall_polygon, layer_skip_points, m_wipe_tower_width, 2.5 * m_perimeter_width,
2672 insert_skip_polygon);
2673 } else {
2674 result_wall.push_back(to_polyline(wall_polygon));
2675 insert_skip_polygon = wall_polygon;
2676 }
2677 writer.generate_path(result_wall, feedrate, retract_length, retract_speed, m_used_fillet);
2678 // Tower-local shift that puts the rib wall's protruding first-layer min corner at the
2679 // configured tower position, like WipeTower::generate_support_wall_new(). Measured on
2680 // the un-gapped outline so a wall gap cannot shift the tower.
2681 if (rib_wall && is_first_layer()) {
2682 BoundingBox bbox = get_extents(insert_skip_polygon);
2683 m_rib_offset = Vec2f(-unscaled<float>(bbox.min.x()), -unscaled<float>(bbox.min.y()));
2684 }
2685
2686 return insert_skip_polygon;
2687}
Polygon generate_rib_polygon(const WipeTower::box_coordinates &wt_box)
Definition WipeTower2.cpp:2603
Vec2f m_rib_offset
Definition WipeTower2.hpp:263
Polygon generate_rectange_polygon(const Vec2f &wt_box_min, const Vec2f &wt_box_max)
Definition WipeTower.cpp:710
static Polygon rounding_polygon(Polygon &polygon, double rounding=2., double angle_tol=30./180. *PI)
Definition WipeTower2.cpp:128
Polylines construct_gap_for_skip_points(const Polygon &polygon, const std::vector< Vec2f > &skip_points, float wt_width, float gap_length, Polygon &insert_skip_polygon)
Definition WipeTower.cpp:695
static Polyline to_polyline(const std::vector< TravelPoint > &travel)
Definition AvoidCrossingPerimeters.cpp:370

References Slic3r::construct_gap_for_skip_points(), EPSILON, Slic3r::WipeTowerWriter2::generate_path(), Slic3r::generate_rectange_polygon(), generate_rib_polygon(), Slic3r::get_extents(), is_first_layer(), Slic3r::WipeTower::box_coordinates::ld, m_current_tool, m_filpar, m_layer_info, m_perimeter_width, m_plan, m_rib_offset, m_use_gap_wall, m_used_fillet, m_wall_skip_points, m_wipe_tower_width, m_y_shift, Slic3r::BoundingBoxBase< PointType, APointsType >::min, Slic3r::rounding_polygon(), Slic3r::WipeTower::box_coordinates::ru, Slic3r::to_polyline(), Slic3r::union_(), and Slic3r::unscaled().

Referenced by finish_layer().

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

◆ get_bbx()

BoundingBoxf Slic3r::WipeTower2::get_bbx ( ) const
inline
91 {
92 if (m_first_layer_bbx.defined)
93 return m_first_layer_bbx;
94 // Fallback: nominal rectangle (used if generate() hasn't run yet)
95 const float brim = m_wipe_tower_brim_width_real;
96 return BoundingBoxf(Vec2d(-brim, -brim), Vec2d(double(m_wipe_tower_width) + brim, double(m_wipe_tower_depth) + brim));
97 }

References m_first_layer_bbx, m_wipe_tower_brim_width_real, m_wipe_tower_depth, and m_wipe_tower_width.

Referenced by Slic3r::Print::_make_wipe_tower().

Here is the caller graph for this function:

◆ get_brim_width()

float Slic3r::WipeTower2::get_brim_width ( ) const
inline

References m_wipe_tower_brim_width_real.

Referenced by Slic3r::Print::_make_wipe_tower().

Here is the caller graph for this function:

◆ get_depth()

float Slic3r::WipeTower2::get_depth ( ) const
inline
84{ return m_wipe_tower_depth; }

References m_wipe_tower_depth.

Referenced by Slic3r::Print::_make_wipe_tower().

Here is the caller graph for this function:

◆ get_number_of_toolchanges()

int Slic3r::WipeTower2::get_number_of_toolchanges ( ) const
inline
173{ return m_num_tool_changes; }

References m_num_tool_changes.

Referenced by Slic3r::Print::_make_wipe_tower().

Here is the caller graph for this function:

◆ get_rib_length()

float Slic3r::WipeTower2::get_rib_length ( ) const
inline
102{ return m_rib_length; }

References m_rib_length.

Referenced by Slic3r::Print::_make_wipe_tower().

Here is the caller graph for this function:

◆ get_rib_offset()

Vec2f Slic3r::WipeTower2::get_rib_offset ( ) const
inline
100{ return m_rib_offset; }

References m_rib_offset.

Referenced by Slic3r::Print::_make_wipe_tower().

Here is the caller graph for this function:

◆ get_rib_width()

float Slic3r::WipeTower2::get_rib_width ( ) const
inline
101{ return m_rib_width; }

References m_rib_width.

Referenced by Slic3r::Print::_make_wipe_tower().

Here is the caller graph for this function:

◆ get_used_filament()

std::vector< float > Slic3r::WipeTower2::get_used_filament ( ) const
inline
171{ return m_used_filament_length; }

References m_used_filament_length.

Referenced by Slic3r::Print::_make_wipe_tower().

Here is the caller graph for this function:

◆ get_used_filament_until_layer()

std::vector< std::pair< float, std::vector< float > > > Slic3r::WipeTower2::get_used_filament_until_layer ( ) const
inline

◆ get_wipe_tower_cone_base()

std::pair< double, double > Slic3r::WipeTower2::get_wipe_tower_cone_base ( double width,
double height,
double depth,
double angle_deg )
static
2152{
2153 double R = std::tan(Geometry::deg2rad(angle_deg/2.)) * height;
2154 double fake_width = 0.66 * width;
2155 double diag = std::hypot(fake_width / 2., depth / 2.);
2156 double support_scale = 1.;
2157 if (R > diag) {
2158 double w = fake_width;
2159 double sin = 0.5 * depth / diag;
2160 double tan = depth / w;
2161 double t = (R - diag) * sin;
2162 support_scale = (w / 2. + t / tan + t * tan) / (w / 2.);
2163 }
2164 return std::make_pair(R, support_scale);
2165}
coord_t height(const BoundingBox &box)
Definition Arrange.cpp:1185

References Slic3r::Geometry::deg2rad(), and width().

Referenced by cone_base_polygon(), Slic3r::Print::first_layer_wipe_tower_corners(), generate_support_cone_wall(), Slic3r::FakeWipeTower::getFakeExtrusionPathsFromWipeTower2(), and toolchange_Change().

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

◆ get_wipe_tower_height()

float Slic3r::WipeTower2::get_wipe_tower_height ( ) const
inline
87{ return m_wipe_tower_height; }

References m_wipe_tower_height.

Referenced by Slic3r::Print::_make_wipe_tower().

Here is the caller graph for this function:

◆ get_z_and_depth_pairs()

std::vector< std::pair< float, float > > Slic3r::WipeTower2::get_z_and_depth_pairs ( ) const
2590{
2591 std::vector<std::pair<float, float>> out = {{0.f, m_wipe_tower_depth}};
2592 for (const WipeTowerInfo& wti : m_plan) {
2593 assert(wti.depth < wti.depth + WT_EPSILON);
2594 if (wti.depth < out.back().second - WT_EPSILON)
2595 out.emplace_back(wti.z, wti.depth);
2596 }
2597 if (out.back().first < m_wipe_tower_height - WT_EPSILON)
2598 out.emplace_back(m_wipe_tower_height, 0.f);
2599 return out;
2600}
Definition WipeTower2.hpp:365

References m_plan, m_wipe_tower_depth, m_wipe_tower_height, and WT_EPSILON.

Referenced by Slic3r::Print::_make_wipe_tower().

Here is the caller graph for this function:

◆ is_first_layer()

bool Slic3r::WipeTower2::is_first_layer ( ) const
inlineprivate
316{ return size_t(m_layer_info - m_plan.begin()) == m_first_layer_idx; }

References m_first_layer_idx, m_layer_info, and m_plan.

Referenced by finish_layer(), generate_support_rib_wall(), set_layer(), tool_change(), toolchange_Change(), toolchange_Unload(), and toolchange_Wipe().

Here is the caller graph for this function:

◆ layer_finished()

bool Slic3r::WipeTower2::layer_finished ( ) const
inline
167 {
169 }

References m_current_layer_finished.

Referenced by Slic3r::Print::_make_wipe_tower(), and finish_layer().

Here is the caller graph for this function:

◆ never_skip_tag()

const std::string Slic3r::WipeTower2::never_skip_tag ( )
inlinestatic
31{ return "_GCODE_WIPE_TOWER_NEVER_SKIP_TAG"; }

Referenced by toolchange_Change().

Here is the caller graph for this function:

◆ plan_toolchange()

void Slic3r::WipeTower2::plan_toolchange ( float z_par,
float layer_height_par,
unsigned int old_tool,
unsigned int new_tool,
float wipe_volume = 0.f )
2258{
2259 assert(m_plan.empty() || m_plan.back().z <= z_par + WT_EPSILON); // refuses to add a layer below the last one
2260
2261 if (m_plan.empty() || m_plan.back().z + WT_EPSILON < z_par) // if we moved to a new layer, we'll add it to m_plan first
2262 m_plan.push_back(WipeTowerInfo(z_par, layer_height_par));
2263
2264 if (m_first_layer_idx == size_t(-1) && (! m_sparse_layers_skipped || old_tool != new_tool || m_plan.size() == 1))
2265 m_first_layer_idx = m_plan.size() - 1;
2266
2267 if (old_tool == new_tool) // new layer without toolchanges - we are done
2268 return;
2269
2270 // this is an actual toolchange - let's calculate depth to reserve on the wipe tower
2271 const bool first_layer_plan = (m_plan.size() - 1) == m_first_layer_idx;
2272 m_plan.back().tool_changes.push_back(set_toolchange(old_tool, new_tool, layer_height_par, wipe_volume, first_layer_plan));
2273}

References m_first_layer_idx, m_plan, m_sparse_layers_skipped, set_toolchange(), and WT_EPSILON.

Referenced by Slic3r::Print::_make_wipe_tower().

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

◆ plan_tower()

void Slic3r::WipeTower2::plan_tower ( )
private
2315{
2316 // Calculate m_wipe_tower_depth (maximum depth for all the layers) and propagate depths downwards
2317 m_wipe_tower_depth = 0.f;
2318 for (auto& layer : m_plan)
2319 layer.depth = 0.f;
2320 m_wipe_tower_height = m_plan.empty() ? 0.f : m_plan.back().z;
2321 m_current_height = 0.f;
2322
2323 for (int layer_index = int(m_plan.size()) - 1; layer_index >= 0; --layer_index)
2324 {
2325 float this_layer_depth = std::max(m_plan[layer_index].depth, m_plan[layer_index].toolchanges_depth());
2326 m_plan[layer_index].depth = this_layer_depth;
2327
2328 if (this_layer_depth > m_wipe_tower_depth - m_perimeter_width)
2329 m_wipe_tower_depth = this_layer_depth + m_perimeter_width;
2330
2331 for (int i = layer_index - 1; i >= 0 ; i--)
2332 {
2333 if (m_plan[i].depth - this_layer_depth < 2*m_perimeter_width )
2334 m_plan[i].depth = this_layer_depth;
2335 }
2336 }
2337}

References m_current_height, m_perimeter_width, m_plan, m_wipe_tower_depth, and m_wipe_tower_height.

Referenced by generate().

Here is the caller graph for this function:

◆ position()

const Vec2f & Slic3r::WipeTower2::position ( ) const
inline
142{ return m_wipe_tower_pos; }

References m_wipe_tower_pos.

Referenced by Slic3r::Print::_make_wipe_tower().

Here is the caller graph for this function:

◆ prime()

std::vector< WipeTower::ToolChangeResult > Slic3r::WipeTower2::prime ( float first_layer_height,
const std::vector< unsigned int > & tools,
bool last_wipe_inside_wipe_tower )
1237{
1238 this->set_layer(initial_layer_print_height, initial_layer_print_height, tools.size(), true, false);
1239 m_current_tool = tools.front();
1240
1241 // The Prusa i3 MK2 has a working space of [0, -2.2] to [250, 210].
1242 // Due to the XYZ calibration, this working space may shrink slightly from all directions,
1243 // therefore the homing position is shifted inside the bed by 0.2 in the firmware to [0.2, -2.0].
1244// WipeTower::box_coordinates cleaning_box(xy(0.5f, - 1.5f), m_wipe_tower_width, wipe_area);
1245
1246 float prime_section_width = std::min(0.9f * m_bed_width / tools.size(), 60.f);
1247 WipeTower::box_coordinates cleaning_box(Vec2f(0.02f * m_bed_width, 0.01f + m_perimeter_width/2.f), prime_section_width, 100.f);
1248 if (m_bed_shape == CircularBed) {
1249 cleaning_box = WipeTower::box_coordinates(Vec2f(0.f, 0.f), prime_section_width, 100.f);
1250 float total_width_half = tools.size() * prime_section_width / 2.f;
1251 cleaning_box.translate(-total_width_half, -std::sqrt(std::max(0.f, std::pow(m_bed_width/2, 2.f) - std::pow(1.05f * total_width_half, 2.f))));
1252 }
1253 else
1254 cleaning_box.translate(m_bed_bottom_left);
1255
1256 std::vector<WipeTower::ToolChangeResult> results;
1257
1258 // Iterate over all priming toolchanges and push respective ToolChangeResults into results vector.
1259 for (size_t idx_tool = 0; idx_tool < tools.size(); ++ idx_tool) {
1260 size_t old_tool = m_current_tool;
1261
1263 writer.set_extrusion_flow(m_extrusion_flow)
1264 .set_z(m_z_pos)
1265 .set_initial_tool(m_current_tool);
1266
1267 // This is the first toolchange - initiate priming
1268 if (idx_tool == 0) {
1269 writer.append(";--------------------\n"
1270 "; CP PRIMING START\n")
1271 .append(";--------------------\n")
1272 .speed_override_backup()
1273 .speed_override(100)
1274 .set_initial_position(Vec2f::Zero()) // Always move to the starting position
1275 .travel(cleaning_box.ld, 7200);
1277 writer.set_extruder_trimpot(750); // Increase the extruder driver current to allow fast ramming.
1278 }
1279 else
1280 writer.set_initial_position(results.back().end_pos);
1281
1282
1283 unsigned int tool = tools[idx_tool];
1284 m_left_to_right = true;
1285 toolchange_Change(writer, tool, m_filpar[tool].material, m_filpar[tool].first_layer_temperature, false); // Select the tool, set a speed override for soluble and flex materials.
1286 toolchange_Load(writer, cleaning_box); // Prime the tool.
1287 if (idx_tool + 1 == tools.size()) {
1288 // Last tool should not be unloaded, but it should be wiped enough to become of a pure color.
1289 toolchange_Wipe(writer, cleaning_box, wipe_volumes[tools[idx_tool-1]][tool], false, true);
1290 } else {
1291 // Ram the hot material out of the melt zone, retract the filament into the cooling tubes and let it cool.
1292 //writer.travel(writer.x(), writer.y() + m_perimeter_width, 7200);
1293 toolchange_Wipe(writer, cleaning_box , 20.f, false, true);
1294 WipeTower::box_coordinates box = cleaning_box;
1295 box.translate(0.f, writer.y() - cleaning_box.ld.y() + m_perimeter_width);
1296 toolchange_Unload(writer, box , m_filpar[m_current_tool].material, m_filpar[m_current_tool].first_layer_temperature, m_filpar[tools[idx_tool + 1]].first_layer_temperature);
1297 cleaning_box.translate(prime_section_width, 0.f);
1298 writer.travel(cleaning_box.ld, 7200);
1299 }
1301
1302
1303 // Ask our writer about how much material was consumed:
1305 m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length();
1306
1307 // This is the last priming toolchange - finish priming
1308 if (idx_tool+1 == tools.size()) {
1309 // Reset the extruder current to a normal value.
1311 writer.set_extruder_trimpot(550);
1312 writer.speed_override_restore()
1313 .feedrate(m_travel_speed * 60.f)
1314 .flush_planner_queue()
1315 .reset_extruder()
1316 .append("; CP PRIMING END\n"
1317 ";------------------\n"
1318 "\n\n");
1319 }
1320
1321 results.emplace_back(construct_tcr(writer, true, old_tool, true, false));
1322 }
1323
1324 m_old_temperature = -1; // If the priming is turned off in config, the temperature changing commands will not actually appear
1325 // in the output gcode - we should not remember emitting them (we will output them twice in the worst case)
1326
1327 return results;
1328}
void toolchange_Unload(WipeTowerWriter2 &writer, const WipeTower::box_coordinates &cleaning_box, const std::string &current_material, const int old_temperature, const int new_temperature)
Definition WipeTower2.cpp:1460
void toolchange_Change(WipeTowerWriter2 &writer, const size_t new_tool, const std::string &new_material, const int wait_for_temp, const bool wait_beside_tower)
Definition WipeTower2.cpp:1723
void toolchange_Load(WipeTowerWriter2 &writer, const WipeTower::box_coordinates &cleaning_box)
Definition WipeTower2.cpp:1852
void toolchange_Wipe(WipeTowerWriter2 &writer, const WipeTower::box_coordinates &cleaning_box, float wipe_volume, bool interface_layer, bool priming=false, bool fill_box=false)
Definition WipeTower2.cpp:1881
zaa_minimize_perimeter_height initial_layer_print_height((ConfigOptionFloatsNullable, initial_layer_speed))((ConfigOptionFloatsNullable

References Slic3r::WipeTowerWriter2::append(), CircularBed, construct_tcr(), Slic3r::WipeTowerWriter2::feedrate(), Slic3r::WipeTowerWriter2::flush_planner_queue(), Slic3r::WipeTowerWriter2::get_and_reset_used_filament_length(), Slic3r::initial_layer_print_height(), Slic3r::WipeTower::box_coordinates::ld, m_bed_bottom_left, m_bed_shape, m_bed_width, m_current_tool, m_enable_arc_fitting, m_extrusion_flow, m_filpar, m_gcode_flavor, m_layer_height, m_left_to_right, m_num_tool_changes, m_old_temperature, m_perimeter_width, m_set_extruder_trimpot, m_travel_speed, m_used_filament_length, m_z_pos, Slic3r::WipeTowerWriter2::reset_extruder(), Slic3r::WipeTowerWriter2::set_extruder_trimpot(), Slic3r::WipeTowerWriter2::set_extrusion_flow(), Slic3r::WipeTowerWriter2::set_initial_position(), Slic3r::WipeTowerWriter2::set_initial_tool(), set_layer(), Slic3r::WipeTowerWriter2::set_z(), Slic3r::WipeTowerWriter2::speed_override(), Slic3r::WipeTowerWriter2::speed_override_backup(), Slic3r::WipeTowerWriter2::speed_override_restore(), toolchange_Change(), toolchange_Load(), toolchange_Unload(), toolchange_Wipe(), Slic3r::WipeTower::box_coordinates::translate(), Slic3r::WipeTowerWriter2::travel(), wipe_volumes, and Slic3r::WipeTowerWriter2::y().

Referenced by Slic3r::Print::_make_wipe_tower().

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

◆ save_on_last_wipe()

void Slic3r::WipeTower2::save_on_last_wipe ( )
private
2340{
2341 for (m_layer_info=m_plan.begin();m_layer_info<m_plan.end();++m_layer_info) {
2342 set_layer(m_layer_info->z, m_layer_info->height, 0, m_layer_info->z == m_plan.front().z, m_layer_info->z == m_plan.back().z);
2343 if (m_layer_info->tool_changes.size()==0) // we have no way to save anything on an empty layer
2344 continue;
2345
2346 // Which toolchange will finish_layer extrusions be subtracted from?
2348
2349 if (idx == -1) {
2350 // In this case, finish_layer will be called at the very beginning.
2352 }
2353
2354 const float width = m_wipe_tower_width - 3*m_perimeter_width; // width we draw into
2355 auto recompute_toolchange = [this, width](WipeTowerInfo::ToolChange& toolchange, float volume_to_save) {
2356 float volume_left_to_wipe = std::max(m_filpar[toolchange.new_tool].filament_minimal_purge_on_wipe_tower, toolchange.wipe_volume_total - volume_to_save);
2357 float volume_we_need_depth_for = std::max(0.f, volume_left_to_wipe - length_to_volume(toolchange.first_wipe_line, m_perimeter_width*m_extra_flow, m_layer_info->height));
2358
2359 // ORCA: Keep wipe-depth planning consistent with toolchange_Wipe().
2360 // ORCA: On the first layer, toolchange_Wipe() advances purge rows using
2361 // ORCA: m_extra_flow * m_perimeter_width, while later layers use
2362 // ORCA: m_extra_spacing_wipe * m_perimeter_width.
2363 // ORCA: float dy = (is_first_layer() ? m_extra_flow : m_extra_spacing_wipe) * m_perimeter_width;
2364 // ORCA: Use the same spacing here so reserved depth matches consumed depth
2365 // ORCA: and first-layer purge segments do not leave visible gaps.
2366 const bool first_layer_plan = size_t(m_layer_info - m_plan.begin()) == m_first_layer_idx;
2367 const float planning_spacing = first_layer_plan ? m_extra_flow : m_extra_spacing_wipe;
2368
2369 float depth_to_wipe = get_wipe_depth(volume_we_need_depth_for, m_layer_info->height, m_perimeter_width, m_extra_flow, planning_spacing, width);
2370
2371 toolchange.required_depth = toolchange.ramming_depth + depth_to_wipe;
2372 toolchange.wipe_volume = volume_left_to_wipe;
2373 };
2374
2375 for (int i=0; i<int(m_layer_info->tool_changes.size()); ++i) {
2376 auto& toolchange = m_layer_info->tool_changes[i];
2377 tool_change(toolchange.new_tool);
2378
2379 if (i == idx) {
2380 recompute_toolchange(toolchange, length_to_volume(finish_layer().total_extrusion_length_in_plane(), m_perimeter_width, m_layer_info->height));
2381 } else if (toolchange.wipe_volume < m_filpar[toolchange.new_tool].filament_minimal_purge_on_wipe_tower) {
2382 // Keep filament_minimal_purge_on_wipe_tower enforced for toolchanges that get
2383 // no finish-layer saving, e.g. a support/soluble filament skipped as the
2384 // finish filament above. Recomputing only when the clamp binds leaves all
2385 // other toolchanges with their planned values bit-for-bit.
2386 recompute_toolchange(toolchange, 0.f);
2387 }
2388 }
2389 }
2390}
static float length_to_volume(float length, float line_width, float layer_height)
Definition WipeTower2.cpp:329
static float get_wipe_depth(float volume, float layer_height, float perimeter_width, float extra_flow, float extra_spacing, float width)
Definition WipeTower2.cpp:2247
float total_extrusion_length_in_plane()
Definition WipeTower.hpp:167

References finish_layer(), first_toolchange_to_nonsoluble_nonsupport(), Slic3r::WipeTower2::WipeTowerInfo::ToolChange::first_wipe_line, Slic3r::get_wipe_depth(), Slic3r::length_to_volume(), m_extra_flow, m_extra_spacing_wipe, m_filpar, m_first_layer_idx, m_layer_info, m_perimeter_width, m_plan, m_wipe_tower_width, Slic3r::WipeTower2::WipeTowerInfo::ToolChange::new_tool, Slic3r::WipeTower2::WipeTowerInfo::ToolChange::ramming_depth, Slic3r::WipeTower2::WipeTowerInfo::ToolChange::required_depth, set_layer(), tool_change(), Slic3r::WipeTower::ToolChangeResult::total_extrusion_length_in_plane(), width(), Slic3r::WipeTower2::WipeTowerInfo::ToolChange::wipe_volume, and Slic3r::WipeTower2::WipeTowerInfo::ToolChange::wipe_volume_total.

Referenced by generate().

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

◆ set_extruder()

void Slic3r::WipeTower2::set_extruder ( size_t idx,
const PrintConfig & config )
1129{
1130 //while (m_filpar.size() < idx+1) // makes sure the required element is in the vector
1131 m_filpar.push_back(FilamentParameters());
1132
1133 // Orca: one row per filament, indexed by the raw filament id. Under a per-layer nozzle
1134 // grouping the per-variant arrays may hold several columns per filament; the tower has no
1135 // layer dimension here, so it keeps the filament's first column (tower x per-layer
1136 // grouping is a documented follow-up).
1137 m_filpar[idx].material = config.filament_type.get_at(idx);
1138 if (m_wipe_tower_filament > 0)
1139 m_filpar[idx].is_soluble = (idx != size_t(m_wipe_tower_filament - 1));
1140 else
1141 m_filpar[idx].is_soluble = config.filament_soluble.get_at(idx);
1142 m_filpar[idx].is_support = config.filament_is_support.get_at(idx);
1143 m_filpar[idx].temperature = config.nozzle_temperature.get_at(idx);
1144 m_filpar[idx].first_layer_temperature = config.nozzle_temperature_initial_layer.get_at(idx);
1145 m_filpar[idx].filament_minimal_purge_on_wipe_tower = config.filament_minimal_purge_on_wipe_tower.get_at(idx);
1146 {
1147 int interface_temp = config.filament_tower_interface_print_temp.get_at(idx);
1148 if (interface_temp == -1)
1149 interface_temp = config.nozzle_temperature_range_high.get_at(idx);
1150 m_filpar[idx].interface_print_temperature = interface_temp;
1151 }
1152 m_filpar[idx].tower_interface_pre_extrusion_dist = config.filament_tower_interface_pre_extrusion_dist.get_at(idx);
1153 m_filpar[idx].tower_interface_pre_extrusion_length = config.filament_tower_interface_pre_extrusion_length.get_at(idx);
1154 m_filpar[idx].tower_ironing_area = config.filament_tower_ironing_area.get_at(idx);
1155 m_filpar[idx].tower_interface_purge_length = config.filament_tower_interface_purge_volume.get_at(idx);
1156
1157 // If this is a single extruder MM printer, we will use all the SE-specific config values.
1158 // Otherwise, the defaults will be used to turn off the SE stuff.
1159 if (m_semm) {
1160 m_filpar[idx].loading_speed = float(config.filament_loading_speed.get_at(idx));
1161 m_filpar[idx].loading_speed_start = float(config.filament_loading_speed_start.get_at(idx));
1162 m_filpar[idx].unloading_speed = float(config.filament_unloading_speed.get_at(idx));
1163 m_filpar[idx].unloading_speed_start = float(config.filament_unloading_speed_start.get_at(idx));
1164 m_filpar[idx].delay = float(config.filament_toolchange_delay.get_at(idx));
1165 m_filpar[idx].cooling_moves = config.filament_cooling_moves.get_at(idx);
1166 m_filpar[idx].cooling_initial_speed = float(config.filament_cooling_initial_speed.get_at(idx));
1167 m_filpar[idx].cooling_final_speed = float(config.filament_cooling_final_speed.get_at(idx));
1168 m_filpar[idx].filament_stamping_loading_speed = float(config.filament_stamping_loading_speed.get_at(idx));
1169 m_filpar[idx].filament_stamping_distance = float(config.filament_stamping_distance.get_at(idx));
1170 }
1171
1172 m_filpar[idx].filament_area = float((M_PI/4.f) * pow(config.filament_diameter.get_at(idx), 2)); // all extruders are assumed to have the same filament diameter at this point
1173 float nozzle_diameter = float(config.nozzle_diameter.get_at(idx));
1174 m_filpar[idx].nozzle_diameter = nozzle_diameter; // to be used in future with (non-single) multiextruder MM
1175
1176 // Orca: max_layer_height is per nozzle, so read it through the filament->nozzle map rather than
1177 // by filament id. Zero means three quarters of the nozzle diameter, as in Slicing.cpp.
1178 {
1179 const std::vector<int> &filament_map = config.filament_map.values; // 1 based nozzle indices
1180 const size_t nozzle_idx = idx < filament_map.size() && filament_map[idx] > 0 ? size_t(filament_map[idx] - 1) : 0;
1181 const float max_layer_height = float(config.max_layer_height.get_at(nozzle_idx));
1182 m_filpar[idx].max_layer_height = max_layer_height > 0.f ? max_layer_height
1183 : 0.75f * float(config.nozzle_diameter.get_at(nozzle_idx));
1184 }
1185
1186 float max_vol_speed = float(config.filament_max_volumetric_speed.get_at(idx));
1187 if (max_vol_speed!= 0.f)
1188 m_filpar[idx].max_e_speed = (max_vol_speed / filament_area());
1189
1190 m_perimeter_width = nozzle_diameter * Width_To_Nozzle_Ratio; // all extruders are now assumed to have the same diameter
1191
1192 if (m_semm) {
1193 std::istringstream stream{config.filament_ramming_parameters.get_at(idx)};
1194 float speed = 0.f;
1195 stream >> m_filpar[idx].ramming_line_width_multiplicator >> m_filpar[idx].ramming_step_multiplicator;
1196 m_filpar[idx].ramming_line_width_multiplicator /= 100;
1197 m_filpar[idx].ramming_step_multiplicator /= 100;
1198 while (stream >> speed)
1199 m_filpar[idx].ramming_speed.push_back(speed);
1200 // ramming_speed now contains speeds to be used for every 0.25s piece of the ramming line.
1201 // This allows to have the ramming flow variable. The 0.25s value is how it is saved in config
1202 // and the same time step has to be used when the ramming is performed.
1203 } else {
1204 // We will use the same variables internally, but the correspondence to the configuration options will be different.
1205 float vol = config.filament_multitool_ramming_volume.get_at(idx);
1206 float flow = config.filament_multitool_ramming_flow.get_at(idx);
1207 m_filpar[idx].multitool_ramming = config.filament_multitool_ramming.get_at(idx) && vol > 0.f && flow > 0.f;
1208 m_filpar[idx].ramming_line_width_multiplicator = 2.;
1209 m_filpar[idx].ramming_step_multiplicator = 1.;
1210
1211 // Now the ramming speed vector. In this case it contains just one value (flow).
1212 // The time is calculated and saved separately. This is here so that the MM ramming
1213 // is not limited by the 0.25s granularity - it is not possible to create a SEMM-style
1214 // ramming_speed vector that would respect both the volume and flow (because of
1215 // rounding issues with small volumes and high flow).
1216 m_filpar[idx].ramming_speed.push_back(flow);
1217 m_filpar[idx].multitool_ramming_time = flow > 0.f ? vol/flow : 0.f;
1218 }
1219
1220 m_used_filament_length.resize(std::max(m_used_filament_length.size(), idx + 1)); // makes sure that the vector is big enough so we don't have to check later
1221
1222 m_filpar[idx].retract_length = config.retraction_length.get_at(idx);
1223 m_filpar[idx].retract_speed = config.retraction_speed.get_at(idx);
1224}
const float Width_To_Nozzle_Ratio
Definition WipeTower2.hpp:220
Definition WipeTower2.hpp:175
zaa_minimize_perimeter_height filament_map((ConfigOptionInts, filament_volume_map))((ConfigOptionInts

References filament_area(), Slic3r::filament_map(), m_filpar, m_perimeter_width, M_PI, m_semm, m_used_filament_length, m_wipe_tower_filament, Slic3r::nozzle_diameter(), and Width_To_Nozzle_Ratio.

Referenced by Slic3r::Print::_make_wipe_tower().

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

◆ set_layer()

void Slic3r::WipeTower2::set_layer ( float print_z,
float layer_height,
size_t max_tool_changes,
bool ,
bool is_last_layer )
inline
116 {
117 m_z_pos = print_z;
119 m_depth_traversed = 0.f;
122
123
124 // Advance m_layer_info iterator, making sure we got it right
125 while (!m_plan.empty() && m_layer_info->z < print_z - WT_EPSILON && m_layer_info+1 != m_plan.end())
126 ++m_layer_info;
127 m_current_layer_has_interface = (m_layer_info != m_plan.end()) && (m_layer_info->toolchanges_depth() > WT_EPSILON);
128
129 //m_current_shape = (! this->is_first_layer() && m_current_shape == SHAPE_NORMAL) ? SHAPE_REVERSED : SHAPE_NORMAL;
131 if (this->is_first_layer()) {
134 } else
136
137 // Calculate extrusion flow from desired line width, nozzle diameter, filament diameter and layer_height:
139 }
bool m_current_layer_has_interface
Definition WipeTower2.hpp:256
float m_depth_traversed
Definition WipeTower2.hpp:309
float extrusion_flow(float layer_height=-1.f) const
Definition WipeTower2.hpp:350

References extrusion_flow(), is_first_layer(), Slic3r::layer_height(), m_current_layer_finished, m_current_layer_has_interface, m_current_shape, m_depth_traversed, m_extrusion_flow, m_layer_height, m_layer_info, m_num_layer_changes, m_num_tool_changes, m_plan, m_prev_layer_had_interface, m_z_pos, SHAPE_NORMAL, and WT_EPSILON.

Referenced by Slic3r::Print::_make_wipe_tower(), generate(), prime(), and save_on_last_wipe().

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

◆ set_toolchange()

WipeTower2::WipeTowerInfo::ToolChange Slic3r::WipeTower2::set_toolchange ( size_t old_tool,
size_t new_tool,
float layer_height,
float wipe_volume,
bool first_layer_plan )
private
2276{
2278 float length_to_extrude = volume_to_length((m_semm ? 0.25f : m_filpar[old_tool].multitool_ramming_time) * std::accumulate(m_filpar[old_tool].ramming_speed.begin(), m_filpar[old_tool].ramming_speed.end(), 0.f),
2279 m_perimeter_width * m_filpar[old_tool].ramming_line_width_multiplicator,
2280 layer_height);
2281 // Orca: Reserve ramming depth only when toolchange_Unload() will actually ram,
2282 // otherwise the unprinted reservation leaves blank bands between the purge boxes.
2283 const bool do_ramming = tool_ramming_enabled(old_tool);
2284 // Orca: with the gap wall on a multi-tool printer the ram band is quantized up to
2285 // the whole reserved rows and the wipe restarts at the left-edge boundary on a
2286 // fresh row below it (BBL parity: the old-tool purge is whole rows and the wipe
2287 // always starts at the box corner, where the entry scrub runs).
2288 const bool boundary_wipe_start = boundary_wipe_start_enabled(old_tool);
2289 float ramming_depth = do_ramming ? ((int(length_to_extrude / width) + 1) * (m_perimeter_width * m_filpar[old_tool].ramming_line_width_multiplicator * m_filpar[old_tool].ramming_step_multiplicator) * m_extra_spacing_ramming) : 0;
2290 // first_wipe_line rides for free on the last (partially used) ramming row, which
2291 // is already covered by ramming_depth. Without ramming that row does not exist
2292 // (and with a boundary wipe start the ram band is quantized to whole rows), so
2293 // the whole wipe volume needs reserved wiping depth.
2294 float first_wipe_line = (do_ramming && !boundary_wipe_start) ? - (width*((length_to_extrude / width)-int(length_to_extrude / width)) - width) : 0.f;
2295
2296 float first_wipe_volume = length_to_volume(first_wipe_line, m_perimeter_width * m_extra_flow, layer_height);
2297
2298 // ORCA: Keep wipe-depth planning consistent with toolchange_Wipe().
2299 // ORCA: On the first layer, toolchange_Wipe() advances purge rows using
2300 // ORCA: m_extra_flow * m_perimeter_width, while later layers use
2301 // ORCA: m_extra_spacing_wipe * m_perimeter_width.
2302 // ORCA: float dy = (is_first_layer() ? m_extra_flow : m_extra_spacing_wipe) * m_perimeter_width;
2303 // ORCA: Use the same spacing here so reserved depth matches consumed depth
2304 // ORCA: and first-layer purge segments do not leave visible gaps.
2305 const float planning_spacing = first_layer_plan ? m_extra_flow : m_extra_spacing_wipe;
2306
2307 float wiping_depth = get_wipe_depth(wipe_volume - first_wipe_volume, layer_height, m_perimeter_width, m_extra_flow, planning_spacing, width);
2308
2309 return WipeTowerInfo::ToolChange(old_tool, new_tool, ramming_depth + wiping_depth, ramming_depth, first_wipe_line, wipe_volume);
2310}
bool boundary_wipe_start_enabled(size_t tool) const
Definition WipeTower2.hpp:327
static float volume_to_length(float volume, float line_width, float layer_height)
Definition WipeTower2.cpp:324

References boundary_wipe_start_enabled(), Slic3r::get_wipe_depth(), Slic3r::layer_height(), Slic3r::length_to_volume(), m_extra_flow, m_extra_spacing_ramming, m_extra_spacing_wipe, m_filpar, m_perimeter_width, m_semm, m_wipe_tower_width, tool_ramming_enabled(), Slic3r::volume_to_length(), and width().

Referenced by generate(), and plan_toolchange().

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

◆ tool_change()

WipeTower::ToolChangeResult Slic3r::WipeTower2::tool_change ( size_t new_tool)
1331{
1332 size_t old_tool = m_current_tool;
1333
1334 float wipe_area = 0.f;
1335 float wipe_volume = 0.f;
1336 float ramming_depth = 0.f;
1338
1339 // Finds this toolchange info
1340 if (tool != (unsigned int)(-1))
1341 {
1342 for (const auto &b : m_layer_info->tool_changes)
1343 if ( b.new_tool == tool ) {
1344 wipe_volume = b.wipe_volume;
1345 wipe_area = b.required_depth;
1346 ramming_depth = b.ramming_depth;
1347 break;
1348 }
1349 }
1350 else {
1351 // Otherwise we are going to Unload only. And m_layer_info would be invalid.
1352 }
1353 if (interface_layer && tool != (unsigned int)(-1) && tool < m_filpar.size()) {
1354 float extra_purge_length = m_filpar[tool].tower_interface_purge_length;
1355 if (extra_purge_length > 0.f) {
1356 wipe_volume += extra_purge_length * m_filpar[tool].filament_area;
1357 }
1358 }
1359
1360 WipeTower::box_coordinates cleaning_box(
1363 (tool != (unsigned int)(-1) ? wipe_area+m_depth_traversed-0.5f*m_perimeter_width
1365
1367 writer.set_extrusion_flow(m_extrusion_flow)
1368 .set_z(m_z_pos)
1369 .set_initial_tool(m_current_tool)
1370 .set_y_shift(m_y_shift + (tool!=(unsigned int)(-1) && (m_current_shape == SHAPE_REVERSED) ? m_layer_info->depth - m_layer_info->toolchanges_depth(): 0.f))
1371 .append(";--------------------\n"
1372 "; CP TOOLCHANGE START\n");
1373
1374 if (tool != (unsigned)(-1)){
1375 writer.comment_with_value(" toolchange #", m_num_tool_changes + 1); // the number is zero-based
1376 writer.append(std::string("; material : " + (m_current_tool < m_filpar.size() ? m_filpar[m_current_tool].material : "(NONE)") + " -> " + m_filpar[tool].material + "\n").c_str())
1377 .append(";--------------------\n");
1379 }
1380
1381 writer.speed_override_backup();
1382 writer.speed_override(100);
1383
1384 // On a boundary wipe start this enters at the wall gap on the first wipe row;
1385 // toolchange_Unload() then climbs back up to the ram band along the box interior.
1386 Vec2f initial_position = toolchange_entry_pos(m_depth_traversed, ramming_depth, is_first_layer());
1387 writer.set_initial_position(initial_position, m_wipe_tower_width, m_wipe_tower_depth, m_internal_rotation);
1388
1389 // Increase the extruder driver current to allow fast ramming.
1391 writer.set_extruder_trimpot(750);
1392
1393 // Ram the hot material out of the melt zone, retract the filament into the cooling tubes and let it cool.
1394 if (tool != (unsigned int)-1){ // This is not the last change.
1395 // Without a ram — or with the boundary wipe start, where the ram band is
1396 // quantized to whole rows — the box is planned as whole wipe rows; the wipe
1397 // then fills it completely so adjacent purge blocks stay contiguous. Uses the
1398 // old tool (m_current_tool before toolchange_Change).
1400 auto new_tool_temp = is_first_layer() ? m_filpar[tool].first_layer_temperature : m_filpar[tool].temperature;
1401 toolchange_Unload(writer, cleaning_box, m_filpar[m_current_tool].material,
1402 (is_first_layer() ? m_filpar[m_current_tool].first_layer_temperature : m_filpar[m_current_tool].temperature),
1403 new_tool_temp);
1404 // Wait-at-tower target: the interface temp when an interface boost applies on this layer,
1405 // otherwise the print temp (nozzle_temperature == 0 means "use the first layer temp").
1406 int wait_for_temp = interface_layer && m_filpar[tool].interface_print_temperature > 0 ?
1407 m_filpar[tool].interface_print_temperature :
1408 (is_first_layer() || m_filpar[tool].temperature == 0 ? m_filpar[tool].first_layer_temperature : m_filpar[tool].temperature);
1409 toolchange_Change(writer, tool, m_filpar[tool].material, wait_for_temp, true); // Change the tool, set a speed override for soluble and flex materials.
1410 toolchange_Load(writer, cleaning_box);
1411 writer.travel(writer.x(), writer.y()-m_perimeter_width); // cooling and loading were done a bit down the road
1412 int base_temp = is_first_layer() ? m_filpar[tool].first_layer_temperature : m_filpar[tool].temperature;
1413 if (interface_layer) {
1414 int interface_temp = m_filpar[tool].interface_print_temperature;
1415 // With wait-for-temp-on-wipe-tower the toolchange already blocked for the interface temp.
1416 if (interface_temp > 0 && interface_temp != base_temp && !m_wait_for_temp_on_wipe_tower)
1417 writer.set_extruder_temp(interface_temp, true);
1418 if (m_enable_tower_interface_cooldown_during_tower && interface_temp > 0 && interface_temp != base_temp)
1419 writer.set_extruder_temp(base_temp, false);
1420 float pre_dist = m_filpar[tool].tower_interface_pre_extrusion_dist;
1421 float pre_len = m_filpar[tool].tower_interface_pre_extrusion_length;
1422 if (pre_dist > 0.f && pre_len > 0.f) {
1423 float target_x = writer.x() + pre_dist;
1424 target_x = std::max(cleaning_box.ld.x(), std::min(cleaning_box.rd.x(), target_x));
1425 writer.extrude_explicit(target_x, writer.y(), pre_len, 600.f);
1426 }
1427 }
1428 toolchange_Wipe(writer, cleaning_box, wipe_volume, interface_layer, false, fill_box); // Wipe the newly loaded filament until the end of the assigned wipe area.
1429 if (interface_layer) {
1430 int interface_temp = m_filpar[tool].interface_print_temperature;
1431 if (!m_enable_tower_interface_cooldown_during_tower && interface_temp > 0 && interface_temp != base_temp)
1432 writer.set_extruder_temp(base_temp, false);
1433 }
1436 } else
1437 toolchange_Unload(writer, cleaning_box, m_filpar[m_current_tool].material, m_filpar[m_current_tool].temperature, m_filpar[m_current_tool].temperature);
1438
1439 m_depth_traversed += wipe_area;
1440
1442 writer.set_extruder_trimpot(550); // Reset the extruder current to a normal value.
1443 writer.speed_override_restore();
1444 writer.feedrate(m_travel_speed * 60.f)
1445 .flush_planner_queue()
1446 .reset_extruder()
1447 .append("; CP TOOLCHANGE END\n"
1448 ";------------------\n"
1449 "\n\n");
1450
1451 // Ask our writer about how much material was consumed:
1453 m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length();
1454
1455 return construct_tcr(writer, false, old_tool, false, interface_layer);
1456}
static const std::string & reserved_tag(ETags tag)
Definition GCodeProcessor.hpp:636
@ Wipe_Tower_End
Definition GCodeProcessor.hpp:620
@ Wipe_Tower_Start
Definition GCodeProcessor.hpp:619

References Slic3r::WipeTowerWriter2::append(), boundary_wipe_start_enabled(), Slic3r::WipeTowerWriter2::comment_with_value(), construct_tcr(), Slic3r::WipeTowerWriter2::extrude_explicit(), Slic3r::WipeTowerWriter2::feedrate(), Slic3r::WipeTowerWriter2::flush_planner_queue(), Slic3r::WipeTowerWriter2::get_and_reset_used_filament_length(), is_first_layer(), Slic3r::WipeTower::box_coordinates::ld, m_current_layer_has_interface, m_current_shape, m_current_tool, m_depth_traversed, m_enable_arc_fitting, m_enable_tower_interface_cooldown_during_tower, m_enable_tower_interface_features, m_extrusion_flow, m_filpar, m_gcode_flavor, m_internal_rotation, m_layer_height, m_layer_info, m_num_tool_changes, m_perimeter_width, m_set_extruder_trimpot, m_travel_speed, m_used_filament_length, m_wait_for_temp_on_wipe_tower, m_wipe_tower_depth, m_wipe_tower_width, m_y_shift, m_z_pos, Slic3r::WipeTower::box_coordinates::rd, Slic3r::GCodeProcessor::reserved_tag(), Slic3r::WipeTowerWriter2::reset_extruder(), Slic3r::WipeTowerWriter2::set_extruder_temp(), Slic3r::WipeTowerWriter2::set_extruder_trimpot(), Slic3r::WipeTowerWriter2::set_extrusion_flow(), Slic3r::WipeTowerWriter2::set_initial_position(), Slic3r::WipeTowerWriter2::set_initial_tool(), Slic3r::WipeTowerWriter2::set_y_shift(), Slic3r::WipeTowerWriter2::set_z(), SHAPE_REVERSED, Slic3r::WipeTowerWriter2::speed_override(), Slic3r::WipeTowerWriter2::speed_override_backup(), Slic3r::WipeTowerWriter2::speed_override_restore(), tool_ramming_enabled(), toolchange_Change(), toolchange_entry_pos(), toolchange_Load(), toolchange_Unload(), toolchange_Wipe(), Slic3r::WipeTowerWriter2::travel(), Slic3r::GCodeProcessor::Wipe_Tower_End, Slic3r::GCodeProcessor::Wipe_Tower_Start, Slic3r::WipeTowerWriter2::x(), and Slic3r::WipeTowerWriter2::y().

Referenced by Slic3r::Print::_make_wipe_tower(), generate(), and save_on_last_wipe().

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

◆ tool_ramming_enabled()

bool Slic3r::WipeTower2::tool_ramming_enabled ( size_t tool) const
inlineprivate
323{ return (m_semm && m_enable_filament_ramming) || m_filpar[tool].multitool_ramming; }

References m_enable_filament_ramming, m_filpar, and m_semm.

Referenced by boundary_wipe_start_enabled(), set_toolchange(), tool_change(), and toolchange_Unload().

Here is the caller graph for this function:

◆ toolchange_Change()

void Slic3r::WipeTower2::toolchange_Change ( WipeTowerWriter2 & writer,
const size_t new_tool,
const std::string & new_material,
const int wait_for_temp,
const bool wait_beside_tower )
private
1729{
1730 // Ask the writer about how much of the old filament we consumed:
1732 m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length();
1733
1734 // This is where we want to place the custom gcodes. We will use placeholders for this.
1735 // These will be substituted by the actual gcodes when the gcode is generated.
1736 //writer.append("[end_filament_gcode]\n");
1737 writer.append("[change_filament_gcode]\n");
1738
1739 if (m_is_mk4mmu3)
1740 writer.switch_filament_monitoring(true);
1741
1742 const bool wait_for_temp_here = m_wait_for_temp_on_wipe_tower && wait_for_temp > 0;
1743
1744 // The Tn above was issued without a blocking temperature wait (GCode::set_extruder only raises
1745 // the target, ahead of the Tn); block here, before the deretraction below, which must not
1746 // extrude on a cold nozzle. Like the Bambu H2C, park beside the tower for the heat-up so drool lands
1747 // next to it instead of on its top surface — nearest x side first, then that side clamped
1748 // toward the bed edge, then the far side, in place if all would leave the bed. Raw
1749 // pre-rotated moves (see the repositioning move below) keep the writer's tracked position
1750 // at the tower entry. The tag keeps the
1751 // interface-temp deduplication pass in append_tcr2 from stripping the M109.
1752 if (wait_for_temp_here && wait_beside_tower) {
1753 // The rib wall and the stabilization cone bulge past the nominal width rectangle
1754 // (widest near the bottom), and the first-layer brim is printed around the wall later
1755 // in the layer — clear the widest of them, not just the rectangle, so the park point
1756 // and its drool stay off the tower.
1757 float min_x = 0.f, max_x = m_wipe_tower_width;
1758 if (m_wall_type == (int)wtwRib) {
1759 WipeTower::box_coordinates wt_box(Vec2f(0.f, 0.f), m_wipe_tower_width, m_layer_info->depth + m_perimeter_width);
1760 const BoundingBox rib_bbox = get_extents(generate_rib_polygon(wt_box)); // the fillet stays within this bbox
1761 min_x = std::min(min_x, unscaled<float>(rib_bbox.min.x()));
1762 max_x = std::max(max_x, unscaled<float>(rib_bbox.max.x()));
1763 } else if (m_wall_type == (int)wtwCone) {
1766 const double z = m_sparse_layers_skipped ? (m_current_height + m_layer_info->height) : m_layer_info->z;
1767 const double r = std::tan(Geometry::deg2rad(m_wipe_tower_cone_angle / 2.f)) * (m_wipe_tower_height - z);
1768 const double w = m_layer_info->depth + m_perimeter_width;
1769 if (r > 0.5 * w + 0.01) { // same guard as generate_support_cone_wall
1770 const float bulge = float(std::sqrt(r * r - 0.25 * w * w) / support_scale);
1771 min_x = std::min(min_x, m_wipe_tower_width / 2.f - bulge);
1772 max_x = std::max(max_x, m_wipe_tower_width / 2.f + bulge);
1773 }
1774 }
1775 if (is_first_layer()) {
1778 min_x -= brim;
1779 max_x += brim;
1780 }
1781 constexpr float gap = 2.f;
1782 constexpr float min_gap = 0.5f;
1783 const bool on_left = writer.x() < m_wipe_tower_width / 2.f;
1784 const float near_x = on_left ? min_x - gap : max_x + gap;
1785 const float far_x = on_left ? max_x + gap : min_x - gap;
1786 const Eigen::Rotation2Df to_bed(float(Geometry::deg2rad(m_wipe_tower_rotation_angle)));
1787 auto park_pt_on_bed = [this, &writer, to_bed](float side_x) {
1788 const Vec2f bed_pt = to_bed * (writer.rotated(Vec2f(side_x, writer.y())) + m_rib_offset) + m_wipe_tower_pos;
1789 return m_bed_polygon.contains(Point::new_scale(bed_pt.x(), bed_pt.y()));
1790 };
1791 float park_x = near_x;
1792 bool have_park = park_pt_on_bed(near_x);
1793 if (!have_park) {
1794 // The ideal near point hangs off the bed: pull it back to the bed edge as long
1795 // as that still clears the tower envelope by min_gap (the BBL tower clamps its
1796 // stop_pos against the bed the same way in append_tcr). Bisection, because with
1797 // tower rotation and non-rectangular beds the bed edge is not axis-aligned.
1798 const float limit_x = on_left ? min_x - min_gap : max_x + min_gap;
1799 if (park_pt_on_bed(limit_x)) {
1800 float on = limit_x, off = near_x;
1801 for (int i = 0; i < 8; ++i) {
1802 const float mid = 0.5f * (on + off);
1803 if (park_pt_on_bed(mid))
1804 on = mid;
1805 else
1806 off = mid;
1807 }
1808 park_x = on;
1809 have_park = true;
1810 }
1811 }
1812 if (!have_park && park_pt_on_bed(far_x)) {
1813 park_x = far_x;
1814 have_park = true;
1815 }
1816 if (have_park) {
1817 const Vec2f stop = writer.rotated(Vec2f(park_x, writer.y()));
1818 writer.feedrate(m_travel_speed * 60.f)
1819 .append(std::string("G1 X") + Slic3r::float_to_string_decimal_point(stop.x())
1820 + " Y" + Slic3r::float_to_string_decimal_point(stop.y())
1821 + never_skip_tag() + "\n");
1822 }
1823 writer.set_extruder_temp(wait_for_temp, true, wait_for_temp_tag());
1824 }
1825
1826 // Travel to where we assume we are. Custom toolchange or some special T code handling (parking extruder etc)
1827 // gcode could have left the extruder somewhere, we cannot just start extruding. We should also inform the
1828 // postprocessor that we absolutely want to have this in the gcode, even if it thought it is the same as before.
1829 Vec2f current_pos = writer.pos_rotated();
1830 writer.feedrate(m_travel_speed * 60.f) // see https://github.com/prusa3d/PrusaSlicer/issues/5483
1831 .append(std::string("G1 X") + Slic3r::float_to_string_decimal_point(current_pos.x())
1832 + " Y" + Slic3r::float_to_string_decimal_point(current_pos.y())
1833 + never_skip_tag() + "\n"
1834 );
1835
1836 // Priming has no tower to park beside — wait right at the priming line instead.
1837 if (wait_for_temp_here && !wait_beside_tower)
1838 writer.set_extruder_temp(wait_for_temp, true, wait_for_temp_tag());
1839
1840 writer.append("[deretraction_from_wipe_tower_generator]");
1841
1842 // The toolchange Tn command will be inserted later, only in case that the user does
1843 // not provide a custom toolchange gcode.
1844 writer.set_tool(new_tool); // This outputs nothing, the writer just needs to know the tool has changed.
1845 // writer.append("[filament_start_gcode]\n");
1846
1847
1848 writer.flush_planner_queue();
1849 m_current_tool = new_tool;
1850}
static const std::string wait_for_temp_tag()
Definition WipeTower2.hpp:34
static const std::string never_skip_tag()
Definition WipeTower2.hpp:31
std::string float_to_string_decimal_point(double value, int precision)
Definition LocalesUtils.cpp:108

References Slic3r::WipeTowerWriter2::append(), Slic3r::Geometry::deg2rad(), Slic3r::WipeTowerWriter2::feedrate(), Slic3r::float_to_string_decimal_point(), Slic3r::WipeTowerWriter2::flush_planner_queue(), generate_rib_polygon(), Slic3r::WipeTowerWriter2::get_and_reset_used_filament_length(), Slic3r::WipeTower::get_auto_brim_by_height(), Slic3r::get_extents(), get_wipe_tower_cone_base(), is_first_layer(), m_bed_polygon, m_current_height, m_current_tool, m_is_mk4mmu3, m_layer_info, m_perimeter_width, m_rib_offset, m_sparse_layers_skipped, m_travel_speed, m_used_filament_length, m_wait_for_temp_on_wipe_tower, m_wall_type, m_wipe_tower_brim_width, m_wipe_tower_cone_angle, m_wipe_tower_depth, m_wipe_tower_height, m_wipe_tower_pos, m_wipe_tower_rotation_angle, m_wipe_tower_width, Slic3r::BoundingBoxBase< PointType, APointsType >::max, Slic3r::BoundingBoxBase< PointType, APointsType >::min, never_skip_tag(), Slic3r::Point::new_scale(), Slic3r::WipeTowerWriter2::pos_rotated(), Slic3r::WipeTowerWriter2::rotated(), Slic3r::WipeTowerWriter2::set_extruder_temp(), Slic3r::WipeTowerWriter2::set_tool(), Slic3r::WipeTowerWriter2::switch_filament_monitoring(), Slic3r::unscaled(), wait_for_temp_tag(), Slic3r::wtwCone, Slic3r::wtwRib, Slic3r::WipeTowerWriter2::x(), and Slic3r::WipeTowerWriter2::y().

Referenced by prime(), and tool_change().

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

◆ toolchange_entry_pos()

Vec2f Slic3r::WipeTower2::toolchange_entry_pos ( float depth_traversed,
float ramming_depth,
bool first_layer ) const
inlineprivate
342 {
343 Vec2f pos(m_perimeter_width / 2.f, m_perimeter_width / 2.f + depth_traversed);
344 if (!m_semm && m_use_gap_wall && ramming_depth > 0.f)
345 pos.y() += wipe_start_offset_after_ram(ramming_depth, first_layer);
346 return pos;
347 }
float wipe_start_offset_after_ram(float ramming_depth, bool first_layer) const
Definition WipeTower2.hpp:331
Vec3d pos(const Pt &p)
Definition ReprojectPointsOnMesh.hpp:16

References m_perimeter_width, m_semm, m_use_gap_wall, and wipe_start_offset_after_ram().

Referenced by compute_wall_skip_points(), and tool_change().

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

◆ toolchange_Load()

void Slic3r::WipeTower2::toolchange_Load ( WipeTowerWriter2 & writer,
const WipeTower::box_coordinates & cleaning_box )
private
1855{
1857 float xl = cleaning_box.ld.x() + m_perimeter_width * 0.75f;
1858 float xr = cleaning_box.rd.x() - m_perimeter_width * 0.75f;
1859 float oldx = writer.x(); // the nozzle is in place to do the first wiping moves, we will remember the position
1860
1861 // Load the filament while moving left / right, so the excess material will not create a blob at a single position.
1862 float turning_point = ( oldx-xl < xr-oldx ? xr : xl );
1864
1865 writer.append("; CP TOOLCHANGE LOAD\n")
1866 .suppress_preview()
1867 .load(0.2f * edist, 60.f * m_filpar[m_current_tool].loading_speed_start)
1868 .load_move_x_advanced(turning_point, 0.7f * edist, m_filpar[m_current_tool].loading_speed) // Fast phase
1869 .load_move_x_advanced(oldx, 0.1f * edist, 0.1f * m_filpar[m_current_tool].loading_speed) // Super slow*/
1870
1871 .travel(oldx, writer.y()) // in case last move was shortened to limit x feedrate
1872 .resume_preview();
1873
1874 // Reset the extruder current to the normal value.
1876 writer.set_extruder_trimpot(550);
1877 }
1878}

References Slic3r::WipeTowerWriter2::append(), Slic3r::WipeTower::box_coordinates::ld, Slic3r::WipeTowerWriter2::load(), Slic3r::WipeTowerWriter2::load_move_x_advanced(), m_current_tool, m_enable_filament_ramming, m_extra_loading_move, m_filpar, m_parking_pos_retraction, m_perimeter_width, m_semm, m_set_extruder_trimpot, Slic3r::WipeTower::box_coordinates::rd, Slic3r::WipeTowerWriter2::resume_preview(), Slic3r::WipeTowerWriter2::set_extruder_trimpot(), Slic3r::WipeTowerWriter2::suppress_preview(), Slic3r::WipeTowerWriter2::travel(), Slic3r::WipeTowerWriter2::x(), and Slic3r::WipeTowerWriter2::y().

Referenced by prime(), and tool_change().

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

◆ toolchange_Unload()

void Slic3r::WipeTower2::toolchange_Unload ( WipeTowerWriter2 & writer,
const WipeTower::box_coordinates & cleaning_box,
const std::string & current_material,
const int old_temperature,
const int new_temperature )
private
1466{
1467 float xl = cleaning_box.ld.x() + 1.f * m_perimeter_width;
1468 float xr = cleaning_box.rd.x() - 1.f * m_perimeter_width;
1469
1470 const float line_width = m_perimeter_width * m_filpar[m_current_tool].ramming_line_width_multiplicator; // desired ramming line thickness
1471 const float y_step = line_width * m_filpar[m_current_tool].ramming_step_multiplicator * m_extra_spacing_ramming; // spacing between lines in mm
1472
1473 const Vec2f ramming_start_pos = Vec2f(xl, cleaning_box.ld.y() + m_depth_traversed + y_step/2.f);
1474
1475 writer.append("; CP TOOLCHANGE UNLOAD\n")
1476 .change_analyzer_line_width(line_width);
1477
1478 unsigned i = 0; // iterates through ramming_speed
1479 m_left_to_right = true; // current direction of ramming
1480 float remaining = xr - xl ; // keeps track of distance to the next turnaround
1481 float e_done = 0; // measures E move done from each segment
1482
1483 const bool do_ramming = tool_ramming_enabled(m_current_tool);
1484 const bool cold_ramming = m_is_mk4mmu3;
1485 // Orca: see set_toolchange() — quantized ram band + wipe restart at the boundary.
1486 const bool boundary_wipe_start = boundary_wipe_start_enabled(m_current_tool);
1487 float planned_ramming_depth = 0.f;
1488 if (boundary_wipe_start && m_layer_info != m_plan.end())
1489 for (const auto& tch : m_layer_info->tool_changes)
1490 if (tch.old_tool == m_current_tool) { planned_ramming_depth = tch.ramming_depth; break; }
1491
1492 if (do_ramming) {
1493 if (boundary_wipe_start)
1494 // The entry sits at the wall gap on the first wipe row past the reserved
1495 // ram band; step inward first, then move to the band clear of the wall.
1496 writer.travel(Vec2f(ramming_start_pos.x(), writer.y()));
1497 writer.travel(ramming_start_pos); // move to starting position
1498 if (! m_is_mk4mmu3)
1499 writer.disable_linear_advance();
1500 if (cold_ramming)
1501 writer.set_extruder_temp(old_temperature - 20);
1502 }
1503 else
1504 writer.set_position(ramming_start_pos);
1505
1506 // if the ending point of the ram would end up in mid air, align it with the end of the wipe tower:
1507 // (with a boundary wipe start the band is quantized to whole rows below, so no phase alignment is needed)
1508 if (do_ramming && !boundary_wipe_start && (m_layer_info > m_plan.begin() && m_layer_info < m_plan.end() && (m_layer_info-1!=m_plan.begin() || !m_adhesion ))) {
1509
1510 // this is y of the center of previous sparse infill border
1511 float sparse_beginning_y = 0.f;
1513 sparse_beginning_y += ((m_layer_info-1)->depth - (m_layer_info-1)->toolchanges_depth())
1514 - ((m_layer_info)->depth-(m_layer_info)->toolchanges_depth()) ;
1515 else
1516 sparse_beginning_y += (m_layer_info-1)->toolchanges_depth() + m_perimeter_width;
1517
1518 float sum_of_depths = 0.f;
1519 for (const auto& tch : m_layer_info->tool_changes) { // let's find this toolchange
1520 if (tch.old_tool == m_current_tool) {
1521 sum_of_depths += tch.ramming_depth;
1522 float ramming_end_y = sum_of_depths;
1523 ramming_end_y -= (y_step/m_extra_spacing_ramming-m_perimeter_width) / 2.f; // center of final ramming line
1524
1525 if ( (m_current_shape == SHAPE_REVERSED && ramming_end_y < sparse_beginning_y - 0.5f*m_perimeter_width ) ||
1526 (m_current_shape == SHAPE_NORMAL && ramming_end_y > sparse_beginning_y + 0.5f*m_perimeter_width ) )
1527 {
1528 writer.extrude(xl + tch.first_wipe_line-1.f*m_perimeter_width,writer.y());
1529 remaining -= tch.first_wipe_line-1.f*m_perimeter_width;
1530 }
1531 break;
1532 }
1533 sum_of_depths += tch.required_depth;
1534 }
1535 }
1536
1537 if (m_is_mk4mmu3) {
1538 writer.switch_filament_monitoring(false);
1539 writer.wait(1.5f);
1540 }
1541
1542
1543 // now the ramming itself:
1544 while (do_ramming && i < m_filpar[m_current_tool].ramming_speed.size())
1545 {
1546 // The time step is different for SEMM ramming and the MM ramming. See comments in set_extruder() for details.
1547 const float time_step = m_semm ? 0.25f : m_filpar[m_current_tool].multitool_ramming_time;
1548
1549 const float x = volume_to_length(m_filpar[m_current_tool].ramming_speed[i] * time_step, line_width, m_layer_height);
1550 const float e = m_filpar[m_current_tool].ramming_speed[i] * time_step / filament_area(); // transform volume per sec to E move;
1551 const float dist = std::min(x - e_done, remaining); // distance to travel for either the next time_step, or to the next turnaround
1552 const float actual_time = dist/x * time_step;
1553 writer.ram(writer.x(), writer.x() + (m_left_to_right ? 1.f : -1.f) * dist, 0.f, 0.f, e * (dist / x), dist / (actual_time / 60.f));
1554 remaining -= dist;
1555
1556 if (remaining < WT_EPSILON) { // we reached a turning point
1557 writer.travel(writer.x(), writer.y() + y_step, 7200);
1559 remaining = xr - xl;
1560 }
1561 e_done += dist; // subtract what was actually done
1562 if (e_done > x - WT_EPSILON) { // current segment finished
1563 ++i;
1564 e_done = 0;
1565 }
1566 }
1567
1568 // Orca: quantize the ram band up to the whole reserved rows (BBL quantizes the
1569 // old-tool purge the same way) so no unprinted void is left between the band and
1570 // the wipe restarting at the boundary below it.
1571 if (planned_ramming_depth > 0.f) {
1572 const int reserved_rows = std::max(1, int(std::round(planned_ramming_depth / y_step)));
1573 const float last_row_y = ramming_start_pos.y() + (reserved_rows - 1) * y_step;
1574 // Same bead model as the ramming segments above: E per mm of ram line.
1575 const float e_per_mm = 1.f / (volume_to_length(1.f, line_width, m_layer_height) * filament_area());
1576 const float fill_feed = m_filpar[m_current_tool].ramming_speed.empty() ? 3000.f :
1577 60.f * volume_to_length(m_filpar[m_current_tool].ramming_speed.back(), line_width, m_layer_height);
1578 while (true) {
1579 const float target_x = m_left_to_right ? xr : xl;
1580 if (std::abs(target_x - writer.x()) > WT_EPSILON)
1581 writer.ram(writer.x(), target_x, 0.f, 0.f, e_per_mm * std::abs(target_x - writer.x()), fill_feed);
1582 if (writer.y() + 0.5f * y_step > last_row_y)
1583 break;
1584 writer.travel(writer.x(), writer.y() + y_step, 7200);
1586 }
1587 }
1588
1589 Vec2f end_of_ramming(writer.x(),writer.y());
1590 writer.change_analyzer_line_width(m_perimeter_width); // so the next lines are not affected by ramming_line_width_multiplier
1591
1592 // Retraction:
1594 writer.append("; Ramming start\n");
1595
1596 float old_x = writer.x();
1597 float turning_point = (!m_left_to_right ? xl : xr );
1599 writer.append("; Retract(unload)\n");
1600 float total_retraction_distance = m_cooling_tube_retraction + m_cooling_tube_length/2.f - 15.f; // the 15mm is reserved for the first part after ramming
1601 writer.suppress_preview()
1602 .retract(15.f, m_filpar[m_current_tool].unloading_speed_start * 60.f) // feedrate 5000mm/min = 83mm/s
1603 .retract(0.70f * total_retraction_distance, 1.0f * m_filpar[m_current_tool].unloading_speed * 60.f)
1604 .retract(0.20f * total_retraction_distance, 0.5f * m_filpar[m_current_tool].unloading_speed * 60.f)
1605 .retract(0.10f * total_retraction_distance, 0.3f * m_filpar[m_current_tool].unloading_speed * 60.f)
1606 .resume_preview();
1607 }
1608
1609 const int& number_of_cooling_moves = m_filpar[m_current_tool].cooling_moves;
1610 const bool cooling_will_happen = m_enable_filament_ramming && m_semm && number_of_cooling_moves > 0 && m_cooling_tube_length != 0;
1611 bool change_temp_later = false;
1612
1613 // Wipe tower should only change temperature with single extruder MM. Otherwise, all temperatures should
1614 // be already set and there is no need to change anything. Also, the temperature could be changed
1615 // for wrong extruder.
1616 if (m_semm) {
1617 if (new_temperature != 0 && (new_temperature != m_old_temperature || is_first_layer() || cold_ramming) ) { // Set the extruder temperature, but don't wait.
1618 // If the required temperature is the same as last time, don't emit the M104 again (if user adjusted the value, it would be reset)
1619 // However, always change temperatures on the first layer (this is to avoid issues with priming lines turned off).
1620 if (cold_ramming && cooling_will_happen)
1621 change_temp_later = true;
1622 else
1623 writer.set_extruder_temp(new_temperature, false);
1624 m_old_temperature = new_temperature;
1625 }
1626 }
1627
1628 // Cooling:
1629 if (cooling_will_happen) {
1630 writer.append("; Cooling\n");
1631 const float& initial_speed = m_filpar[m_current_tool].cooling_initial_speed;
1632 const float& final_speed = m_filpar[m_current_tool].cooling_final_speed;
1633
1634 float speed_inc = (final_speed - initial_speed) / (2.f * number_of_cooling_moves - 1.f);
1635
1636 if (m_is_mk4mmu3)
1637 writer.disable_linear_advance();
1638
1639 writer.suppress_preview()
1640 .travel(writer.x(), writer.y() + y_step);
1641 old_x = writer.x();
1642 turning_point = xr-old_x > old_x-xl ? xr : xl;
1643 float stamping_dist_e = m_filpar[m_current_tool].filament_stamping_distance + m_cooling_tube_length / 2.f;
1644
1645 for (int i=0; i<number_of_cooling_moves; ++i) {
1646
1647 // Stamping - happens after every cooling move except for the last one.
1648 if (i>0 && m_filpar[m_current_tool].filament_stamping_distance != 0) {
1649
1650 // Stamping turning point shall be no farther than 20mm from the current nozzle position:
1651 float stamping_turning_point = std::clamp(old_x + 20.f * (turning_point - old_x > 0.f ? 1.f : -1.f), xl, xr);
1652
1653 // Only last 5mm will be done with the fast x travel. The point is to spread possible blobs
1654 // along the whole wipe tower.
1655 if (stamping_dist_e > 5) {
1656 float cent = writer.x();
1657 writer.load_move_x_advanced(stamping_turning_point, (stamping_dist_e - 5), m_filpar[m_current_tool].filament_stamping_loading_speed, 200);
1658 writer.load_move_x_advanced(cent, 5, m_filpar[m_current_tool].filament_stamping_loading_speed, m_travel_speed);
1659 writer.travel(cent, writer.y());
1660 } else
1661 writer.load_move_x_advanced_there_and_back(stamping_turning_point, stamping_dist_e, m_filpar[m_current_tool].filament_stamping_loading_speed, m_travel_speed);
1662
1663 // Retract while the print head is stationary, so if there is a blob, it is not dragged along.
1664 writer.retract(stamping_dist_e, m_filpar[m_current_tool].unloading_speed * 60.f);
1665 }
1666
1667 if (i == number_of_cooling_moves - 1 && change_temp_later) {
1668 // If cold_ramming, the temperature change should be done before the last cooling move.
1669 writer.set_extruder_temp(new_temperature, false);
1670 }
1671
1672 float speed = initial_speed + speed_inc * 2*i;
1673 writer.load_move_x_advanced(turning_point, m_cooling_tube_length, speed);
1674 speed += speed_inc;
1675 writer.load_move_x_advanced(old_x, -m_cooling_tube_length, speed);
1676 }
1677 }
1678
1680 writer.append("; Cooling park\n");
1681 // let's wait is necessary:
1682 writer.wait(m_filpar[m_current_tool].delay);
1683 // we should be at the beginning of the cooling tube again - let's move to parking position:
1685 if (_e != 0.f)
1686 writer.retract(_e, 2000);
1687 }
1688
1690 writer.append("; Ramming end\n");
1691
1692
1693 // this is to align ramming and future wiping extrusions, so the future y-steps can be uniform from the start:
1694 // the perimeter_width will later be subtracted, it is there to not load while moving over just extruded material
1695 Vec2f pos = Vec2f(end_of_ramming.x(), end_of_ramming.y() + (y_step/m_extra_spacing_ramming-m_perimeter_width) / 2.f + m_perimeter_width);
1696 if (planned_ramming_depth > 0.f) {
1697 // Orca: restart the wipe at the left-edge boundary on a fresh row below the
1698 // quantized ram band so the entry scrub always runs at the wall gap (BBL keeps
1699 // CP_TOOLCHANGE_WIPE starting at a box corner the same way). Same lattice
1700 // formula as the no-ram branch below, offset by the ram band.
1701 writer.travel(Vec2f(ramming_start_pos.x(),
1702 cleaning_box.ld.y() + m_depth_traversed +
1703 wipe_start_offset_after_ram(planned_ramming_depth, is_first_layer()) + m_perimeter_width), 2400.f);
1704 m_left_to_right = true;
1705 }
1706 else if (do_ramming)
1707 writer.travel(pos, 2400.f);
1708 else {
1709 // Orca: with no ram printed there is no ramming geometry to align with. Start the
1710 // first wipe row so the purge row lattice continues across the block boundary
1711 // (previous box's last row top edge sits at its box top): with the planned depth
1712 // of rows * dy, the last row's top edge then lands exactly on this box's top and
1713 // no blank band is left between adjacent purge blocks.
1714 writer.set_position(Vec2f(end_of_ramming.x(),
1716 }
1717
1718 writer.resume_preview()
1719 .flush_planner_queue();
1720}
zaa_minimize_perimeter_height filament_stamping_loading_speed((ConfigOptionFloats, filament_stamping_distance))((ConfigOptionEnum< WipeTowerType >

References Slic3r::WipeTowerWriter2::append(), boundary_wipe_start_enabled(), Slic3r::WipeTowerWriter2::change_analyzer_line_width(), Slic3r::WipeTowerWriter2::disable_linear_advance(), Slic3r::Geometry::dist(), Slic3r::WipeTowerWriter2::extrude(), filament_area(), Slic3r::filament_stamping_loading_speed(), Slic3r::WipeTowerWriter2::flush_planner_queue(), is_first_layer(), Slic3r::WipeTower::box_coordinates::ld, Slic3r::WipeTowerWriter2::load_move_x_advanced(), Slic3r::WipeTowerWriter2::load_move_x_advanced_there_and_back(), m_adhesion, m_cooling_tube_length, m_cooling_tube_retraction, m_current_shape, m_current_tool, m_depth_traversed, m_enable_filament_ramming, m_extra_spacing_ramming, m_filpar, m_is_mk4mmu3, m_layer_height, m_layer_info, m_left_to_right, m_old_temperature, m_parking_pos_retraction, m_perimeter_width, m_plan, m_semm, m_travel_speed, Slic3r::WipeTowerWriter2::ram(), Slic3r::WipeTower::box_coordinates::rd, Slic3r::WipeTowerWriter2::resume_preview(), Slic3r::WipeTowerWriter2::retract(), Slic3r::WipeTowerWriter2::set_extruder_temp(), Slic3r::WipeTowerWriter2::set_position(), SHAPE_NORMAL, SHAPE_REVERSED, Slic3r::WipeTowerWriter2::suppress_preview(), Slic3r::WipeTowerWriter2::switch_filament_monitoring(), tool_ramming_enabled(), Slic3r::WipeTowerWriter2::travel(), Slic3r::volume_to_length(), Slic3r::WipeTowerWriter2::wait(), wipe_start_offset_after_ram(), WT_EPSILON, Slic3r::WipeTowerWriter2::x(), and Slic3r::WipeTowerWriter2::y().

Referenced by prime(), and tool_change().

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

◆ toolchange_Wipe()

void Slic3r::WipeTower2::toolchange_Wipe ( WipeTowerWriter2 & writer,
const WipeTower::box_coordinates & cleaning_box,
float wipe_volume,
bool interface_layer,
bool priming = false,
bool fill_box = false )
private
1888{
1889 // Increase flow on first layer, slow down print.
1890 writer.set_extrusion_flow(m_extrusion_flow * (is_first_layer() ? 1.18f : 1.f))
1891 .append("; CP TOOLCHANGE WIPE\n");
1892 const float& xl = cleaning_box.ld.x();
1893 const float& xr = cleaning_box.rd.x();
1894
1895 writer.set_extrusion_flow(m_extrusion_flow * m_extra_flow);
1896 const float line_width = wipe_line_width();
1897 writer.change_analyzer_line_width(line_width);
1898
1899 // Variables x_to_wipe and traversed_x are here to be able to make sure it always wipes at least
1900 // the ordered volume, even if it means violating the box. This can later be removed and simply
1901 // wipe until the end of the assigned area.
1902
1903 float x_to_wipe = volume_to_length(wipe_volume, m_perimeter_width, m_layer_height) / m_extra_flow;
1904 float dy = wipe_row_spacing(is_first_layer()); // Don't use the extra spacing for the first layer, but do use the spacing resulting from increased flow.
1905 // All the calculations in all other places take the spacing into account for all the layers.
1906
1907 // If spare layers are excluded->if 1 or less toolchange has been done, it must be sill the first layer, too.So slow down.
1908 const float target_speed = is_first_layer() || (m_num_tool_changes <= 1 && m_sparse_layers_skipped) ? m_first_layer_speed * 60.f : std::min(m_wipe_tower_max_purge_speed * 60.f, m_infill_speed * 60.f);
1909 float wipe_speed = 0.33f * target_speed;
1910
1911 // if there is less than 2.5*line_width to the edge, advance straightaway (there is likely a blob anyway)
1912 if ((m_left_to_right ? xr-writer.x() : writer.x()-xl) < 2.5f*line_width) {
1913 writer.travel((m_left_to_right ? xr-line_width : xl+line_width),writer.y()+dy);
1914 m_left_to_right = !m_left_to_right;
1915 }
1916
1917 // now the wiping itself:
1918 for (int i = 0; true; ++i) {
1919 if (i!=0) {
1920 if (wipe_speed < 0.34f * target_speed) wipe_speed = 0.375f * target_speed;
1921 else if (wipe_speed < 0.377 * target_speed) wipe_speed = 0.458f * target_speed;
1922 else if (wipe_speed < 0.46f * target_speed) wipe_speed = 0.875f * target_speed;
1923 else wipe_speed = std::min(target_speed, wipe_speed + 50.f);
1924 }
1925
1926 float traversed_x = writer.x();
1927
1928 // BBS gap wall: iron the first few mm of the purge, then drag the retracted nozzle
1929 // back out through the wall gap and scrub it with a dry spiral centred on the entry
1930 // point so the toolchange start blob is not left on the wall (same sequence as the
1931 // BBL tower's toolchange_wipe_new; the spiral self-disables when the filament's
1932 // tower ironing area is 0). WT2's entry gap always sits at the left-edge entry
1933 // point, so only iron when the purge actually starts there heading right (in-place
1934 // toolchangers do; SEMM ram/cooling moves leave the nozzle mid-box, far from any gap).
1935 if (i == 0 && m_use_gap_wall && !interface_layer && !priming && m_left_to_right &&
1936 writer.x() - xl < 2.5f * line_width) {
1937 float ironing_length = 3.f;
1938 if (xr - writer.x() < ironing_length)
1939 ironing_length = std::max(xr - writer.x(), 0.f);
1940 const float retract_length = m_filpar[m_current_tool].retract_length;
1941 const float retract_speed = m_filpar[m_current_tool].retract_speed * 60.f;
1942 writer.extrude(writer.x() + ironing_length, writer.y(), wipe_speed);
1943 writer.retract(retract_length, retract_speed);
1944 writer.travel(writer.x() - 1.5f * ironing_length, writer.y(), 600.f);
1945 writer.travel(writer.x() + 0.5f * ironing_length, writer.y(), 240.f);
1946 const Vec2f iron_end(writer.x() + ironing_length, writer.y());
1947 writer.spiral_flat_ironing(writer.pos(), m_filpar[m_current_tool].tower_ironing_area, m_perimeter_width, flat_iron_speed);
1948 writer.travel(iron_end, wipe_speed);
1949 writer.retract(-retract_length, retract_speed);
1950 }
1951
1952 if (m_left_to_right)
1953 writer.extrude(xr - (i % 4 == 0 ? 0 : 1.5f*line_width), writer.y(), wipe_speed);
1954 else
1955 writer.extrude(xl + (i % 4 == 1 ? 0 : 1.5f*line_width), writer.y(), wipe_speed);
1956
1957 if (writer.y()+float(EPSILON) > cleaning_box.lu.y()-0.5f*line_width)
1958 break; // in case next line would not fit
1959
1960 traversed_x -= writer.x();
1961 x_to_wipe -= std::abs(traversed_x);
1962 // Orca: with no ram printed the box was planned as whole wipe rows; fill it
1963 // completely (quantizing the purge up to the planned rows) so the next block
1964 // can start right above it without a blank band in between.
1965 if (!fill_box && x_to_wipe < WT_EPSILON) {
1966 writer.travel(m_left_to_right ? xl + 1.5f*line_width : xr - 1.5f*line_width, writer.y(), 7200);
1967 break;
1968 }
1969 // stepping to the next line:
1970 writer.extrude(writer.x() + (i % 4 == 0 ? -1.f : (i % 4 == 1 ? 1.f : 0.f)) * 1.5f*line_width, writer.y() + dy);
1972 }
1973
1974 // We may be going back to the model - wipe the nozzle. If this is followed
1975 // by finish_layer, this wipe path will be overwritten.
1976 writer.add_wipe_point(writer.x(), writer.y())
1977 .add_wipe_point(writer.x(), writer.y() - dy)
1978 .add_wipe_point(! m_left_to_right ? m_wipe_tower_width : 0.f, writer.y() - dy);
1979
1980 if (m_layer_info != m_plan.end() && m_current_tool != m_layer_info->tool_changes.back().new_tool)
1982
1983 writer.set_extrusion_flow(m_extrusion_flow); // Reset the extrusion flow.
1984 writer.change_analyzer_line_width(m_perimeter_width);
1985}
float wipe_row_spacing(bool first_layer) const
Definition WipeTower2.hpp:319
float wipe_line_width() const
Definition WipeTower2.hpp:320
float flat_iron_speed
Definition WipeTower.cpp:43

References Slic3r::WipeTowerWriter2::add_wipe_point(), Slic3r::WipeTowerWriter2::append(), Slic3r::WipeTowerWriter2::change_analyzer_line_width(), EPSILON, Slic3r::WipeTowerWriter2::extrude(), Slic3r::flat_iron_speed, is_first_layer(), Slic3r::WipeTower::box_coordinates::ld, Slic3r::WipeTower::box_coordinates::lu, m_current_tool, m_extra_flow, m_extrusion_flow, m_filpar, m_first_layer_speed, m_infill_speed, m_layer_height, m_layer_info, m_left_to_right, m_num_tool_changes, m_perimeter_width, m_plan, m_sparse_layers_skipped, m_use_gap_wall, m_wipe_tower_max_purge_speed, m_wipe_tower_width, Slic3r::WipeTowerWriter2::pos(), Slic3r::WipeTower::box_coordinates::rd, Slic3r::WipeTowerWriter2::retract(), Slic3r::WipeTowerWriter2::set_extrusion_flow(), Slic3r::WipeTowerWriter2::spiral_flat_ironing(), Slic3r::WipeTowerWriter2::travel(), Slic3r::volume_to_length(), wipe_line_width(), wipe_row_spacing(), WT_EPSILON, Slic3r::WipeTowerWriter2::x(), and Slic3r::WipeTowerWriter2::y().

Referenced by prime(), and tool_change().

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

◆ use_gap_wall()

bool Slic3r::WipeTower2::use_gap_wall ( const PrintConfig & config)
static
1030{
1031 // The cone wall has its own fully separate generator with no gap machinery.
1032 return config.prime_tower_skip_points.value && config.wipe_tower_wall_type.value != wtwCone;
1033}

References Slic3r::wtwCone.

Referenced by WipeTower2(), Slic3r::WipeTowerIntegration::append_tcr2(), and Slic3r::WipeTowerIntegration::travel_to_tower_gap().

Here is the caller graph for this function:

◆ wait_for_temp_enabled()

bool Slic3r::WipeTower2::wait_for_temp_enabled ( const PrintConfig & config)
static
1036{
1037 // SEMM runs its own unload/load temperature sequence; the GUI hides the option
1038 // there but a profile may still carry it set.
1039 return config.wait_for_temp_on_wipe_tower.value && !config.single_extruder_multi_material.value;
1040}

Referenced by WipeTower2(), Slic3r::WipeTowerIntegration::append_tcr2(), and Slic3r::Print::invalidate_state_by_config_options().

Here is the caller graph for this function:

◆ wait_for_temp_tag()

const std::string Slic3r::WipeTower2::wait_for_temp_tag ( )
inlinestatic
34{ return ";_WAIT_FOR_TEMP_ON_WIPE_TOWER"; }

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

Here is the caller graph for this function:

◆ width()

float Slic3r::WipeTower2::width ( ) const
inline
144{ return m_wipe_tower_width; }

References m_wipe_tower_width.

Referenced by Slic3r::Print::_make_wipe_tower(), cone_base_polygon(), get_wipe_tower_cone_base(), save_on_last_wipe(), and set_toolchange().

Here is the caller graph for this function:

◆ wipe_line_width()

float Slic3r::WipeTower2::wipe_line_width ( ) const
inlineprivate

References m_extra_flow, and m_perimeter_width.

Referenced by toolchange_Wipe(), and wipe_start_offset_after_ram().

Here is the caller graph for this function:

◆ wipe_row_spacing()

float Slic3r::WipeTower2::wipe_row_spacing ( bool first_layer) const
inlineprivate
319{ return (first_layer ? m_extra_flow : m_extra_spacing_wipe) * m_perimeter_width; }

References m_extra_flow, m_extra_spacing_wipe, and m_perimeter_width.

Referenced by toolchange_Wipe(), and wipe_start_offset_after_ram().

Here is the caller graph for this function:

◆ wipe_start_offset_after_ram()

float Slic3r::WipeTower2::wipe_start_offset_after_ram ( float ramming_depth,
bool first_layer ) const
inlineprivate
332 {
333 return ramming_depth + wipe_row_spacing(first_layer) - (m_perimeter_width + wipe_line_width()) / 2.f;
334 }

References m_perimeter_width, wipe_line_width(), and wipe_row_spacing().

Referenced by toolchange_entry_pos(), and toolchange_Unload().

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

Member Data Documentation

◆ m_adhesion

bool Slic3r::WipeTower2::m_adhesion = true
private

Referenced by finish_layer(), and toolchange_Unload().

◆ m_bed_bottom_left

Vec2f Slic3r::WipeTower2::m_bed_bottom_left
private

Referenced by WipeTower2(), and prime().

◆ m_bed_polygon

Polygon Slic3r::WipeTower2::m_bed_polygon
private

Referenced by WipeTower2(), and toolchange_Change().

◆ []

enum { ... } Slic3r::WipeTower2::m_bed_shape

Referenced by WipeTower2(), and prime().

◆ m_bed_width

float Slic3r::WipeTower2::m_bed_width
private

Referenced by WipeTower2(), and prime().

◆ m_bridging

float Slic3r::WipeTower2::m_bridging = 0.f
private

Referenced by WipeTower2(), and finish_layer().

◆ m_cooling_tube_length

float Slic3r::WipeTower2::m_cooling_tube_length = 0.f
private

Referenced by WipeTower2(), and toolchange_Unload().

◆ m_cooling_tube_retraction

float Slic3r::WipeTower2::m_cooling_tube_retraction = 0.f
private

Referenced by WipeTower2(), and toolchange_Unload().

◆ m_current_height

float Slic3r::WipeTower2::m_current_height = 0.f
private

◆ m_current_layer_finished

bool Slic3r::WipeTower2::m_current_layer_finished = false
private

◆ m_current_layer_has_interface

bool Slic3r::WipeTower2::m_current_layer_has_interface = false
private

Referenced by set_layer(), and tool_change().

◆ m_current_shape

wipe_shape Slic3r::WipeTower2::m_current_shape = SHAPE_NORMAL
private

◆ m_current_tool

◆ m_depth_traversed

float Slic3r::WipeTower2::m_depth_traversed = 0.f
private

◆ m_enable_arc_fitting

bool Slic3r::WipeTower2::m_enable_arc_fitting = false
private

◆ m_enable_filament_ramming

bool Slic3r::WipeTower2::m_enable_filament_ramming = true
private

◆ m_enable_tower_interface_cooldown_during_tower

bool Slic3r::WipeTower2::m_enable_tower_interface_cooldown_during_tower = false
private

Referenced by WipeTower2(), and tool_change().

◆ m_enable_tower_interface_features

bool Slic3r::WipeTower2::m_enable_tower_interface_features = false
private

◆ m_extra_flow

float Slic3r::WipeTower2::m_extra_flow = 1.f
private

◆ m_extra_loading_move

float Slic3r::WipeTower2::m_extra_loading_move = 0.f
private

Referenced by WipeTower2(), and toolchange_Load().

◆ m_extra_rib_length

float Slic3r::WipeTower2::m_extra_rib_length = 0
private

Referenced by WipeTower2(), and generate().

◆ m_extra_spacing_ramming

float Slic3r::WipeTower2::m_extra_spacing_ramming = 1.f
private

◆ m_extra_spacing_wipe

float Slic3r::WipeTower2::m_extra_spacing_wipe = 1.f
private

◆ m_extrusion_flow

float Slic3r::WipeTower2::m_extrusion_flow = 0.038f
private

◆ m_filpar

◆ m_first_layer_bbx

BoundingBoxf Slic3r::WipeTower2::m_first_layer_bbx
private

Referenced by finish_layer(), and get_bbx().

◆ m_first_layer_idx

size_t Slic3r::WipeTower2::m_first_layer_idx = size_t(-1)
private

◆ m_first_layer_speed

float Slic3r::WipeTower2::m_first_layer_speed = 0.f
private

◆ m_gcode_flavor

GCodeFlavor Slic3r::WipeTower2::m_gcode_flavor
private

◆ m_infill_speed

float Slic3r::WipeTower2::m_infill_speed = 0.f
private

◆ m_internal_rotation

float Slic3r::WipeTower2::m_internal_rotation = 0.f
private

Referenced by finish_layer(), generate(), and tool_change().

◆ m_is_mk4mmu3

bool Slic3r::WipeTower2::m_is_mk4mmu3 = false
private

◆ m_layer_height

float Slic3r::WipeTower2::m_layer_height = 0.f
private

◆ m_layer_info

◆ m_left_to_right

bool Slic3r::WipeTower2::m_left_to_right = true
private

◆ m_max_color_changes

size_t Slic3r::WipeTower2::m_max_color_changes = 0
private

Referenced by finished().

◆ m_num_layer_changes

unsigned int Slic3r::WipeTower2::m_num_layer_changes = 0
private

Referenced by finish_layer(), and set_layer().

◆ m_num_tool_changes

unsigned int Slic3r::WipeTower2::m_num_tool_changes = 0
private

◆ m_old_temperature

int Slic3r::WipeTower2::m_old_temperature = -1
private

Referenced by generate(), prime(), and toolchange_Unload().

◆ m_parking_pos_retraction

float Slic3r::WipeTower2::m_parking_pos_retraction = 0.f
private

◆ m_perimeter_speed

float Slic3r::WipeTower2::m_perimeter_speed = 0.f
private

Referenced by WipeTower2(), and finish_layer().

◆ m_perimeter_width

◆ m_plan

◆ m_prev_layer_had_interface

bool Slic3r::WipeTower2::m_prev_layer_had_interface = false
private

Referenced by finish_layer(), and set_layer().

◆ m_rib_length

float Slic3r::WipeTower2::m_rib_length = 0
private

◆ m_rib_offset

Vec2f Slic3r::WipeTower2::m_rib_offset = Vec2f::Zero()
private

◆ m_rib_width

float Slic3r::WipeTower2::m_rib_width = 10
private

◆ m_semm

◆ m_set_extruder_trimpot

bool Slic3r::WipeTower2::m_set_extruder_trimpot = false
private

◆ m_sparse_layers_combined

bool Slic3r::WipeTower2::m_sparse_layers_combined = false
private

Referenced by WipeTower2(), and generate().

◆ m_sparse_layers_skipped

bool Slic3r::WipeTower2::m_sparse_layers_skipped = false
private

◆ m_travel_speed

float Slic3r::WipeTower2::m_travel_speed = 0.f
private

◆ m_use_gap_wall

bool Slic3r::WipeTower2::m_use_gap_wall = false
private

◆ m_used_filament_length

std::vector<float> Slic3r::WipeTower2::m_used_filament_length
private

◆ m_used_filament_length_until_layer

std::vector<std::pair<float, std::vector<float> > > Slic3r::WipeTower2::m_used_filament_length_until_layer
private

◆ m_used_fillet

bool Slic3r::WipeTower2::m_used_fillet = true
private

◆ m_wait_for_temp_on_wipe_tower

bool Slic3r::WipeTower2::m_wait_for_temp_on_wipe_tower = false
private

◆ m_wall_skip_points

std::vector<std::vector<Vec2f> > Slic3r::WipeTower2::m_wall_skip_points
private

◆ m_wall_type

int Slic3r::WipeTower2::m_wall_type
private

◆ m_wipe_tower_brim_width

float Slic3r::WipeTower2::m_wipe_tower_brim_width = 0.f
private

◆ m_wipe_tower_brim_width_real

float Slic3r::WipeTower2::m_wipe_tower_brim_width_real = 0.f
private

◆ m_wipe_tower_cone_angle

float Slic3r::WipeTower2::m_wipe_tower_cone_angle = 0.f
private

◆ m_wipe_tower_depth

◆ m_wipe_tower_filament

int Slic3r::WipeTower2::m_wipe_tower_filament = 0
private

◆ m_wipe_tower_height

◆ m_wipe_tower_max_purge_speed

float Slic3r::WipeTower2::m_wipe_tower_max_purge_speed = 90.f
private

◆ m_wipe_tower_pos

Vec2f Slic3r::WipeTower2::m_wipe_tower_pos
private

◆ m_wipe_tower_rotation_angle

float Slic3r::WipeTower2::m_wipe_tower_rotation_angle = 0.f
private

Referenced by WipeTower2(), and toolchange_Change().

◆ m_wipe_tower_width

◆ m_y_shift

float Slic3r::WipeTower2::m_y_shift = 0.f
private

◆ m_z_pos

float Slic3r::WipeTower2::m_z_pos = 0.f
private

◆ Width_To_Nozzle_Ratio

const float Slic3r::WipeTower2::Width_To_Nozzle_Ratio = 1.25f
private

Referenced by set_extruder().

◆ wipe_volumes

const std::vector<std::vector<float> > Slic3r::WipeTower2::wipe_volumes
private

◆ WT_EPSILON

const float Slic3r::WipeTower2::WT_EPSILON = 1e-3f
private

The documentation for this class was generated from the following files:
  • /home/runner/work/OrcaSlicer/OrcaSlicer/src/libslic3r/GCode/WipeTower2.hpp
  • /home/runner/work/OrcaSlicer/OrcaSlicer/src/libslic3r/GCode/WipeTower2.cpp