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

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

Collaboration diagram for Slic3r::WipeTower:

Classes

struct  PurgeEstimate
struct  Extrusion
struct  NozzleChangeResult
struct  ToolChangeResult
struct  box_coordinates
struct  FilamentParameters
struct  WipeTowerBlock
struct  BlockDepthInfo
struct  WipeTowerInfo

Public Types

enum class  WipeTowerLayerType : unsigned char { Normal , Contact , Solid , Contact_UP }

Public Member Functions

ToolChangeResult construct_tcr (WipeTowerWriter &writer, bool priming, size_t old_tool, bool is_finish, bool is_tool_change, float purge_volume, bool is_contact) const
ToolChangeResult construct_block_tcr (WipeTowerWriter &writer, bool priming, size_t filament_id, bool is_finish, float purge_volume) const
 WipeTower (const PrintConfig &config, int plate_idx, Vec3d plate_origin, size_t initial_tool, const float wipe_tower_height, const std::vector< unsigned int > &slice_used_filaments)
void set_extruder (size_t idx, const PrintConfig &config)
void set_shared_print_bed (const Polygons &bed)
void set_has_filament_switcher (bool v)
void plan_toolchange (float z_par, float layer_height_par, unsigned int old_tool, unsigned int new_tool, float wipe_volume_ec=0.f, float wipe_volume_nc=0.f, float prime_volume=0.f)
void generate (std::vector< std::vector< ToolChangeResult > > &result)
WipeTower::ToolChangeResult only_generate_out_wall (bool is_new_mode=false)
Polygon generate_support_wall (WipeTowerWriter &writer, const box_coordinates &wt_box, double feedrate, bool first_layer)
Polygon generate_support_wall_new (WipeTowerWriter &writer, const box_coordinates &wt_box, double feedrate, bool first_layer, bool rib_wall, bool extrude_perimeter, bool skip_points)
Polygon generate_rib_polygon (const box_coordinates &wt_box)
float get_depth () const
float get_brim_width () const
BoundingBoxf get_bbx () const
std::map< float, Polylines > get_outer_wall () const
float get_height () const
float get_layer_height () const
float get_rib_length () const
float get_rib_width () const
void set_last_layer_extruder_fill (bool extruder_fill)
void set_layer (float print_z, float layer_height, size_t max_tool_changes, bool is_first_layer, bool is_last_layer)
const Vec2f & position () const
float width () const
bool finished () const
std::vector< ToolChangeResult > prime (float initial_layer_print_height, const std::vector< unsigned int > &tools, bool last_wipe_inside_wipe_tower)
ToolChangeResult tool_change (size_t new_tool, bool extrude_perimeter=false, bool first_toolchange_to_nonsoluble=false)
NozzleChangeResult nozzle_change (int old_filament_id, int new_filament_id)
ToolChangeResult finish_layer (bool extruder_perimeter=true, bool extruder_fill=true)
float extrusion_flow (float layer_height=-1.f) const
float nozzle_change_extrusion_flow (float layer_height=-1.f) const
bool get_floating_area (float &start_pos_y, float &end_pos_y) const
bool need_thick_bridge_flow (float pos_y) const
float get_extrusion_flow () const
bool layer_finished () const
std::vector< float > get_used_filament () const
int get_number_of_toolchanges () const
void set_has_tpu_filament (bool has_tpu)
bool has_tpu_filament () const
void set_used_filament_ids (const std::vector< int > &used_filament_ids)
void set_filament_categories (const std::vector< int > &filament_categories)
void set_nozzle_group_result (const MultiNozzleUtils::LayeredNozzleGroupResult &multi_nozzle_group_result)
WipeTowerBlock * get_block_by_category (int filament_adhesiveness_category, bool create)
void add_depth_to_block (int filament_id, int filament_adhesiveness_category, float depth, bool is_nozzle_change=false)
int get_filament_category (int filament_id)
void reset_block_status ()
int get_wall_filament_for_all_layer ()
void generate_new (std::vector< std::vector< WipeTower::ToolChangeResult > > &result)
void plan_tower_new ()
void generate_wipe_tower_blocks (bool add_solid_flag)
void update_all_layer_depth (float wipe_tower_depth)
void set_nozzle_last_layer_id ()
void set_first_layer_flow_ratio (const float flow_ratio)
void set_accelerations (const std::vector< double > &normal, const std::vector< double > &first_layer_normal, const std::vector< double > &travel, const std::vector< double > &first_layer_travel)
void calc_block_infill_gap ()
ToolChangeResult tool_change_new (size_t new_tool, bool solid_change=false, bool solid_nozzlechange=false)
NozzleChangeResult ramming (int old_filament_id, int new_filament_id, bool solid_change=false, bool extruder_change=true)
ToolChangeResult finish_layer_new (bool extrude_perimeter=true, bool extrude_fill=true, bool extrude_fill_wall=true)
ToolChangeResult finish_block (const WipeTowerBlock &block, int filament_id, bool extrude_fill=true)
ToolChangeResult finish_block_solid (const WipeTowerBlock &block, int filament_id, bool extrude_fill=true, WipeTowerLayerType layer_type=WipeTowerLayerType::Normal)
void toolchange_wipe_new (WipeTowerWriter &writer, const box_coordinates &cleaning_box, float wipe_length, bool solid_toolchange=false)
Vec2f get_rib_offset () const
bool is_need_ramming (int filament_id_1, int filament_id_2, int layer_id) const
bool is_same_extruder (int filament_id_1, int filament_id_2, int layer_id) const
bool is_same_nozzle (int filament_id_1, int filament_id_2, int layer_id) const
int get_nozzle_id (int filament_id, int layer_id) const
int get_extruder_id (int filament_id, int layer_id) const

Static Public Member Functions

static const std::string never_skip_tag ()
static float get_limit_depth_by_height (float max_height)
static float get_auto_brim_by_height (float max_height)
static float estimate_brim_real_width (float brim_width, float nozzle_diameter, float first_layer_height, bool type2)
static float get_wrapping_detection_depth ()
static float nozzle_change_perimeter_width (float nozzle_diameter)
static TriangleMesh its_make_rib_tower (float width, float depth, float height, float rib_length, float rib_width, bool fillet_wall)
static TriangleMesh its_make_rib_brim (const Polygon &brim, float layer_height)
static Polygon rib_section (float width, float depth, float rib_length, float rib_width, bool fillet_wall)
static float estimate_tower_blocks_depth (const std::vector< PurgeEstimate > &purges, float width, float layer_height, float nozzle_diameter, float extra_spacing)
static float rib_footprint_side (float width, float depth, float rib_width, float extra_rib_length, float max_height)
static float estimate_rib_tower_bbox_side (const std::vector< PurgeEstimate > &purges, float width, float layer_height, float nozzle_diameter, float extra_spacing, float rib_width, float extra_rib_length, float max_height)
static Vec2f move_box_inside_polygon (const BoundingBox &box, const Polygons &polygons, coord_t offset=0)
static Polygon rounding_polygon (Polygon &polygon, double rounding=2., double angle_tol=30./180. *PI)

Public Attributes

std::vector< int > m_used_filament_ids
std::vector< int > m_filament_categories
const MultiNozzleUtils::LayeredNozzleGroupResult * m_multi_nozzle_group_result {nullptr}
std::vector< std::vector< BlockDepthInfo > > m_all_layers_depth
std::vector< WipeTowerBlock > m_wipe_tower_blocks
int m_last_block_id
WipeTowerBlock * m_cur_block {nullptr}

Static Public Attributes

static const std::map< float, float > min_depth_per_height

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
bool is_valid_last_layer (int tool, int layer_id, double layer_z) const
float volume_to_length (float volume, float line_width, float layer_height) const
float length_to_volume (float length, float line_width, float layer_height) const
void plan_tower ()
bool layer_is_printed (bool toolchanges_on_layer) const
void make_wipe_tower_square ()
Vec2f get_next_pos (const WipeTower::box_coordinates &cleaning_box, float wipe_length, bool solid_toolchange)
void save_on_last_wipe ()
bool is_tpu_filament (int filament_id) const
bool is_petg_filament (int filament_id) const
bool is_need_reverse_travel (int filament, bool extruder_change) const
box_coordinates align_perimeter (const box_coordinates &perimeter_box)
void set_for_wipe_tower_writer (WipeTowerWriter &writer)
int first_toolchange_to_nonsoluble_nonsupport (const std::vector< WipeTowerInfo::ToolChange > &tool_changes) const
WipeTowerInfo::ToolChange set_toolchange (int old_tool, int new_tool, float layer_height, float wipe_volume, float purge_volume, int layer_id)
void toolchange_Unload (WipeTowerWriter &writer, const box_coordinates &cleaning_box, const std::string &current_material, const int new_temperature)
void toolchange_Change (WipeTowerWriter &writer, const size_t new_tool, const std::string &new_material)
void toolchange_Load (WipeTowerWriter &writer, const box_coordinates &cleaning_box)
void toolchange_Wipe (WipeTowerWriter &writer, const box_coordinates &cleaning_box, float wipe_volume)
void get_wall_skip_points (const WipeTowerInfo &layer, int layer_id)
void get_all_wall_skip_points ()
ToolChangeResult merge_tcr (ToolChangeResult &first, ToolChangeResult &second)
float get_block_gap_width (int tool, bool is_nozzlechangle=false)

Private Attributes

const float Width_To_Nozzle_Ratio = 1.25f
const float WT_EPSILON = 1e-3f
int m_slice_used_filaments = 0
int m_wrapping_detection_layers = 0
bool m_enable_wrapping_detection = false
bool m_enable_timelapse_print = false
bool m_semm = true
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_brim_width = 0.f
float m_wipe_tower_brim_width_real = 0.f
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_first_layer_speed = 0.f
size_t m_first_layer_idx = size_t(-1)
Vec2f m_origin
std::vector< int > m_last_layer_id
std::pair< std::vector< double >, std::vector< double > > m_filaments_change_length
size_t m_cur_layer_id
NozzleChangeResult m_nozzle_change_result
bool m_has_tpu_filament {false}
bool m_is_multi_extruder {false}
bool m_use_gap_wall {false}
bool m_use_rib_wall {false}
float m_rib_length =0.f
float m_rib_width =0.f
float m_extra_rib_length =0.f
bool m_used_fillet {false}
Vec2f m_rib_offset {Vec2f(0.f, 0.f)}
bool m_tower_framework {false}
bool m_need_reverse_travel {false}
bool m_enable_tower_interface_features {false}
float m_bridging = 0.f
bool m_sparse_layers_skipped = false
bool m_sparse_layers_combined = false
bool m_adhesion = true
GCodeFlavor m_gcode_flavor
bool m_is_multiple_nozzle = false
std::vector< unsigned int > m_normal_accels
std::vector< unsigned int > m_first_layer_normal_accels
std::vector< unsigned int > m_travel_accels
std::vector< unsigned int > m_first_layer_travel_accels
unsigned int m_max_accels
bool m_accel_to_decel_enable
float m_accel_to_decel_factor
bool m_enable_arc_fitting = true
std::vector< double > m_hotend_heating_rate
std::vector< double > m_hotend_cooling_rate
Polygons m_shared_print_bed
enum Slic3r::WipeTower:: { ... }  m_bed_shape
float m_bed_width
Vec2f m_bed_bottom_left
float m_first_layer_flow_ratio
float m_perimeter_width = 0.4f * Width_To_Nozzle_Ratio
float m_nozzle_change_perimeter_width = 0.4f * Width_To_Nozzle_Ratio
float m_extrusion_flow = 0.038f
std::unordered_map< int, std::pair< float, float > > m_block_infill_gap_width
std::vector< FilamentParameters > m_filpar
unsigned int m_num_layer_changes = 0
unsigned int m_num_tool_changes = 0
bool m_print_brim = true
 unsigned int m_idx_tool_change_in_layer = 0; // Layer change counter in this layer. Counting up to m_max_color_changes.
wipe_shape m_current_shape = SHAPE_NORMAL
size_t m_current_tool = 0
float m_depth_traversed = 0.f
bool m_current_layer_finished = false
bool m_left_to_right = true
float m_extra_spacing = 1.f
float m_tpu_fixed_spacing = 2
float m_max_speed = 5400.f
std::vector< std::vector< Vec2f > > m_wall_skip_points
std::map< float, Polylines > m_outer_wall
std::vector< double > m_printable_height
bool m_flat_ironing =false
bool m_contact_ironing = false
bool m_has_filament_switcher = false
float m_contact_speed = 20 * 60.f
std::vector< int > m_physical_extruder_map
std::vector< WipeTowerInfo > m_plan
std::vector< WipeTowerInfo >::iterator m_layer_info = m_plan.end()
std::vector< float > m_used_filament_length

Friends

class WipeTowerWriter

Detailed Description


Class Documentation

◆ Slic3r::WipeTower::PurgeEstimate

struct Slic3r::WipeTower::PurgeEstimate
Class Members
int category = 0
float filament_change_length = 0.f
float filament_diameter = 1.75f
float prime_volume = 0.f

◆ Slic3r::WipeTower::NozzleChangeResult

struct Slic3r::WipeTower::NozzleChangeResult
Collaboration diagram for Slic3r::WipeTower::NozzleChangeResult:
Class Members
Vec2f end_pos
string gcode
bool is_extruder_change {true}
Vec2f origin_start_pos
Vec2f start_pos
vector< Vec2f > wipe_path

◆ Slic3r::WipeTower::FilamentParameters

struct Slic3r::WipeTower::FilamentParameters
Collaboration diagram for Slic3r::WipeTower::FilamentParameters:
Class Members
int category
float filament_area
float filament_cooling_before_tower = 0.f
float filament_petg_pre_extrusion_offset_dist = 0
float filament_tower_interface_pre_extrusion_dist = 0
float filament_tower_interface_pre_extrusion_length = 0
float filament_tower_interface_print_temp
float flat_iron_area
bool is_soluble = false
bool is_support = false
string material = "PLA"
pair< float, float > max_e_ramming_speed
float max_e_speed = std::numeric_limits<float>::max()
float max_layer_height = 0.f
float nozzle_diameter
int nozzle_temperature = 0
int nozzle_temperature_initial_layer = 0
pair< vector< float >, vector< float > > precool_t
pair< vector< float >, vector< float > > precool_t_first_layer
pair< int, int > precool_target_temp
float ramming_line_width_multiplicator = 1.f
vector< float > ramming_speed
float ramming_step_multiplicator = 1.f
pair< float, float > ramming_travel_time
float retract_length
float retract_speed
float wipe_dist

◆ Slic3r::WipeTower::WipeTowerBlock

struct Slic3r::WipeTower::WipeTowerBlock
Collaboration diagram for Slic3r::WipeTower::WipeTowerBlock:
Class Members
int block_id {0}
float cur_depth {0}
float depth {0}
int filament_adhesiveness_category {0}
vector< float > finish_depth {0}
int last_filament_change_id {-1}
int last_nozzle_change_id {-1}
vector< float > layer_depths
vector< WipeTowerLayerType > layers_type
float start_depth {0}

◆ Slic3r::WipeTower::BlockDepthInfo

struct Slic3r::WipeTower::BlockDepthInfo
Class Members
int category {-1}
float depth {0}
float nozzle_change_depth {0}

Member Enumeration Documentation

◆ anonymous enum

anonymous enum
private
Enumerator
RectangularBed 
CircularBed 
CustomBed 
557 {
561 } m_bed_shape;
@ CustomBed
Definition WipeTower.hpp:560
@ RectangularBed
Definition WipeTower.hpp:558
@ CircularBed
Definition WipeTower.hpp:559
enum Slic3r::WipeTower::@012070043006025220222204001227075365337241203153 m_bed_shape

◆ wipe_shape

Enumerator
SHAPE_NORMAL 
SHAPE_REVERSED 
480 {
481 SHAPE_NORMAL = 1,
482 SHAPE_REVERSED = -1
483 };
@ SHAPE_NORMAL
Definition WipeTower.hpp:481
@ SHAPE_REVERSED
Definition WipeTower.hpp:482

◆ WipeTowerLayerType

enum class Slic3r::WipeTower::WipeTowerLayerType : unsigned char
strong
Enumerator
Normal 
Contact 
Solid 
Contact_UP 
417: unsigned char { Normal, Contact, Solid, Contact_UP};// Contact layer should be solid and reduce feed
@ Normal
Definition PrePrintChecker.hpp:15

Constructor & Destructor Documentation

◆ WipeTower()

Slic3r::WipeTower::WipeTower ( const PrintConfig & config,
int plate_idx,
Vec3d plate_origin,
size_t initial_tool,
const float wipe_tower_height,
const std::vector< unsigned int > & slice_used_filaments )
1975 :
1976 m_semm(config.single_extruder_multi_material.value),
1977 m_wipe_tower_pos(config.wipe_tower_x.get_at(plate_idx), config.wipe_tower_y.get_at(plate_idx)),
1978 m_wipe_tower_width(float(config.prime_tower_width)),
1979 // BBS
1980 m_wipe_tower_height(wipe_tower_height),
1981 m_wipe_tower_rotation_angle(float(config.wipe_tower_rotation_angle)),
1982 m_wipe_tower_brim_width(float(config.prime_tower_brim_width)),
1983 m_y_shift(0.f),
1984 m_z_pos(0.f),
1985 //m_bridging(float(config.wipe_tower_bridging)),
1986 m_bridging(10.f),
1989 m_gcode_flavor(config.gcode_flavor),
1990 m_travel_speed(config.travel_speed.get_at(get_extruder_index(config, (unsigned int)initial_tool))),
1991 m_current_tool(initial_tool),
1992 //wipe_volumes(flush_matrix)
1993 m_enable_timelapse_print(config.timelapse_type.value == TimelapseType::tlSmooth),
1994 m_enable_wrapping_detection(config.enable_wrapping_detection),
1995 m_wrapping_detection_layers(config.wrapping_detection_layers.value && (config.wrapping_exclude_area.values.size() > 2)),
1996 m_slice_used_filaments(slice_used_filaments.size()),
1997 m_is_multi_extruder(config.nozzle_diameter.size() > 1),
1998 m_use_gap_wall(config.prime_tower_skip_points.value),
1999 // Orca: rib-wall options live under wipe_tower_* names and the wall type is an enum
2000 m_use_rib_wall(config.wipe_tower_wall_type.value == WipeTowerWallType::wtwRib),
2001 m_extra_rib_length((float)config.wipe_tower_extra_rib_length.value),
2002 m_rib_width((float)config.wipe_tower_rib_width.value),
2003 m_used_fillet(config.wipe_tower_fillet_wall.value),
2004 m_extra_spacing((float)config.prime_tower_infill_gap.value/100.f),
2005 m_tower_framework(config.prime_tower_enable_framework.value),
2006 // Orca: prime_tower_max_speed is named wipe_tower_max_purge_speed (same default/min)
2007 m_max_speed((float)config.wipe_tower_max_purge_speed.value*60.f),
2008 m_accel_to_decel_enable(config.accel_to_decel_enable.value),
2009 m_accel_to_decel_factor(config.accel_to_decel_factor.value),
2010 m_printable_height(config.extruder_printable_height.values),
2011 m_flat_ironing(config.prime_tower_flat_ironing.value),
2012 m_enable_tower_interface_features(config.enable_tower_interface_features.value),
2013 m_physical_extruder_map(config.physical_extruder_map.values),
2014 m_enable_arc_fitting(config.enable_arc_fitting.value == ArcFittingMode::Enabled)
2015 // Orca: has_filament_switcher is a device-set dynamic key, not a PrintConfig member;
2016 // it is pushed in from Print via set_has_filament_switcher() instead of read here.
2017{
2018 m_contact_speed = 20 * 60.f;
2019 m_filaments_change_length.first = config.filament_change_length.values;
2020 m_filaments_change_length.second = config.filament_change_length_nc.values;
2021 m_hotend_heating_rate = config.hotend_heating_rate.values;
2022 m_hotend_cooling_rate = config.hotend_cooling_rate.values;
2024 // Orca: default/initial-layer/travel acceleration are object-scope options here (PrintConfig
2025 // members in BBS), so Print pushes the resolved columns in via set_accelerations() instead of
2026 // the ctor reading them from config.
2027 m_max_accels = config.machine_max_acceleration_extruding.values.front();
2028
2029 // Read absolute value of first layer speed, if given as percentage,
2030 // it is taken over following default. Speeds from config are not
2031 // easily accessible here.
2032 const float default_speed = 60.f;
2033 m_first_layer_speed = config.initial_layer_speed.get_at(get_extruder_index(config, (unsigned int) initial_tool));
2034 if (m_first_layer_speed == 0.f) // just to make sure autospeed doesn't break it.
2035 m_first_layer_speed = default_speed / 2.f;
2036
2037 // If this is a single extruder MM printer, we will use all the SE-specific config values.
2038 // Otherwise, the defaults will be used to turn off the SE stuff.
2039 // BBS: remove useless config
2040#if 0
2041 if (m_semm) {
2042 m_cooling_tube_retraction = float(config.cooling_tube_retraction);
2043 m_cooling_tube_length = float(config.cooling_tube_length);
2044 m_parking_pos_retraction = float(config.parking_pos_retraction);
2045 m_extra_loading_move = float(config.extra_loading_move);
2046 m_set_extruder_trimpot = config.high_current_on_filament_swap;
2047 }
2048#endif
2049 // Calculate where the priming lines should be - very naive test not detecting parallelograms etc.
2050 const std::vector<Vec2d>& bed_points = config.printable_area.values;
2051 BoundingBoxf bb(bed_points);
2052 m_bed_width = float(bb.size().x());
2053 m_bed_shape = (bed_points.size() == 4 ? RectangularBed : CircularBed);
2054
2055 if (m_bed_shape == CircularBed) {
2056 // this may still be a custom bed, check that the points are roughly on a circle
2057 double r2 = std::pow(m_bed_width/2., 2.);
2058 double lim2 = std::pow(m_bed_width/10., 2.);
2059 Vec2d center = bb.center();
2060 for (const Vec2d& pt : bed_points)
2061 if (std::abs(std::pow(pt.x()-center.x(), 2.) + std::pow(pt.y()-center.y(), 2.) - r2) > lim2) {
2063 break;
2064 }
2065 }
2066
2068 ? Vec2f(bed_points.front().x(), bed_points.front().y())
2069 : Vec2f::Zero();
2070 m_last_layer_id.resize(config.nozzle_diameter.size(), -1);
2071 m_origin = {plate_origin[0], plate_origin[1]};
2072 m_is_multiple_nozzle = std::any_of(config.extruder_max_nozzle_count.values.begin(), config.extruder_max_nozzle_count.values.end(), [](auto &elem) { return elem > 1; });
2073}
unsigned int m_max_accels
Definition WipeTower.hpp:548
int m_slice_used_filaments
Definition WipeTower.hpp:491
Vec2f m_wipe_tower_pos
Definition WipeTower.hpp:496
float m_accel_to_decel_factor
Definition WipeTower.hpp:550
float m_wipe_tower_brim_width
Definition WipeTower.hpp:501
float m_y_shift
Definition WipeTower.hpp:505
Vec2f m_origin
Definition WipeTower.hpp:513
bool m_accel_to_decel_enable
Definition WipeTower.hpp:549
std::vector< int > m_physical_extruder_map
Definition WipeTower.hpp:600
bool m_semm
Definition WipeTower.hpp:495
bool m_sparse_layers_skipped
Definition WipeTower.hpp:537
std::vector< double > m_hotend_cooling_rate
Definition WipeTower.hpp:553
GCodeFlavor m_gcode_flavor
Definition WipeTower.hpp:542
bool m_flat_ironing
Definition WipeTower.hpp:596
bool m_sparse_layers_combined
Definition WipeTower.hpp:538
int m_wrapping_detection_layers
Definition WipeTower.hpp:492
float m_rib_width
Definition WipeTower.hpp:523
float m_wipe_tower_height
Definition WipeTower.hpp:500
bool m_use_rib_wall
Definition WipeTower.hpp:521
bool m_tower_framework
Definition WipeTower.hpp:527
float m_max_speed
Definition WipeTower.hpp:590
bool m_enable_wrapping_detection
Definition WipeTower.hpp:493
std::vector< double > m_printable_height
Definition WipeTower.hpp:593
bool m_is_multi_extruder
Definition WipeTower.hpp:519
bool m_enable_tower_interface_features
Definition WipeTower.hpp:529
float m_wipe_tower_rotation_angle
Definition WipeTower.hpp:503
float m_z_pos
Definition WipeTower.hpp:506
float m_extra_rib_length
Definition WipeTower.hpp:524
Vec2f m_bed_bottom_left
Definition WipeTower.hpp:563
bool m_is_multiple_nozzle
Definition WipeTower.hpp:543
std::vector< int > m_last_layer_id
Definition WipeTower.hpp:514
bool m_enable_arc_fitting
Definition WipeTower.hpp:551
std::vector< double > m_hotend_heating_rate
Definition WipeTower.hpp:552
size_t m_current_tool
Definition WipeTower.hpp:581
bool m_used_fillet
Definition WipeTower.hpp:525
bool m_use_gap_wall
Definition WipeTower.hpp:520
bool m_enable_timelapse_print
Definition WipeTower.hpp:494
float m_bed_width
Definition WipeTower.hpp:562
float m_travel_speed
Definition WipeTower.hpp:510
std::pair< std::vector< double >, std::vector< double > > m_filaments_change_length
Definition WipeTower.hpp:515
float m_extra_spacing
Definition WipeTower.hpp:588
float m_contact_speed
Definition WipeTower.hpp:599
float m_bridging
Definition WipeTower.hpp:536
float m_first_layer_speed
Definition WipeTower.hpp:511
float m_wipe_tower_width
Definition WipeTower.hpp:497
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
@ tlSmooth
Definition PrintConfig.hpp:470
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
@ wtwRib
Definition PrintConfig.hpp:608
bool wipe_tower_sparse_layers_combined(const PrintConfig &config)
Definition WipeTower.cpp:77

References Slic3r::accel_to_decel_enable(), Slic3r::BoundingBoxBase< PointType, APointsType >::center(), Slic3r::center(), CircularBed, CustomBed, Slic3r::enable_tower_interface_features(), Slic3r::gcode_flavor(), Slic3r::get_extruder_index(), m_accel_to_decel_enable, m_accel_to_decel_factor, m_bed_bottom_left, m_bed_shape, m_bed_width, m_bridging, m_contact_speed, m_current_tool, m_enable_arc_fitting, m_enable_timelapse_print, m_enable_tower_interface_features, m_enable_wrapping_detection, m_extra_rib_length, m_extra_spacing, m_filaments_change_length, m_first_layer_speed, m_flat_ironing, m_gcode_flavor, m_hotend_cooling_rate, m_hotend_heating_rate, m_is_multi_extruder, m_is_multiple_nozzle, m_last_layer_id, m_max_accels, m_max_speed, m_origin, m_physical_extruder_map, m_printable_height, m_rib_width, m_semm, m_slice_used_filaments, m_sparse_layers_combined, m_sparse_layers_skipped, m_tower_framework, m_travel_speed, m_use_gap_wall, m_use_rib_wall, m_used_fillet, m_wipe_tower_brim_width, m_wipe_tower_height, m_wipe_tower_pos, m_wipe_tower_rotation_angle, m_wipe_tower_width, m_wrapping_detection_layers, m_y_shift, m_z_pos, Slic3r::nozzle_diameter(), Slic3r::physical_extruder_map(), Slic3r::prime_tower_brim_width(), Slic3r::prime_tower_enable_framework(), Slic3r::prime_tower_skip_points(), RectangularBed, Slic3r::single_extruder_multi_material(), Slic3r::BoundingBoxBase< PointType, APointsType >::size(), Slic3r::tlSmooth, Slic3r::travel_speed(), 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(), Slic3r::wrapping_detection_layers(), and Slic3r::wtwRib.

Here is the call graph for this function:

Member Function Documentation

◆ add_depth_to_block()

void Slic3r::WipeTower::add_depth_to_block ( int filament_id,
int filament_adhesiveness_category,
float depth,
bool is_nozzle_change = false )
4455{
4456 std::vector<WipeTower::BlockDepthInfo> &layer_depth = m_all_layers_depth[m_cur_layer_id];
4457 auto iter = std::find_if(layer_depth.begin(), layer_depth.end(), [&filament_adhesiveness_category](const WipeTower::BlockDepthInfo &item) {
4458 return item.category == filament_adhesiveness_category;
4459 });
4460
4461 if (iter != layer_depth.end()) {
4462 iter->depth += depth;
4463 if (is_nozzle_change)
4464 iter->nozzle_change_depth += depth;
4465 }
4466 else {
4467 WipeTower::BlockDepthInfo new_block;
4468 new_block.category = filament_adhesiveness_category;
4469 new_block.depth = depth;
4470 if (is_nozzle_change)
4471 new_block.nozzle_change_depth += depth;
4472 layer_depth.emplace_back(std::move(new_block));
4473 }
4474}
size_t m_cur_layer_id
Definition WipeTower.hpp:516
std::vector< std::vector< BlockDepthInfo > > m_all_layers_depth
Definition WipeTower.hpp:441
zaa_minimize_perimeter_height filament_adhesiveness_category((ConfigOptionFloats, filament_density))((ConfigOptionStrings

References Slic3r::WipeTower::BlockDepthInfo::category, Slic3r::WipeTower::BlockDepthInfo::depth, Slic3r::filament_adhesiveness_category(), m_all_layers_depth, m_cur_layer_id, and Slic3r::WipeTower::BlockDepthInfo::nozzle_change_depth.

Referenced by generate_wipe_tower_blocks().

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

◆ align_perimeter()

WipeTower::box_coordinates Slic3r::WipeTower::align_perimeter ( const box_coordinates & perimeter_box)
private
2901{
2902 box_coordinates aligned_box = perimeter_box;
2903
2904 float spacing = m_extra_spacing * m_perimeter_width;
2905 float up = perimeter_box.lu(1) - m_perimeter_width - EPSILON;
2906 up = align_ceil(up, spacing);
2908 up = std::min(up, m_wipe_tower_depth);
2909
2910 float down = perimeter_box.ld(1) - m_perimeter_width + EPSILON;
2911 down = align_floor(down, spacing);
2913 down = std::max(down, -m_y_shift);
2914
2915 aligned_box.lu(1) = aligned_box.ru(1) = up;
2916 aligned_box.ld(1) = aligned_box.rd(1) = down;
2917
2918 return aligned_box;
2919}
#define EPSILON
Definition ColorUtils.cpp:64
float m_perimeter_width
Definition WipeTower.hpp:566
float m_wipe_tower_depth
Definition WipeTower.hpp:498
float align_floor(float value, float base)
Definition WipeTower.cpp:129
float align_ceil(float value, float base)
Definition WipeTower.cpp:124
@ up
Definition MarchingSquares.hpp:192
@ down
Definition MarchingSquares.hpp:189
Definition WipeTower.hpp:184

References Slic3r::align_ceil(), Slic3r::align_floor(), EPSILON, Slic3r::WipeTower::box_coordinates::ld, Slic3r::WipeTower::box_coordinates::lu, m_extra_spacing, m_perimeter_width, m_wipe_tower_depth, m_y_shift, Slic3r::WipeTower::box_coordinates::rd, and Slic3r::WipeTower::box_coordinates::ru.

Referenced by finish_block(), finish_layer_new(), only_generate_out_wall(), and tool_change().

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

◆ calc_block_infill_gap()

void Slic3r::WipeTower::calc_block_infill_gap ( )
4686{
4687 //1.calc block infill gap width
4688 struct BlockInfo
4689 {
4690 bool has_ramming = false;
4691 bool has_reverse_travel = false;
4692 float depth = 0.f;
4693 };
4694 std::unordered_map<int, BlockInfo> block_info;
4695 std::unordered_map<int, BlockInfo> high_block_info;
4696 for (int i= (int)m_plan.size()-1;i>=0;i--)
4697 {
4698 for (auto &toolchange : m_plan[i].tool_changes) {
4699 int new_tool =toolchange.new_tool;
4700 int old_tool =toolchange.old_tool;
4701 if (is_need_ramming(old_tool,new_tool, i)) {
4702 bool extruder_change = !is_same_extruder(new_tool, old_tool, i);
4703 block_info[m_filpar[old_tool].category].has_ramming=true;
4704 if (is_need_reverse_travel(old_tool, extruder_change)) block_info[m_filpar[old_tool].category].has_reverse_travel = true;
4705 block_info[m_filpar[old_tool].category].depth += toolchange.nozzle_change_depth;
4706 }
4707 if (!block_info.count(m_filpar[new_tool].category)) block_info.insert({m_filpar[new_tool].category,BlockInfo{}});
4708 block_info[m_filpar[new_tool].category].depth += toolchange.required_depth - toolchange.nozzle_change_depth;
4709 }
4710 for (auto &block : block_info) {
4711 if (high_block_info.count(block.first) && high_block_info[block.first].depth > block.second.depth)
4712 block.second.depth = high_block_info[block.first].depth;
4713 }
4714 high_block_info = block_info;
4715
4716 for (auto &block : block_info) { block.second.depth = 0.f;}
4717 if (i == 0) block_info = high_block_info;
4718 }
4719 float max_depth = std::accumulate(block_info.begin(), block_info.end(), 0.f, [](float value, const std::pair<int,BlockInfo> &block) { return value + block.second.depth; });
4720 float height_to_depth = get_limit_depth_by_height(m_wipe_tower_height);
4721 float height_to_spacing = max_depth > height_to_depth ? 1.f : height_to_depth / max_depth;
4722
4723 float spacing_ratio = m_extra_spacing - 1.f;
4724 float extra_width = spacing_ratio * m_perimeter_width;
4725 float line_gap_tol = 2.f * m_nozzle_change_perimeter_width; //If the block's line_gap is greater than it, the block should be aligned.
4726 for (auto &info : block_info) {
4727 //case1: no ramming, it can always align
4728 if (!info.second.has_ramming) {
4729 m_block_infill_gap_width[info.first].first = m_block_infill_gap_width[info.first].second = extra_width + m_perimeter_width;
4730 }
4731 // case2: has ramming, but no reverse travel
4732 //
4733 else if (!info.second.has_reverse_travel) {
4734 float line_gap = m_nozzle_change_perimeter_width + extra_width;
4735 if (!m_use_rib_wall) line_gap *= height_to_spacing;
4736 if (line_gap < line_gap_tol) {
4737 m_block_infill_gap_width[info.first].first = m_perimeter_width + extra_width;
4738 m_block_infill_gap_width[info.first].second = m_nozzle_change_perimeter_width + extra_width;
4739 } else {
4740 m_block_infill_gap_width[info.first].first = m_block_infill_gap_width[info.first].second = m_nozzle_change_perimeter_width + extra_width;
4741 }
4742 }
4743 // case 3: has ramming and reverse travel
4744 else {
4745 float extra_tpu_fix_spacing = m_tpu_fixed_spacing - 1.f;
4746 float line_gap = m_nozzle_change_perimeter_width + std::max(extra_tpu_fix_spacing * m_perimeter_width, extra_width);
4747 if (!m_use_rib_wall) line_gap = height_to_spacing * line_gap;
4748 if (line_gap < line_gap_tol) {
4749 m_block_infill_gap_width[info.first].first = m_perimeter_width + extra_width;
4750 m_block_infill_gap_width[info.first].second = m_nozzle_change_perimeter_width + std::max(extra_tpu_fix_spacing * m_perimeter_width, extra_width);
4751 } else {
4753 std::max(extra_tpu_fix_spacing * m_perimeter_width, extra_width);
4754 }
4755 }
4756 }
4757
4758 //2. recalculate toolchange depth
4759 for (int idx = 0; idx < m_plan.size(); idx++) {
4760 for (auto &toolchange : m_plan[idx].tool_changes) {
4761 toolchange = set_toolchange(toolchange.old_tool, toolchange.new_tool, m_plan[idx].height, toolchange.wipe_volume, toolchange.purge_volume,idx);
4762 }
4763 }
4764 m_extra_spacing = 1.f;
4765}
bool is_same_extruder(int filament_id_1, int filament_id_2, int layer_id) const
Definition WipeTower.cpp:5546
std::unordered_map< int, std::pair< float, float > > m_block_infill_gap_width
Definition WipeTower.hpp:569
static float get_limit_depth_by_height(float max_height)
Definition WipeTower.cpp:1697
float m_nozzle_change_perimeter_width
Definition WipeTower.hpp:567
std::vector< WipeTowerInfo > m_plan
Definition WipeTower.hpp:663
float m_tpu_fixed_spacing
Definition WipeTower.hpp:589
bool is_need_ramming(int filament_id_1, int filament_id_2, int layer_id) const
Definition WipeTower.cpp:5542
bool is_need_reverse_travel(int filament, bool extruder_change) const
Definition WipeTower.cpp:3334
std::vector< FilamentParameters > m_filpar
Definition WipeTower.hpp:571
WipeTowerInfo::ToolChange set_toolchange(int old_tool, int new_tool, float layer_height, float wipe_volume, float purge_volume, int layer_id)
Definition WipeTower.cpp:3102

References get_limit_depth_by_height(), is_need_ramming(), is_need_reverse_travel(), is_same_extruder(), m_block_infill_gap_width, m_extra_spacing, m_filpar, m_nozzle_change_perimeter_width, m_perimeter_width, m_plan, m_tpu_fixed_spacing, m_use_rib_wall, m_wipe_tower_height, and set_toolchange().

Referenced by plan_tower_new().

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

◆ construct_block_tcr()

WipeTower::ToolChangeResult Slic3r::WipeTower::construct_block_tcr ( WipeTowerWriter & writer,
bool priming,
size_t filament_id,
bool is_finish,
float purge_volume ) const
1668{
1669 ToolChangeResult result;
1670 result.priming = priming;
1671 result.initial_tool = int(filament_id);
1672 result.new_tool = int(filament_id);
1673 result.print_z = m_z_pos;
1674 result.layer_height = m_layer_height;
1675 result.elapsed_time = writer.elapsed_time();
1676 result.start_pos = writer.start_pos_rotated();
1677 result.end_pos = priming ? writer.pos() : writer.pos_rotated();
1678 result.gcode = std::move(writer.gcode());
1679 result.extrusions = std::move(writer.extrusions());
1680 result.wipe_path = std::move(writer.wipe_path());
1681 result.is_finish_first = is_finish;
1682 result.is_tool_change = false;
1683 result.tool_change_start_pos = Vec2f(0, 0);
1684 // BBS
1685 result.purge_volume = purge_volume;
1686 return result;
1687}
float m_layer_height
Definition WipeTower.hpp:507
Definition WipeTower.hpp:114
bool priming
Definition WipeTower.hpp:133

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

Referenced by finish_block(), and finish_block_solid().

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

◆ construct_tcr()

WipeTower::ToolChangeResult Slic3r::WipeTower::construct_tcr ( WipeTowerWriter & writer,
bool priming,
size_t old_tool,
bool is_finish,
bool is_tool_change,
float purge_volume,
bool is_contact ) const
1644{
1645 ToolChangeResult result;
1646 result.priming = priming;
1647 result.initial_tool = int(old_tool);
1648 result.new_tool = int(m_current_tool);
1649 result.print_z = m_z_pos;
1650 result.layer_height = m_layer_height;
1651 result.elapsed_time = writer.elapsed_time();
1652 result.start_pos = writer.start_pos_rotated();
1653 result.end_pos = priming ? writer.pos() : writer.pos_rotated();
1654 result.gcode = std::move(writer.gcode());
1655 result.extrusions = std::move(writer.extrusions());
1656 result.wipe_path = std::move(writer.wipe_path());
1657 result.is_finish_first = is_finish;
1658 result.nozzle_change_result = m_nozzle_change_result;
1659 result.is_tool_change = is_tool_change;
1660 result.tool_change_start_pos = is_tool_change ? result.start_pos : Vec2f(0, 0);
1661 result.is_contact = is_contact;
1662 // BBS
1663 result.purge_volume = purge_volume;
1664 return result;
1665}
NozzleChangeResult m_nozzle_change_result
Definition WipeTower.hpp:517

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

Referenced by finish_layer_new(), only_generate_out_wall(), tool_change(), and tool_change_new().

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

◆ estimate_brim_real_width()

float Slic3r::WipeTower::estimate_brim_real_width ( float brim_width,
float nozzle_diameter,
float first_layer_height,
bool type2 )
static
1739{
1740 if (brim_width <= 0.f)
1741 return brim_width;
1742 const float spacing = nozzle_diameter * 1.25f - first_layer_height * float(1. - M_PI_4); // Width_To_Nozzle_Ratio
1743 if (spacing <= EPSILON)
1744 return brim_width;
1745 const int loops_num = int((brim_width + spacing / 2.f) / spacing);
1746 return loops_num * spacing + (type2 ? 0.f : spacing / 2.f);
1747}
zaa_minimize_perimeter_height nozzle_diameter((ConfigOptionBool, reduce_infill_retraction))((ConfigOptionBool

References EPSILON, and Slic3r::nozzle_diameter().

Referenced by Slic3r::estimate_wipe_tower_footprint().

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

◆ estimate_rib_tower_bbox_side()

float Slic3r::WipeTower::estimate_rib_tower_bbox_side ( const std::vector< PurgeEstimate > & purges,
float width,
float layer_height,
float nozzle_diameter,
float extra_spacing,
float rib_width,
float extra_rib_length,
float max_height )
static
1817{
1818 if (purges.empty() || width < EPSILON || layer_height < EPSILON || nozzle_diameter < EPSILON)
1819 return 0.f;
1820 const float pw = nozzle_diameter * 1.25f; // Width_To_Nozzle_Ratio
1821 const float square = align_ceil(std::sqrt(estimate_tower_blocks_depth(purges, width, layer_height, nozzle_diameter, extra_spacing) * width), pw);
1822 const float depth = estimate_tower_blocks_depth(purges, square, layer_height, nozzle_diameter, extra_spacing);
1823 return rib_footprint_side(square, depth, rib_width, extra_rib_length, max_height);
1824}
static float rib_footprint_side(float width, float depth, float rib_width, float extra_rib_length, float max_height)
Definition WipeTower.cpp:1799
float width() const
Definition WipeTower.hpp:315
static float estimate_tower_blocks_depth(const std::vector< PurgeEstimate > &purges, float width, float layer_height, float nozzle_diameter, float extra_spacing)
Definition WipeTower.cpp:1760
layer_height((ConfigOptionInt, faded_layers))((ConfigOptionFloat

References Slic3r::align_ceil(), EPSILON, estimate_tower_blocks_depth(), Slic3r::layer_height(), Slic3r::nozzle_diameter(), rib_footprint_side(), and width().

Referenced by Slic3r::estimate_wipe_tower_footprint().

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

◆ estimate_tower_blocks_depth()

float Slic3r::WipeTower::estimate_tower_blocks_depth ( const std::vector< PurgeEstimate > & purges,
float width,
float layer_height,
float nozzle_diameter,
float extra_spacing )
static
1761{
1762 if (purges.empty() || layer_height < EPSILON || nozzle_diameter < EPSILON)
1763 return 0.f;
1764 const float pw = nozzle_diameter * 1.25f; // Width_To_Nozzle_Ratio
1766 const float line_width = width - 2.f * pw;
1767 if (line_width <= EPSILON)
1768 return 0.f;
1769 // Line cross-section as volume_to_length() sees it; the infill gap stretches the perimeter
1770 // width by the configured ratio and nozzle-change lines keep their own width
1771 // (calc_block_infill_gap).
1772 auto line_area = [layer_height](float w) { return layer_height * (w - layer_height * float(1. - M_PI_4)); };
1773 const float extra_width = (extra_spacing - 1.f) * pw;
1774 const float gap = pw + extra_width;
1775 const float nc_gap = ncpw + extra_width;
1776 // A layer purges into at most (filaments - 1) targets, so a category holding every filament
1777 // never sees its smallest purge (the layer's first filament) in its worst layer.
1778 struct Block { float depth = 0.f; float min_purge = 0.f; size_t filaments = 0; };
1779 std::map<int, Block> blocks;
1780 for (const PurgeEstimate &purge : purges) {
1781 Block &block = blocks[purge.category];
1782 const float purge_depth = std::ceil(purge.prime_volume / line_area(pw) / line_width) * gap;
1783 block.min_purge = block.filaments == 0 ? purge_depth : std::min(block.min_purge, purge_depth);
1784 block.depth += purge_depth;
1785 ++block.filaments;
1786 if (purge.filament_change_length > EPSILON) {
1787 // The leaving filament is rammed over the nozzle-change flow, again in whole lines.
1788 const float filament_area = float(M_PI) * purge.filament_diameter * purge.filament_diameter / 4.f;
1789 const float nc_length = purge.filament_change_length * filament_area / line_area(ncpw);
1790 block.depth += std::ceil(nc_length / (width - ncpw - pw)) * nc_gap;
1791 }
1792 }
1793 float depth = pw; // plan_tower_new starts the first block one perimeter width in
1794 for (const auto &[category, block] : blocks)
1795 depth += block.filaments == purges.size() ? block.depth - block.min_purge : block.depth;
1796 return depth;
1797}
#define M_PI
Definition ExtrusionSimulator.cpp:31
static float nozzle_change_perimeter_width(float nozzle_diameter)
Definition WipeTower.cpp:1754
float filament_area() const
Definition WipeTower.hpp:487
Definition WipeTower.hpp:66

References EPSILON, filament_area(), Slic3r::layer_height(), M_PI, nozzle_change_perimeter_width(), Slic3r::nozzle_diameter(), and width().

Referenced by estimate_rib_tower_bbox_side(), and Slic3r::estimate_wipe_tower_footprint().

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

◆ extrusion_flow()

float Slic3r::WipeTower::extrusion_flow ( float layer_height = -1.f) const
inline
342 {
343 if (layer_height < 0) return m_extrusion_flow;
344 return layer_height * (m_perimeter_width - layer_height * (1.f - float(M_PI) / 4.f)) / filament_area();
345 }
float m_extrusion_flow
Definition WipeTower.hpp:568

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

Referenced by finish_block_solid(), Slic3r::WipeTowerWriter::line(), Slic3r::WipeTowerWriter::rectangle_fill_box(), set_layer(), tool_change(), toolchange_Wipe(), and toolchange_wipe_new().

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

◆ filament_area()

float Slic3r::WipeTower::filament_area ( ) const
inlineprivate
487 {
488 return m_filpar[0].filament_area; // all extruders are assumed to have the same filament diameter at this point
489 }

References m_filpar.

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

Here is the caller graph for this function:

◆ finish_block()

WipeTower::ToolChangeResult Slic3r::WipeTower::finish_block ( const WipeTowerBlock & block,
int filament_id,
bool extrude_fill = true )
4004{
4006 writer.set_extrusion_flow(m_extrusion_flow)
4007 .set_z(m_z_pos)
4008 .set_initial_tool(filament_id)
4009 .set_y_shift(m_y_shift - (m_current_shape == SHAPE_REVERSED ? m_layer_info->toolchanges_depth() : 0.f));
4010
4012
4014
4015 // Slow down on the 1st layer.
4016 bool first_layer = is_first_layer();
4017 // BBS: speed up perimeter speed to 90mm/s for non-first layer
4018 float feedrate = first_layer ? std::min(m_first_layer_speed * 60.f, m_max_speed) : std::min(60.0f * m_filpar[filament_id].max_e_speed / m_extrusion_flow, m_max_speed);
4019
4020 box_coordinates fill_box(Vec2f(0, 0), 0, 0);
4021 fill_box = box_coordinates(Vec2f(m_perimeter_width, block.cur_depth), m_wipe_tower_width - 2 * m_perimeter_width, block.start_depth + block.layer_depths[m_cur_layer_id] - block.cur_depth - m_perimeter_width);
4022
4023 writer.set_initial_position((m_left_to_right ? fill_box.ru : fill_box.lu), m_wipe_tower_width, m_wipe_tower_depth, m_internal_rotation);
4024
4025 bool toolchanges_on_layer = m_layer_info->toolchanges_depth() > WT_EPSILON;
4026
4027 std::vector<Vec2f> finish_rect_wipe_path;
4028 // inner perimeter of the sparse section, if there is space for it:
4029 if (fill_box.ru.y() - fill_box.rd.y() > WT_EPSILON) {
4030 writer.rectangle_fill_box(this, fill_box, finish_rect_wipe_path, feedrate);
4031 }
4032
4033 // Extrude infill to support the material to be printed above.
4034 const float dy = (fill_box.lu.y() - fill_box.ld.y() - m_perimeter_width);
4035 float left = fill_box.lu.x() + 2 * m_perimeter_width;
4036 float right = fill_box.ru.x() - 2 * m_perimeter_width;
4037 if (extrude_fill && dy > m_perimeter_width) {
4038 writer.travel(fill_box.ld + Vec2f(m_perimeter_width * 2, 0.f))
4039 .append(";--------------------\n"
4040 "; CP EMPTY GRID START\n")
4041 .comment_with_value(" layer #", m_num_layer_changes + 1);
4042
4043 // Is there a soluble filament wiped/rammed at the next layer?
4044 // If so, the infill should not be sparse.
4045 bool solid_infill = m_layer_info + 1 == m_plan.end() ?
4046 false :
4047 std::any_of((m_layer_info + 1)->tool_changes.begin(), (m_layer_info + 1)->tool_changes.end(),
4048 [this](const WipeTowerInfo::ToolChange &tch) { return m_filpar[tch.new_tool].is_soluble || m_filpar[tch.old_tool].is_soluble; });
4049 solid_infill |= first_layer && m_adhesion;
4050
4051 if (solid_infill) {
4052 float sparse_factor = 1.5f; // 1=solid, 2=every other line, etc.
4053 if (first_layer) { // the infill should touch perimeters
4056 sparse_factor = 1.f;
4057 }
4058 float y = fill_box.ld.y() + m_perimeter_width;
4059 int n = dy / (m_perimeter_width * sparse_factor);
4060 float spacing = (dy - m_perimeter_width) / (n - 1);
4061 int i = 0;
4062 for (i = 0; i < n; ++i) {
4063 writer.extrude(writer.x(), y, feedrate).extrude(i % 2 ? left : right, y);
4064 y = y + spacing;
4065 }
4066 writer.extrude(writer.x(), fill_box.lu.y());
4067 } else {
4068 // Extrude an inverse U at the left of the region and the sparse infill.
4069 writer.extrude(fill_box.lu + Vec2f(m_perimeter_width * 2, 0.f), feedrate);
4070
4071 const int n = 1 + int((right - left) / m_bridging);
4072 const float dx = (right - left) / n;
4073 for (int i = 1; i <= n; ++i) {
4074 float x = left + dx * i;
4075 writer.travel(x, writer.y());
4076 writer.extrude(x, i % 2 ? fill_box.rd.y() : fill_box.ru.y());
4077 }
4078 finish_rect_wipe_path.clear();
4079 // BBS: add wipe_path for this case: only with finish rectangle
4080 finish_rect_wipe_path.emplace_back(writer.pos());
4081 finish_rect_wipe_path.emplace_back(Vec2f(left + dx * n, n % 2 ? fill_box.ru.y() : fill_box.rd.y()));
4082 }
4083
4084 writer.append("; CP EMPTY GRID END\n"
4085 ";------------------\n\n\n\n\n\n\n");
4086 }
4087
4088 // outer perimeter (always):
4089 // BBS
4091 wt_box = align_perimeter(wt_box);
4092
4093 // Now prepare future wipe. box contains rectangle that was extruded last (ccw).
4094 Vec2f target = (writer.pos() == wt_box.ld ? wt_box.rd : (writer.pos() == wt_box.rd ? wt_box.ru : (writer.pos() == wt_box.ru ? wt_box.lu : wt_box.ld)));
4095
4096 // BBS: add wipe_path for this case: only with finish rectangle
4097 if (finish_rect_wipe_path.size() == 2 && finish_rect_wipe_path[0] == writer.pos()) target = finish_rect_wipe_path[1];
4098
4099 writer.add_wipe_point(writer.pos()).add_wipe_point(target);
4100
4102
4103 // Ask our writer about how much material was consumed.
4104 // Skip this in case the layer is sparse and config option to not print sparse layers is enabled.
4105 if (layer_is_printed(toolchanges_on_layer))
4106 if (filament_id < m_used_filament_length.size())
4107 m_used_filament_length[filament_id] += writer.get_and_reset_used_filament_length();
4108
4109 return construct_block_tcr(writer, false, filament_id, true, 0.f);
4110}
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
bool m_left_to_right
Definition WipeTower.hpp:587
const float WT_EPSILON
Definition WipeTower.hpp:486
std::vector< float > m_used_filament_length
Definition WipeTower.hpp:667
std::vector< WipeTowerInfo >::iterator m_layer_info
Definition WipeTower.hpp:664
float m_internal_rotation
Definition WipeTower.hpp:504
void set_for_wipe_tower_writer(WipeTowerWriter &writer)
Definition WipeTower.cpp:2921
friend class WipeTowerWriter
Definition WipeTower.hpp:45
ToolChangeResult construct_block_tcr(WipeTowerWriter &writer, bool priming, size_t filament_id, bool is_finish, float purge_volume) const
Definition WipeTower.cpp:1667
unsigned int m_num_layer_changes
Definition WipeTower.hpp:575
bool is_first_layer() const
Definition WipeTower.hpp:594
bool m_adhesion
Definition WipeTower.hpp:541
box_coordinates align_perimeter(const box_coordinates &perimeter_box)
Definition WipeTower.cpp:2900
wipe_shape m_current_shape
Definition WipeTower.hpp:580
bool layer_is_printed(bool toolchanges_on_layer) const
Definition WipeTower.cpp:4769
@ right
Definition MarchingSquares.hpp:190
@ left
Definition MarchingSquares.hpp:188

References Slic3r::WipeTowerWriter::add_wipe_point(), align_perimeter(), Slic3r::WipeTowerWriter::append(), Slic3r::WipeTowerWriter::comment_with_value(), construct_block_tcr(), Slic3r::WipeTower::WipeTowerBlock::cur_depth, Slic3r::WipeTowerWriter::extrude(), Slic3r::WipeTowerWriter::get_and_reset_used_filament_length(), is_first_layer(), Slic3r::WipeTower::WipeTowerBlock::layer_depths, layer_is_printed(), Slic3r::WipeTower::box_coordinates::ld, Slic3r::WipeTower::box_coordinates::lu, m_adhesion, m_bridging, m_cur_layer_id, m_current_shape, m_enable_arc_fitting, m_extrusion_flow, m_filpar, m_first_layer_speed, m_gcode_flavor, m_internal_rotation, m_layer_height, m_layer_info, m_left_to_right, m_max_speed, m_num_layer_changes, m_perimeter_width, m_plan, m_used_filament_length, m_wipe_tower_depth, m_wipe_tower_width, m_y_shift, m_z_pos, Slic3r::WipeTowerWriter::pos(), Slic3r::WipeTower::box_coordinates::rd, Slic3r::WipeTowerWriter::rectangle_fill_box(), Slic3r::GCodeProcessor::reserved_tag(), Slic3r::WipeTower::box_coordinates::ru, Slic3r::WipeTowerWriter::set_extrusion_flow(), set_for_wipe_tower_writer(), Slic3r::WipeTowerWriter::set_initial_position(), Slic3r::WipeTowerWriter::set_initial_tool(), Slic3r::WipeTowerWriter::set_y_shift(), Slic3r::WipeTowerWriter::set_z(), SHAPE_REVERSED, Slic3r::WipeTower::WipeTowerBlock::start_depth, Slic3r::WipeTowerWriter::travel(), Slic3r::GCodeProcessor::Wipe_Tower_End, Slic3r::GCodeProcessor::Wipe_Tower_Start, WipeTowerWriter, WT_EPSILON, Slic3r::WipeTowerWriter::x(), and Slic3r::WipeTowerWriter::y().

Referenced by generate_new().

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

◆ finish_block_solid()

WipeTower::ToolChangeResult Slic3r::WipeTower::finish_block_solid ( const WipeTowerBlock & block,
int filament_id,
bool extrude_fill = true,
WipeTowerLayerType layer_type = WipeTowerLayerType::Normal )
4113{
4115 float e_flow = m_extrusion_flow;
4116 if (m_cur_layer_id > 1 && block.layers_type[m_cur_layer_id - 1]==WipeTowerLayerType::Normal && m_extrusion_flow < extrusion_flow(0.2)) {
4117 layer_height = 0.2;
4118 e_flow = extrusion_flow(0.2);
4119 }
4120
4122 writer.set_extrusion_flow(e_flow)
4123 .set_z(m_z_pos)
4124 .set_initial_tool(filament_id)
4125 .set_y_shift(m_y_shift - (m_current_shape == SHAPE_REVERSED ? m_layer_info->toolchanges_depth() : 0.f));
4126
4128
4130
4131 // Slow down on the 1st layer.
4132 bool first_layer = is_first_layer();
4133 // BBS: speed up perimeter speed to 90mm/s for non-first layer
4134 float feedrate = first_layer ? std::min(m_first_layer_speed * 60.f, m_max_speed) : std::min(60.0f * m_filpar[filament_id].max_e_speed / m_extrusion_flow, m_max_speed);
4135 feedrate = (layer_type == WipeTowerLayerType::Contact || layer_type == WipeTowerLayerType::Contact_UP) ? 20.f * 60.f : feedrate;
4136 box_coordinates fill_box(Vec2f(0, 0), 0, 0);
4138 block.start_depth + block.layer_depths[m_cur_layer_id] - block.cur_depth - m_perimeter_width);
4139 bool toolchanges_on_layer = m_layer_info->toolchanges_depth() > WT_EPSILON;
4140 const float dy = (fill_box.lu.y() - fill_box.ld.y());
4141 int n = (dy + 0.25 * m_perimeter_width) / m_perimeter_width+1;
4142 float spacing = m_perimeter_width;
4143 Vec2f initial_pos(0, 0);
4144 bool up_to_down = false;
4145 //set initial pos
4146 {
4147 int index = m_cur_layer_id % 4;
4148 float gird_depth = spacing * (n-1);
4149 switch (index % 4) {
4150 case 0:
4151 initial_pos = fill_box.ld;
4152 m_left_to_right = true;
4153 up_to_down = false;
4154 break;
4155 case 1:
4156 initial_pos = Vec2f(fill_box.rd.x(), fill_box.rd.y() + gird_depth);
4157 m_left_to_right = false;
4158 up_to_down = true;
4159 break;
4160 case 2:
4161 initial_pos = fill_box.rd;
4162 m_left_to_right = false;
4163 up_to_down = false;
4164 break;
4165 case 3:
4166 initial_pos = Vec2f(fill_box.ld.x(), gird_depth + fill_box.ld.y());
4167 m_left_to_right = true;
4168 up_to_down = true;
4169 break;
4170 default: break;
4171 }
4172 }
4173 // Extrude infill to support the material to be printed above.
4174 float left = fill_box.lu.x();
4175 float right = fill_box.ru.x();
4176 std::vector<Vec2f> finish_rect_wipe_path;
4177 {
4178 writer
4179 .append(";--------------------\n"
4180 "; CP EMPTY GRID START\n")
4181 .comment_with_value(" layer #", m_num_layer_changes + 1);
4182 bool is_full_block = std::abs(block.cur_depth - block.start_depth) < EPSILON;
4183 if (is_full_block && layer_type == WipeTowerLayerType::Contact && m_enable_tower_interface_features ) {
4184 Vec2f stop_pos = initial_pos;
4185 float filament_tower_interface_pre_extrusion_dist = m_filpar[m_current_tool].filament_tower_interface_pre_extrusion_dist;
4186 // Orca: unscaled(BoundingBox) here is a template returning BoundingBoxBase<Vec2d>, not BoundingBoxf
4187 auto printer_bbx = unscaled(get_extents(m_shared_print_bed));
4188 printer_bbx.translate((- m_wipe_tower_pos - m_rib_offset).cast<double>()); // first layer never be contact
4189 if (stop_pos.x() < m_wipe_tower_width/2.f)
4190 stop_pos = Vec2f(stop_pos.x() - filament_tower_interface_pre_extrusion_dist, stop_pos.y());
4191 else
4192 stop_pos = Vec2f(stop_pos.x() + filament_tower_interface_pre_extrusion_dist, stop_pos.y());
4193 if (stop_pos.x() < printer_bbx.min[0]) stop_pos.x() = printer_bbx.min[0];
4194 if (stop_pos.x() > printer_bbx.max[0]) stop_pos.x() = printer_bbx.max[0];
4195 initial_pos = stop_pos;
4198 writer.retract(-m_filpar[m_current_tool].filament_tower_interface_pre_extrusion_length - 2.f, 100.f);
4199 }
4200 writer.set_initial_position(initial_pos, m_wipe_tower_width, m_wipe_tower_depth, m_internal_rotation);
4201
4202 int i = 0;
4203 for (i = 0; i < n; ++i) {
4204 writer.extrude(m_left_to_right ? right : left, writer.y(), feedrate);
4205 if (i == n - 1) {
4206 writer.add_wipe_point(writer.pos()).add_wipe_point(Vec2f(m_left_to_right ? left : right, writer.y()));
4207 break;
4208 }
4210 writer.extrude(writer.x(), writer.y()+spacing*(up_to_down?-1:1), feedrate);
4211 }
4213 writer.format_line_M104(m_filpar[m_current_tool].nozzle_temperature, get_extruder_id(m_current_tool, m_cur_layer_id));
4214 writer.append("; CP EMPTY GRID END\n"
4215 ";------------------\n\n\n\n\n\n\n");
4216 }
4217
4219
4220 // Ask our writer about how much material was consumed.
4221 // Skip this in case the layer is sparse and config option to not print sparse layers is enabled.
4222 if (layer_is_printed(toolchanges_on_layer))
4223 if (filament_id < m_used_filament_length.size())
4224 m_used_filament_length[filament_id] += writer.get_and_reset_used_filament_length();
4225
4226 return construct_block_tcr(writer, false, filament_id, true, 0.f);
4227}
@ Contact_UP
Definition WipeTower.hpp:417
@ Normal
Definition WipeTower.hpp:417
@ Contact
Definition WipeTower.hpp:417
Polygons m_shared_print_bed
Definition WipeTower.hpp:554
int get_extruder_id(int filament_id, int layer_id) const
Definition WipeTower.cpp:5558
Vec2f m_rib_offset
Definition WipeTower.hpp:526
float extrusion_flow(float layer_height=-1.f) const
Definition WipeTower.hpp:341
zaa_minimize_perimeter_height filament_tower_interface_print_temp((ConfigOptionFloats, filament_cooling_final_speed))((ConfigOptionStrings
zaa_minimize_perimeter_height filament_tower_interface_pre_extrusion_dist((ConfigOptionFloats, filament_tower_interface_pre_extrusion_length))((ConfigOptionFloats
BoundingBox get_extents(const ExPolygonsWithIds &e)
Definition Emboss.cpp:1374
constexpr Eigen::Matrix< Tout, 2, EigenArgs... > unscaled(const Slic3r::Point &v) noexcept
Definition Arrange.cpp:81
auto cast(const BoundingBoxBase< Tin > &b)
Definition BoundingBox.hpp:299

References Slic3r::WipeTowerWriter::add_wipe_point(), Slic3r::WipeTowerWriter::append(), Slic3r::cast(), Slic3r::WipeTowerWriter::comment_with_value(), construct_block_tcr(), Contact, Contact_UP, Slic3r::WipeTower::WipeTowerBlock::cur_depth, EPSILON, Slic3r::WipeTowerWriter::extrude(), extrusion_flow(), Slic3r::filament_tower_interface_pre_extrusion_dist(), Slic3r::filament_tower_interface_print_temp(), Slic3r::WipeTowerWriter::format_line_M104(), Slic3r::WipeTowerWriter::format_line_M109(), Slic3r::WipeTowerWriter::get_and_reset_used_filament_length(), Slic3r::get_extents(), get_extruder_id(), is_first_layer(), Slic3r::WipeTower::WipeTowerBlock::layer_depths, Slic3r::layer_height(), layer_is_printed(), Slic3r::WipeTower::WipeTowerBlock::layers_type, Slic3r::WipeTower::box_coordinates::ld, Slic3r::WipeTower::box_coordinates::lu, m_cur_layer_id, m_current_shape, m_current_tool, m_enable_arc_fitting, m_enable_tower_interface_features, m_extrusion_flow, m_filpar, m_first_layer_speed, m_gcode_flavor, m_internal_rotation, m_layer_height, m_layer_info, m_left_to_right, m_max_speed, m_num_layer_changes, m_perimeter_width, m_rib_offset, m_shared_print_bed, m_used_filament_length, m_wipe_tower_depth, m_wipe_tower_pos, m_wipe_tower_width, m_y_shift, m_z_pos, Normal, Slic3r::WipeTowerWriter::pos(), Slic3r::WipeTower::box_coordinates::rd, Slic3r::GCodeProcessor::reserved_tag(), Slic3r::WipeTowerWriter::retract(), Slic3r::WipeTower::box_coordinates::ru, Slic3r::WipeTowerWriter::set_extrusion_flow(), set_for_wipe_tower_writer(), Slic3r::WipeTowerWriter::set_initial_position(), Slic3r::WipeTowerWriter::set_initial_tool(), Slic3r::WipeTowerWriter::set_y_shift(), Slic3r::WipeTowerWriter::set_z(), SHAPE_REVERSED, Slic3r::WipeTower::WipeTowerBlock::start_depth, Slic3r::unscaled(), Slic3r::GCodeProcessor::Wipe_Tower_End, Slic3r::GCodeProcessor::Wipe_Tower_Start, WipeTowerWriter, WT_EPSILON, Slic3r::WipeTowerWriter::x(), and Slic3r::WipeTowerWriter::y().

Referenced by generate_new().

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

◆ finish_layer()

ToolChangeResult Slic3r::WipeTower::finish_layer ( bool extruder_perimeter = true,
bool extruder_fill = true )

◆ finish_layer_new()

WipeTower::ToolChangeResult Slic3r::WipeTower::finish_layer_new ( bool extrude_perimeter = true,
bool extrude_fill = true,
bool extrude_fill_wall = true )
3808{
3809 assert(!this->layer_finished());
3811
3813 writer.set_extrusion_flow(m_extrusion_flow)
3814 .set_z(m_z_pos)
3815 .set_initial_tool(m_current_tool)
3816 .set_y_shift(m_y_shift - (m_current_shape == SHAPE_REVERSED ? m_layer_info->toolchanges_depth() : 0.f));
3817
3819
3821
3822 // Slow down on the 1st layer.
3823 bool first_layer = is_first_layer();
3824 // BBS: speed up perimeter speed to 90mm/s for non-first layer
3825 float feedrate = first_layer ? std::min(m_first_layer_speed * 60.f, m_max_speed) : std::min(60.0f * m_filpar[m_current_tool].max_e_speed / m_extrusion_flow, m_max_speed);
3826
3827 bool toolchanges_on_layer = m_layer_info->toolchanges_depth() > WT_EPSILON;
3828
3829 std::vector<Vec2f> finish_rect_wipe_path;
3830 const bool multi_block_fill = (m_wipe_tower_blocks.size() > 1) && (extrude_fill_wall || extrude_fill);
3831
3832 // Build list of fill boxes: one per block when multi_block_fill, else one for whole tower.
3833 std::vector<box_coordinates> fill_boxes;
3834 if (multi_block_fill) {
3835 for (const WipeTowerBlock &block : m_wipe_tower_blocks) {
3836 float block_fill_height = block.depth - 2 * m_perimeter_width;
3837 if (m_cur_layer_id >= 0 && size_t(m_cur_layer_id) < block.layer_depths.size())
3838 block_fill_height = block.layer_depths[m_cur_layer_id] - 2 * m_perimeter_width;
3839 if (block_fill_height <= WT_EPSILON)
3840 continue;
3841 fill_boxes.emplace_back(
3842 Vec2f(m_perimeter_width, block.start_depth + m_perimeter_width),
3844 block_fill_height);
3845 }
3846 }
3847 if (fill_boxes.empty()) {
3848 float fill_box_depth = m_wipe_tower_depth - 2 * m_perimeter_width;
3849 if (m_wipe_tower_blocks.size() == 1)
3850 fill_box_depth = m_layer_info->depth - 2 * m_perimeter_width;
3851 fill_boxes.emplace_back(Vec2f(m_perimeter_width, m_perimeter_width), m_wipe_tower_width - 2 * m_perimeter_width, fill_box_depth);
3852 }
3853
3854 writer.set_initial_position((m_left_to_right ? fill_boxes.front().ru : fill_boxes.front().lu), m_wipe_tower_width, m_wipe_tower_depth, m_internal_rotation);
3855
3856 bool solid_infill = (m_layer_info + 1 == m_plan.end()) ? false :
3857 std::any_of((m_layer_info + 1)->tool_changes.begin(), (m_layer_info + 1)->tool_changes.end(),
3858 [this](const WipeTowerInfo::ToolChange &tch) { return m_filpar[tch.new_tool].is_soluble || m_filpar[tch.old_tool].is_soluble; });
3859 solid_infill |= first_layer && m_adhesion;
3860
3861 for (size_t i = 0; i < fill_boxes.size(); ++i) {
3862 const box_coordinates &fill_box = fill_boxes[i];
3863 if (i > 0)
3864 writer.travel(m_left_to_right ? fill_box.ru : fill_box.lu);
3865
3866 if (extrude_fill_wall && (fill_box.ru.y() - fill_box.rd.y() > WT_EPSILON))
3867 writer.rectangle_fill_box(this, fill_box, finish_rect_wipe_path, feedrate);
3868 // Extrude infill to support the material to be printed above.
3869 const float dy = (fill_box.lu.y() - fill_box.ld.y() - m_perimeter_width);
3870 float left = fill_box.lu.x() + 2 * m_perimeter_width;
3871 float right = fill_box.ru.x() - 2 * m_perimeter_width;
3872
3873 if (extrude_fill && dy > m_perimeter_width) {
3874 writer.travel(fill_box.ld + Vec2f(m_perimeter_width * 2, 0.f))
3875 .append(";--------------------\n"
3876 "; CP EMPTY GRID START\n")
3877 .comment_with_value(" layer #", m_num_layer_changes + 1);
3878
3879 if (solid_infill) {
3880 float sparse_factor = 1.5f; // 1=solid, 2=every other line, etc.
3881 if (first_layer) { // the infill should touch perimeters
3884 sparse_factor = 1.f;
3885 }
3886 float y = fill_box.ld.y() + m_perimeter_width;
3887 int n = dy / (m_perimeter_width * sparse_factor);
3888 float spacing = (dy - m_perimeter_width) / (n - 1);
3889 int i = 0;
3890 for (i = 0; i < n; ++i) {
3891 writer.extrude(writer.x(), y, feedrate).extrude(i % 2 ? left : right, y);
3892 y = y + spacing;
3893 }
3894 writer.extrude(writer.x(), fill_box.lu.y());
3895 } else {
3896 // Extrude an inverse U at the left of the region and the sparse infill.
3897 writer.extrude(fill_box.lu + Vec2f(m_perimeter_width * 2, 0.f), feedrate);
3898
3899 const int n = 1 + int((right - left) / m_bridging);
3900 const float dx = (right - left) / n;
3901 for (int i = 1; i <= n; ++i) {
3902 float x = left + dx * i;
3903 writer.travel(x, writer.y());
3904 writer.extrude(x, i % 2 ? fill_box.rd.y() : fill_box.ru.y());
3905 }
3906
3907 finish_rect_wipe_path.clear();
3908 // BBS: add wipe_path for this case: only with finish rectangle
3909 finish_rect_wipe_path.emplace_back(writer.pos());
3910 finish_rect_wipe_path.emplace_back(Vec2f(left + dx * n, n % 2 ? fill_box.ru.y() : fill_box.rd.y()));
3911 }
3912
3913 writer.append("; CP EMPTY GRID END\n"
3914 ";------------------\n\n\n\n\n\n\n");
3915 }
3916 }
3917
3918 // outer perimeter (always):
3919 // BBS
3920 float wipe_tower_depth = m_wipe_tower_depth;
3921 if (m_wipe_tower_blocks.size() == 1) {
3922 wipe_tower_depth = m_layer_info->depth + m_perimeter_width;
3923 }
3924 box_coordinates wt_box(Vec2f(0.f, 0.f), m_wipe_tower_width, wipe_tower_depth);
3925 wt_box = align_perimeter(wt_box);
3926
3927 //if (extrude_perimeter && !m_use_rib_wall) {
3928 // if (!m_use_gap_wall)
3929 // writer.rectangle(wt_box, feedrate);
3930 // else
3931 // generate_support_wall(writer, wt_box, feedrate, first_layer);
3932 //}
3933 Polygon outer_wall;
3934 outer_wall = generate_support_wall_new(writer, wt_box, feedrate, first_layer, m_use_rib_wall, extrude_perimeter, m_use_gap_wall);
3935 if (extrude_perimeter) {
3936 Polyline shift_polyline = to_polyline(outer_wall);
3937 shift_polyline.translate(0, scaled(m_y_shift));
3938 m_outer_wall[m_z_pos].push_back(shift_polyline);
3939 }
3940 // brim chamfer
3941 float spacing = m_perimeter_width - m_layer_height * float(1. - M_PI_4);
3942 // How many perimeters shall the brim have?
3943 int loops_num = (m_wipe_tower_brim_width + spacing / 2.f) / spacing;
3944 const float max_chamfer_width = 3.f;
3945 if (!first_layer) {
3946 // stop print chamfer if depth changes
3947 if (m_layer_info->depth != m_plan.front().depth) {
3948 loops_num = 0;
3949 } else {
3950 // limit max chamfer width to 3 mm
3951 int chamfer_loops_num = (int) (max_chamfer_width / spacing);
3952 int dist_to_1st = m_layer_info - m_plan.begin() - m_first_layer_idx;
3953 loops_num = std::min(loops_num, chamfer_loops_num) - dist_to_1st;
3954 }
3955 }
3956
3957 if (loops_num > 0) {
3958 //box_coordinates box = wt_box;
3959 for (size_t i = 0; i < loops_num; ++i) {
3960 outer_wall = offset(outer_wall, scaled(spacing)).front();
3961 writer.polygon(outer_wall, feedrate);
3962 m_outer_wall[m_z_pos].push_back(to_polyline(outer_wall));
3963 }
3964
3965 /*for (size_t i = 0; i < loops_num; ++i) {
3966 box.expand(spacing);
3967 writer.rectangle(box, feedrate);
3968 }*/
3969
3970 if (first_layer) {
3971 // Save actual brim width to be later passed to the Print object, which will use it
3972 // for skirt calculation and pass it to GLCanvas for precise preview box
3973 m_wipe_tower_brim_width_real = loops_num * spacing + spacing / 2.f;
3974 //m_wipe_tower_brim_width_real = wt_box.ld.x() - box.ld.x() + spacing / 2.f;
3975 }
3976 //wt_box = box;
3977 }
3978
3979 if (extrude_perimeter || loops_num > 0) {
3980 writer.add_wipe_path(outer_wall, m_filpar[m_current_tool].wipe_dist);
3981 }
3982 else {
3983 // Now prepare future wipe. box contains rectangle that was extruded last (ccw).
3984 Vec2f target = (writer.pos() == wt_box.ld ? wt_box.rd : (writer.pos() == wt_box.rd ? wt_box.ru : (writer.pos() == wt_box.ru ? wt_box.lu : wt_box.ld)));
3985
3986 // BBS: add wipe_path for this case: only with finish rectangle
3987 if (finish_rect_wipe_path.size() == 2 && finish_rect_wipe_path[0] == writer.pos()) target = finish_rect_wipe_path[1];
3988
3989 writer.add_wipe_point(writer.pos()).add_wipe_point(target);
3990 }
3992
3993 // Ask our writer about how much material was consumed.
3994 // Skip this in case the layer is sparse and config option to not print sparse layers is enabled.
3995 if (layer_is_printed(toolchanges_on_layer))
3997 m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length();
3998
3999 m_nozzle_change_result.gcode.clear();
4000 return construct_tcr(writer, false, m_current_tool, true, false, 0.f,false);
4001}
std::map< float, Polylines > m_outer_wall
Definition WipeTower.hpp:592
Polygon generate_support_wall_new(WipeTowerWriter &writer, const box_coordinates &wt_box, double feedrate, bool first_layer, bool rib_wall, bool extrude_perimeter, bool skip_points)
Definition WipeTower.cpp:5334
std::vector< WipeTowerBlock > m_wipe_tower_blocks
Definition WipeTower.hpp:442
size_t m_first_layer_idx
Definition WipeTower.hpp:512
ToolChangeResult construct_tcr(WipeTowerWriter &writer, bool priming, size_t old_tool, bool is_finish, bool is_tool_change, float purge_volume, bool is_contact) const
Definition WipeTower.cpp:1637
bool m_current_layer_finished
Definition WipeTower.hpp:586
bool layer_finished() const
Definition WipeTower.hpp:358
float m_wipe_tower_brim_width_real
Definition WipeTower.hpp:502
Definition WipeTower.hpp:420
BoundingBox scaled(const BoundingBoxf &bb)
Definition BoundingBox.hpp:284
Slic3r::Polygons offset(const Slic3r::Polygon &polygon, const float delta, JoinType joinType, double miterLimit)
Definition ClipperUtils.cpp:582
static Polyline to_polyline(const std::vector< TravelPoint > &travel)
Definition AvoidCrossingPerimeters.cpp:370
Slic3r::Polygon Polygon
Definition Emboss.cpp:101

References Slic3r::WipeTowerWriter::add_wipe_path(), Slic3r::WipeTowerWriter::add_wipe_point(), align_perimeter(), Slic3r::WipeTowerWriter::append(), Slic3r::WipeTowerWriter::comment_with_value(), construct_tcr(), Slic3r::WipeTowerWriter::extrude(), generate_support_wall_new(), Slic3r::WipeTowerWriter::get_and_reset_used_filament_length(), is_first_layer(), layer_finished(), layer_is_printed(), Slic3r::WipeTower::box_coordinates::ld, Slic3r::WipeTower::box_coordinates::lu, m_adhesion, m_bridging, m_cur_layer_id, m_current_layer_finished, m_current_shape, m_current_tool, m_enable_arc_fitting, m_extrusion_flow, m_filpar, m_first_layer_idx, m_first_layer_speed, m_gcode_flavor, m_internal_rotation, m_layer_height, m_layer_info, m_left_to_right, m_max_speed, m_nozzle_change_result, m_num_layer_changes, m_outer_wall, m_perimeter_width, m_plan, m_use_gap_wall, m_use_rib_wall, m_used_filament_length, m_wipe_tower_blocks, m_wipe_tower_brim_width, m_wipe_tower_brim_width_real, m_wipe_tower_depth, m_wipe_tower_width, m_y_shift, m_z_pos, Slic3r::offset(), Slic3r::WipeTowerWriter::polygon(), Slic3r::WipeTowerWriter::pos(), Slic3r::WipeTower::box_coordinates::rd, Slic3r::WipeTowerWriter::rectangle_fill_box(), Slic3r::GCodeProcessor::reserved_tag(), Slic3r::WipeTower::box_coordinates::ru, Slic3r::scaled(), Slic3r::WipeTowerWriter::set_extrusion_flow(), set_for_wipe_tower_writer(), Slic3r::WipeTowerWriter::set_initial_position(), Slic3r::WipeTowerWriter::set_initial_tool(), Slic3r::WipeTowerWriter::set_y_shift(), Slic3r::WipeTowerWriter::set_z(), SHAPE_REVERSED, Slic3r::to_polyline(), Slic3r::MultiPoint::translate(), Slic3r::WipeTowerWriter::travel(), Slic3r::GCodeProcessor::Wipe_Tower_End, Slic3r::GCodeProcessor::Wipe_Tower_Start, WipeTowerWriter, WT_EPSILON, Slic3r::WipeTowerWriter::x(), and Slic3r::WipeTowerWriter::y().

Referenced by generate_new().

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

◆ finished()

bool Slic3r::WipeTower::finished ( ) const
inline
317{ return m_max_color_changes == 0; }
size_t m_max_color_changes
Definition WipeTower.hpp:508

References m_max_color_changes.

◆ first_toolchange_to_nonsoluble_nonsupport()

int Slic3r::WipeTower::first_toolchange_to_nonsoluble_nonsupport ( const std::vector< WipeTowerInfo::ToolChange > & tool_changes) const
private
3346{
3347 for (size_t idx=0; idx<tool_changes.size(); ++idx)
3348 if (! m_filpar[tool_changes[idx].new_tool].is_soluble && ! m_filpar[tool_changes[idx].new_tool].is_support)
3349 return idx;
3350 return -1;
3351}
bool is_support(ExtrusionRole role)
Definition ExtrusionEntity.hpp:113

References Slic3r::is_support(), and m_filpar.

Here is the call graph for this function:

◆ generate()

void Slic3r::WipeTower::generate ( std::vector< std::vector< ToolChangeResult > > & result)

References WipeTowerWriter.

Here is the call graph for this function:

◆ generate_new()

void Slic3r::WipeTower::generate_new ( std::vector< std::vector< WipeTower::ToolChangeResult > > & result)
4924{
4925 if (m_plan.empty())
4926 return;
4927 //m_extra_spacing = 1.f;
4928 // Before planning: the layer heights this rewrites feed the extrusion flow of every later pass.
4931 m_wipe_tower_height = m_plan.back().z;//real wipe_tower_height
4933 m_layer_info = m_plan.begin();
4934
4935 for (const auto &layer : m_plan) {
4936 if (!layer.tool_changes.empty()) {
4937 m_current_tool = layer.tool_changes.front().old_tool;
4938 break;
4939 }
4940 }
4941
4942 for (auto &used : m_used_filament_length) // reset used filament stats
4943 used = 0.f;
4944
4945 int wall_filament = get_wall_filament_for_all_layer();
4946
4947 std::vector<WipeTower::ToolChangeResult> layer_result;
4948 int index = 0;
4949 for (auto layer : m_plan) {
4951 m_cur_layer_id = index++;
4952 set_layer(layer.z, layer.height, 0, false, layer.z == m_plan.back().z);
4953 if (m_layer_info->depth < m_perimeter_width) continue;
4954 if (m_wipe_tower_blocks.size() == 1) {
4956 // align y shift to perimeter width
4958 m_y_shift = (m_wipe_tower_depth - m_layer_info->depth) / 2.f;
4960 }
4961 }
4962
4963 //get_wall_skip_points(layer);
4964
4965 ToolChangeResult finish_layer_tcr;
4966 ToolChangeResult timelapse_wall;
4967
4968 auto get_wall_filament_for_this_layer = [this, &layer, &wall_filament]() -> int {
4969 if (layer.tool_changes.size() == 0)
4970 return -1;
4971
4972 if (wall_filament < 0)
4973 return layer.tool_changes[0].new_tool;
4974
4975 int candidate_id = -1;
4976 for (size_t idx = 0; idx < layer.tool_changes.size(); ++idx) {
4977 if (idx == 0) {
4978 if (layer.tool_changes[idx].old_tool == wall_filament && is_valid_last_layer(layer.tool_changes[idx].old_tool, this->m_cur_layer_id, layer.z))
4979 return wall_filament;
4980 else if (m_filpar[layer.tool_changes[idx].old_tool].category == m_filpar[wall_filament].category &&
4981 is_valid_last_layer(layer.tool_changes[idx].old_tool, this->m_cur_layer_id, layer.z)) {
4982 candidate_id = layer.tool_changes[idx].old_tool;
4983 }
4984 }
4985 if (layer.tool_changes[idx].new_tool == wall_filament) {
4986 return wall_filament;
4987 }
4988
4989 if ((candidate_id == -1) && (m_filpar[layer.tool_changes[idx].new_tool].category == m_filpar[wall_filament].category))
4990 candidate_id = layer.tool_changes[idx].new_tool;
4991 }
4992 return candidate_id == -1 ? layer.tool_changes[0].new_tool : candidate_id;
4993 };
4994 int wall_idx = get_wall_filament_for_this_layer();
4995
4997 // this layer has no tool_change
4998 if (wall_idx == -1) {
4999 bool need_insert_solid_infill = false;
5000 for (const WipeTowerBlock &block : m_wipe_tower_blocks) {
5001 if (block.layers_type[m_cur_layer_id] != WipeTowerLayerType::Normal) {
5002 need_insert_solid_infill = true;
5003 break;
5004 }
5005 }
5006
5007 if (need_insert_solid_infill) {
5008 wall_idx = m_current_tool;
5009 } else {
5010 if (only_generate_wall) {
5011 timelapse_wall = only_generate_out_wall(true);
5012 }
5013 finish_layer_tcr = finish_layer_new(only_generate_wall ? false : true, layer.extruder_fill);
5014 std::for_each(m_wipe_tower_blocks.begin(), m_wipe_tower_blocks.end(), [this](WipeTowerBlock &block) {
5015 block.finish_depth[this->m_cur_layer_id] = block.start_depth;
5016 });
5017 }
5018 }
5019
5020 // generate tool change
5021 bool insert_wall = false;
5022 int insert_finish_layer_idx = -1;
5023 if (wall_idx != -1 && only_generate_wall) {
5024 timelapse_wall = only_generate_out_wall(true);
5025 }
5026 for (int i = 0; i < int(layer.tool_changes.size()); ++i) {
5027 ToolChangeResult wall_gcode;
5028 if (i == 0 && (layer.tool_changes[i].old_tool == wall_idx)) {
5029 finish_layer_tcr = finish_layer_new(only_generate_wall ? false : true, false, false);
5030 }
5031 bool solid_nozzlechange = false, solid_toolchange = false;
5032 const auto * block = get_block_by_category(m_filpar[layer.tool_changes[i].new_tool].category, false);
5033 if (block) solid_toolchange = block->layers_type[m_cur_layer_id] == WipeTowerLayerType::Contact;
5034
5035 const auto * block2 = get_block_by_category(m_filpar[layer.tool_changes[i].old_tool].category, false);
5036 if(block2) solid_nozzlechange = block2->layers_type[m_cur_layer_id] == WipeTowerLayerType::Contact;
5037 layer_result.emplace_back(tool_change_new(layer.tool_changes[i].new_tool, solid_toolchange,solid_nozzlechange));
5038
5039 if (i == 0 && (layer.tool_changes[i].old_tool == wall_idx)) {
5040
5041 }
5042 else if (layer.tool_changes[i].new_tool == wall_idx) {
5043 finish_layer_tcr = finish_layer_new(only_generate_wall ? false : true, false, false);
5044 insert_finish_layer_idx = i;
5045 }
5046 }
5047
5048 // insert finish block
5049 if (wall_idx != -1) {
5050 if (layer.tool_changes.empty()) {
5051 finish_layer_tcr = finish_layer_new(only_generate_wall ? false : true, false, false);
5052 }
5053
5054 for (WipeTowerBlock& block : m_wipe_tower_blocks) {
5055 block.finish_depth[m_cur_layer_id] = block.start_depth + block.depth;
5056 if (block.cur_depth + EPSILON >= block.start_depth + block.layer_depths[m_cur_layer_id]-m_perimeter_width) {
5057 continue;
5058 }
5059 int id = std::find_if(m_wipe_tower_blocks.begin(), m_wipe_tower_blocks.end(), [&](const WipeTowerBlock &b) { return &b == &block; }) - m_wipe_tower_blocks.begin();
5060 bool block_solid = block.layers_type[m_cur_layer_id] == WipeTowerLayerType::Contact || block.layers_type[m_cur_layer_id] == WipeTowerLayerType::Contact_UP ||
5061 block.layers_type[m_cur_layer_id] == WipeTowerLayerType::Solid;
5062 int finish_layer_filament = -1;
5063 if (block.last_filament_change_id != -1) {
5064 finish_layer_filament = block.last_filament_change_id;
5065 } else if (block.last_nozzle_change_id != -1) {
5066 finish_layer_filament = block.last_nozzle_change_id;
5067 }
5068
5069 if (!layer.tool_changes.empty()) {
5070 WipeTowerBlock * last_layer_finish_block = get_block_by_category(get_filament_category(layer.tool_changes.front().old_tool), false);
5071 if (last_layer_finish_block && last_layer_finish_block->block_id == block.block_id && finish_layer_filament == -1)
5072 finish_layer_filament = layer.tool_changes.front().old_tool;
5073 }
5074
5075 if (finish_layer_filament == -1) {
5076 finish_layer_filament = wall_idx;
5077 }
5078 // Cancel the block of the last layer
5079 if (!is_valid_last_layer(finish_layer_filament, m_cur_layer_id, layer.z)) continue;
5080 ToolChangeResult finish_block_tcr;
5081 if (block_solid) {
5082 finish_block_tcr = finish_block_solid(block, finish_layer_filament, layer.extruder_fill, block.layers_type[m_cur_layer_id]);
5083 block.finish_depth[m_cur_layer_id] = block.start_depth + block.depth;
5084 }
5085 else {
5086 finish_block_tcr = finish_block(block, finish_layer_filament, layer.extruder_fill);
5087 block.finish_depth[m_cur_layer_id] = block.cur_depth;
5088 }
5089
5090 bool has_inserted = false;
5091 {
5092 auto fc_iter = std::find_if(layer_result.begin(), layer_result.end(),
5093 [&finish_layer_filament](const WipeTower::ToolChangeResult &item) { return item.new_tool == finish_layer_filament; });
5094 if (fc_iter != layer_result.end()) {
5095 *fc_iter = merge_tcr(*fc_iter, finish_block_tcr);
5096 has_inserted = true;
5097 }
5098 }
5099
5100 if (block.last_filament_change_id == -1 && !has_inserted) {
5101 auto nc_iter = std::find_if(layer_result.begin(), layer_result.end(),
5102 [&finish_layer_filament](const WipeTower::ToolChangeResult &item) { return item.initial_tool == finish_layer_filament; });
5103 if (nc_iter != layer_result.end()) {
5104 *nc_iter = merge_tcr(finish_block_tcr, *nc_iter);
5105 has_inserted = true;
5106 }
5107 }
5108
5109 if (!has_inserted && !finish_block_tcr.gcode.empty())
5110 finish_layer_tcr = merge_tcr(finish_layer_tcr, finish_block_tcr);
5111 }
5112 }
5113 // record the contact layers of different categories
5114 if (layer_result.empty()) {
5115 // there is nothing to merge finish_layer with
5116 layer_result.emplace_back(std::move(finish_layer_tcr));
5117 }
5118 else if (is_valid_gcode(finish_layer_tcr.gcode)) {
5119 if (insert_finish_layer_idx == -1)
5120 layer_result[0] = merge_tcr(finish_layer_tcr, layer_result[0]);
5121 else
5122 layer_result[insert_finish_layer_idx] = merge_tcr(layer_result[insert_finish_layer_idx], finish_layer_tcr);
5123 }
5124
5125 if (only_generate_wall && !timelapse_wall.gcode.empty()) {
5126 layer_result.insert(layer_result.begin(), std::move(timelapse_wall));
5127 }
5128 if (layer.combined_away)
5129 for (WipeTower::ToolChangeResult &tcr : layer_result)
5130 tcr.combined_away = true;
5131 result.emplace_back(std::move(layer_result));
5132 }
5133 assert(m_outer_wall.size() == m_plan.size());
5134}
int get_filament_category(int filament_id)
Definition WipeTower.cpp:4476
@ Solid
Definition WipeTower.hpp:417
WipeTowerBlock * get_block_by_category(int filament_adhesiveness_category, bool create)
Definition WipeTower.cpp:4433
bool is_valid_last_layer(int tool, int layer_id, double layer_z) const
Definition WipeTower.cpp:5523
int get_wall_filament_for_all_layer()
Definition WipeTower.cpp:4867
ToolChangeResult finish_block(const WipeTowerBlock &block, int filament_id, bool extrude_fill=true)
Definition WipeTower.cpp:4003
ToolChangeResult tool_change_new(size_t new_tool, bool solid_change=false, bool solid_nozzlechange=false)
Definition WipeTower.cpp:3494
void plan_tower_new()
Definition WipeTower.cpp:4776
ToolChangeResult finish_block_solid(const WipeTowerBlock &block, int filament_id, bool extrude_fill=true, WipeTowerLayerType layer_type=WipeTowerLayerType::Normal)
Definition WipeTower.cpp:4112
void reset_block_status()
Definition WipeTower.cpp:4483
ToolChangeResult merge_tcr(ToolChangeResult &first, ToolChangeResult &second)
Definition WipeTower.cpp:3353
WipeTower::ToolChangeResult only_generate_out_wall(bool is_new_mode=false)
Definition WipeTower.cpp:5242
ToolChangeResult finish_layer_new(bool extrude_perimeter=true, bool extrude_fill=true, bool extrude_fill_wall=true)
Definition WipeTower.cpp:3807
void set_layer(float print_z, float layer_height, size_t max_tool_changes, bool is_first_layer, bool is_last_layer)
Definition WipeTower.hpp:281
float align_round(float value, float base)
Definition WipeTower.cpp:119
static bool is_valid_gcode(const std::string &gcode)
Definition WipeTower.cpp:142
void combine_sparse_wipe_tower_plan(PlanLayers &plan, const FilamentParams &filpar, size_t first_layer_idx, size_t initial_tool)
Definition WipeTower.hpp:747

References Slic3r::align_round(), Slic3r::WipeTower::WipeTowerBlock::block_id, Slic3r::combine_sparse_wipe_tower_plan(), Contact, Contact_UP, EPSILON, finish_block(), finish_block_solid(), finish_layer_new(), Slic3r::WipeTower::ToolChangeResult::gcode, get_block_by_category(), get_filament_category(), get_wall_filament_for_all_layer(), Slic3r::is_valid_gcode(), is_valid_last_layer(), m_cur_layer_id, m_current_tool, m_enable_timelapse_print, m_enable_wrapping_detection, m_extra_spacing, m_filpar, m_first_layer_idx, m_layer_info, m_outer_wall, m_perimeter_width, m_plan, m_slice_used_filaments, m_sparse_layers_combined, m_used_filament_length, m_wipe_tower_blocks, m_wipe_tower_depth, m_wipe_tower_height, m_y_shift, merge_tcr(), Normal, only_generate_out_wall(), plan_tower_new(), reset_block_status(), set_layer(), Solid, and tool_change_new().

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::WipeTower::generate_rib_polygon ( const box_coordinates & wt_box)
5303{
5304 auto get_current_layer_rib_len = [](float cur_height, float max_height, float max_len) -> float { return std::abs(max_height - cur_height) / max_height * max_len; };
5305 coord_t diagonal_width = scaled(m_rib_width)/2;
5306 float a = this->m_wipe_tower_width, b = this->m_wipe_tower_depth;
5307 Line line_1(Point::new_scale(Vec2f{0, 0}), Point::new_scale(Vec2f{a, b}));
5308 Line line_2(Point::new_scale(Vec2f{a, 0}), Point::new_scale(Vec2f{0, b}));
5309 float diagonal_extra_length = std::max(0.f, m_rib_length - (float) unscaled(line_1.length())) / 2.f;
5310 diagonal_extra_length = scaled(get_current_layer_rib_len(this->m_z_pos, this->m_wipe_tower_height, diagonal_extra_length));
5311 Point y_shift{0, scaled(this->m_y_shift)};
5312
5313 line_1.extend(double(diagonal_extra_length));
5314 line_2.extend(double(diagonal_extra_length));
5315 line_1.translate(-y_shift);
5316 line_2.translate(-y_shift);
5317
5318 Polygon poly_1 = generate_rectange(line_1, diagonal_width);
5319 Polygon poly_2 = generate_rectange(line_2, diagonal_width);
5320 Polygon poly;
5321 poly.points.push_back(Point::new_scale(wt_box.ld));
5322 poly.points.push_back(Point::new_scale(wt_box.rd));
5323 poly.points.push_back(Point::new_scale(wt_box.ru));
5324 poly.points.push_back(Point::new_scale(wt_box.lu));
5325
5326 Polygons p_1_2 = union_({poly_1, poly_2, poly});
5327 //Polygon res_poly = p_1_2.front();
5328 //for (auto &p : res_poly.points) res.push_back(unscale(p).cast<float>());
5329 /*if (p_1_2.front().points.size() != 16)
5330 std::cout << "error " << std::endl;*/
5331 return p_1_2.front();
5332};
static Point new_scale(coordf_t x, coordf_t y)
Definition Point.hpp:214
float m_rib_length
Definition WipeTower.hpp:522
int64_t coord_t
Definition libslic3r.h:48
void poly(std::vector< std::pair< Vec2d, Vec2d > > &out, std::initializer_list< Vec2d > p)
Definition DesignSketchTool.cpp:7751
Kernel::Point_3 Point
Definition MeshRepair.cpp:81
Slic3r::Polygons union_(const Slic3r::Polygons &subject)
Definition ClipperUtils.cpp:801
std::vector< Polygon, PointsAllocator< Polygon > > Polygons
Definition Polygon.hpp:22
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_wall_new().

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

◆ generate_support_wall()

Polygon Slic3r::WipeTower::generate_support_wall ( WipeTowerWriter & writer,
const box_coordinates & wt_box,
double feedrate,
bool first_layer )
5386{
5387 float retract_length = m_filpar[m_current_tool].retract_length;
5388 float retract_speed = m_filpar[m_current_tool].retract_speed *60 ;
5389 bool is_left = false;
5390 bool is_right = false;
5391 for (auto pt : m_wall_skip_points[m_cur_layer_id]) {
5392 if (abs(pt.x()) < EPSILON) {
5393 is_left = true;
5394 } else if (abs(pt.x() - m_wipe_tower_width) < EPSILON) {
5395 is_right = true;
5396 }
5397 }
5398
5399 if (is_left && is_right) {
5400 Vec2f *p = nullptr;
5401 p->x();
5402 }
5403
5404 if (!is_left && !is_right) {
5405 Vec2f *p = nullptr;
5406 p->x();
5407 }
5408
5409 // 3 ------------- 2
5410 // | |
5411 // | |
5412 // 0 ------------- 1
5413
5414 int index = 0;
5415 Vec2f cur_pos = writer.pos();
5416 if (abs(cur_pos.x() - wt_box.ld.x()) > abs(cur_pos.x() - wt_box.rd.x())) {
5417 if (abs(cur_pos.y() - wt_box.ld.y()) > abs(cur_pos.y() - wt_box.lu.y())) {
5418 index = 2;
5419 } else {
5420 index = 1;
5421 }
5422 } else {
5423 if (abs(cur_pos.y() - wt_box.ld.y()) > abs(cur_pos.y() - wt_box.lu.y())) {
5424 index = 3;
5425 } else {
5426 index = 0;
5427 }
5428 }
5429
5430 std::vector<Vec2f> points;
5431 points.emplace_back(wt_box.ld);
5432 points.emplace_back(wt_box.rd);
5433 points.emplace_back(wt_box.ru);
5434 points.emplace_back(wt_box.lu);
5435
5436 writer.travel(points[index]);
5437 int extruded_nums = 0;
5438 while (extruded_nums < 4) {
5439 index = (index + 1) % 4;
5440 if (index == 2) {
5441 if (is_right) {
5442 std::vector<Segment> break_segments = remove_points_from_segment(Segment(wt_box.rd, wt_box.ru), m_wall_skip_points[m_cur_layer_id], 2.5 * m_perimeter_width);
5443 for (auto iter = break_segments.begin(); iter != break_segments.end(); ++iter) {
5444 float dx = iter->start.x() - writer.pos().x();
5445 float dy = iter->start.y() - writer.pos().y();
5446 float len = std::sqrt(dx * dx + dy * dy);
5447 if (len > 0) {
5448 writer.retract(retract_length, retract_speed);
5449 writer.travel(iter->start, 600.);
5450 writer.retract(-retract_length, retract_speed);
5451 } else
5452 writer.travel(iter->start, 600.);
5453
5454 writer.extrude(iter->end, feedrate);
5455 }
5456 writer.travel(wt_box.ru, feedrate);
5457 } else {
5458 writer.extrude(wt_box.ru, feedrate);
5459 }
5460 } else if (index == 0) {
5461 if (is_left) {
5462 std::vector<Segment> break_segments = remove_points_from_segment(Segment(wt_box.ld, wt_box.lu), m_wall_skip_points[m_cur_layer_id], 2.5 * m_perimeter_width);
5463 for (auto iter = break_segments.rbegin(); iter != break_segments.rend(); ++iter) {
5464 float dx = iter->end.x() - writer.pos().x();
5465 float dy = iter->end.y() - writer.pos().y();
5466 float len = std::sqrt(dx * dx + dy * dy);
5467 if (len > 0) {
5468 writer.retract(retract_length, retract_speed);
5469 writer.travel(iter->end, 600.);
5470 writer.retract(-retract_length, retract_speed);
5471 } else
5472 writer.travel(iter->end, 600.);
5473
5474 writer.extrude(iter->start, feedrate);
5475 }
5476 writer.travel(wt_box.ld, feedrate);
5477 } else {
5478 writer.extrude(wt_box.ld, feedrate);
5479 }
5480 } else {
5481 writer.extrude(points[index], feedrate);
5482 }
5483 extruded_nums++;
5484 }
5485
5486 return Polygon();
5487}
std::vector< std::vector< Vec2f > > m_wall_skip_points
Definition WipeTower.hpp:591
std::vector< Segment > remove_points_from_segment(const Segment &segment, const std::vector< Vec2f > &skip_points, double range)
Definition WipeTower.cpp:398

References EPSILON, Slic3r::WipeTowerWriter::extrude(), Slic3r::WipeTower::box_coordinates::ld, Slic3r::WipeTower::box_coordinates::lu, m_cur_layer_id, m_current_tool, m_filpar, m_perimeter_width, m_wall_skip_points, m_wipe_tower_width, Slic3r::WipeTowerWriter::pos(), Slic3r::WipeTower::box_coordinates::rd, Slic3r::remove_points_from_segment(), Slic3r::WipeTowerWriter::retract(), Slic3r::WipeTower::box_coordinates::ru, Slic3r::WipeTowerWriter::travel(), and WipeTowerWriter.

Here is the call graph for this function:

◆ generate_support_wall_new()

Polygon Slic3r::WipeTower::generate_support_wall_new ( WipeTowerWriter & writer,
const box_coordinates & wt_box,
double feedrate,
bool first_layer,
bool rib_wall,
bool extrude_perimeter,
bool skip_points )
5335{
5336 auto get_closet_idx = [&writer](Polylines &pls) -> std::pair<int,int> {
5337 Vec2f anchor{writer.x(), writer.y()};
5338 int closestIndex = -1;
5339 int closestPl = -1;
5340 float minDistance = std::numeric_limits<float>::max();
5341 for (int i = 0; i < pls.size(); ++i) {
5342 for (int j = 0; j < pls[i].size(); ++j) {
5343 float distance = (unscaled<float>(pls[i][j]) - anchor).squaredNorm();
5344 if (distance < minDistance) {
5345 minDistance = distance;
5346 closestPl = i;
5347 closestIndex = j;
5348 }
5349 }
5350 }
5351 return {closestPl, closestIndex};
5352 };
5353
5354 float retract_length = m_filpar[m_current_tool].retract_length;
5355 float retract_speed = m_filpar[m_current_tool].retract_speed * 60;
5356 Polygon wall_polygon = rib_wall ? generate_rib_polygon(wt_box) : generate_rectange_polygon(wt_box.ld, wt_box.ru);
5357 Polylines result_wall;
5358 Polygon insert_skip_polygon;
5359 if (m_used_fillet) {
5360 if (!rib_wall && m_y_shift > EPSILON)// do nothing because the fillet will cause it to be suspended.
5361 {
5362 } else {
5363 wall_polygon = rib_wall ? rounding_polygon(wall_polygon) : wall_polygon; // rectangle_wall do nothing
5364 Polygon wt_box_polygon = generate_rectange_polygon(wt_box.ld, wt_box.ru);
5365 wall_polygon = union_({wall_polygon, wt_box_polygon}).front();
5366 }
5367 }
5368 if (!extrude_perimeter) return wall_polygon;
5369
5370 if (skip_points) {
5371 result_wall = construct_gap_for_skip_points(wall_polygon, m_wall_skip_points[m_cur_layer_id], m_wipe_tower_width, 2.5 * m_perimeter_width, insert_skip_polygon);
5372 }
5373 else {
5374 result_wall.push_back(to_polyline(wall_polygon));
5375 insert_skip_polygon = wall_polygon;
5376 }
5377 writer.generate_path(result_wall, feedrate, retract_length, retract_speed,m_used_fillet);
5378 if (m_cur_layer_id == 0) {
5379 BoundingBox bbox = get_extents(result_wall);
5380 m_rib_offset = Vec2f(-unscaled<float>(bbox.min.x()), -unscaled<float>(bbox.min.y()));
5381 }
5382 return insert_skip_polygon;
5383}
Polygon generate_rib_polygon(const box_coordinates &wt_box)
Definition WipeTower.cpp:5302
static Polygon rounding_polygon(Polygon &polygon, double rounding=2., double angle_tol=30./180. *PI)
Definition WipeTower.cpp:205
float distance(SpiralVase::SpiralPoint a, SpiralVase::SpiralPoint b)
Definition SpiralVase.cpp:19
std::vector< Polyline > Polylines
Definition Polyline.hpp:22
Polygon generate_rectange_polygon(const Vec2f &wt_box_min, const Vec2f &wt_box_max)
Definition WipeTower.cpp:710
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

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

Referenced by finish_layer_new(), and only_generate_out_wall().

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

◆ generate_wipe_tower_blocks()

void Slic3r::WipeTower::generate_wipe_tower_blocks ( bool add_solid_flag)
4559{
4560 // 1. generate all layer depth
4561 m_all_layers_depth.clear();
4562 m_all_layers_depth.resize(m_plan.size());
4563 m_cur_layer_id = 0;
4564 for (auto& info : m_plan) {
4565 for (const WipeTowerInfo::ToolChange &tool_change : info.tool_changes) {
4566 if (!is_need_ramming(tool_change.old_tool, tool_change.new_tool, m_cur_layer_id)) {
4569 }
4570 else {
4571 int old_filament_category = get_filament_category(tool_change.old_tool);
4572 add_depth_to_block(tool_change.old_tool, old_filament_category, tool_change.nozzle_change_depth, true);
4573 int new_filament_category = get_filament_category(tool_change.new_tool);
4574 add_depth_to_block(tool_change.new_tool, new_filament_category, tool_change.required_depth - tool_change.nozzle_change_depth);
4575
4576 }
4577 }
4579 }
4580
4581 // 2. generate all layer depth
4582 std::vector<std::unordered_map<int, float>> all_layer_category_to_depth(m_plan.size());
4583 for (size_t layer_id = 0; layer_id < m_all_layers_depth.size(); ++layer_id) {
4584 const auto& layer_blocks = m_all_layers_depth[layer_id];
4585 std::unordered_map<int, float> &category_to_depth = all_layer_category_to_depth[layer_id];
4586 for (auto block : layer_blocks) {
4587 category_to_depth[block.category] = block.depth;
4588 }
4589 }
4590
4591 // 3. generate wipe tower block
4592 m_wipe_tower_blocks.clear();
4593 for (int layer_id = 0; layer_id < all_layer_category_to_depth.size(); ++layer_id) {
4594 const auto &layer_category_depths = all_layer_category_to_depth[layer_id];
4595 for (auto iter = layer_category_depths.begin(); iter != layer_category_depths.end(); ++iter) {
4596 auto* block = get_block_by_category(iter->first, true);
4597 if (block->layer_depths.empty()) {
4598 block->layer_depths.resize(all_layer_category_to_depth.size(), 0);
4599 block->finish_depth.resize(all_layer_category_to_depth.size(), 0);
4600 block->layers_type.resize(all_layer_category_to_depth.size(), WipeTowerLayerType::Normal);
4601 }
4602 block->depth = std::max(block->depth, iter->second);
4603 block->layer_depths[layer_id] = iter->second;
4604 }
4605 }
4606 // 4. get real depth for every layer
4607 for (int layer_id = m_plan.size() - 1; layer_id >= 0; --layer_id) {
4608 m_plan[layer_id].depth = 0;
4609 for (auto& block : m_wipe_tower_blocks) {
4610 if (layer_id < m_plan.size() - 1)
4611 block.layer_depths[layer_id] = std::max(block.layer_depths[layer_id], block.layer_depths[layer_id + 1]);
4612 m_plan[layer_id].depth += block.layer_depths[layer_id];
4613 }
4614 }
4615
4616 if (m_tower_framework) {
4617 for (int layer_id = 1; layer_id < m_plan.size(); ++layer_id) {
4618 m_plan[layer_id].depth = 0;
4619 for (auto &block : m_wipe_tower_blocks) {
4620 block.layer_depths[layer_id] = block.layer_depths[0];
4621 m_plan[layer_id].depth += block.layer_depths[layer_id];
4622 }
4623 }
4624 }
4625
4626 // add solid infill flag
4627 if (add_solid_flag) {
4628 int solid_infill_layer_low = 4;
4629 std::vector<std::unordered_set<int>> layers_used_tools;
4630
4631 int first_tool = -1;
4632 for (const auto &layer : m_plan) {
4633 if (!layer.tool_changes.empty()) {
4634 first_tool = layer.tool_changes.front().old_tool;
4635 break;
4636 }
4637 }
4638 for (auto &info : m_plan) {
4639 std::unordered_set<int> used_tools;
4640 if (info.tool_changes.empty()) {
4641 used_tools.insert(get_filament_category(first_tool));
4642 } else {
4643 for (const WipeTowerInfo::ToolChange &tool_change : info.tool_changes) {
4644 used_tools.insert(get_filament_category(tool_change.old_tool));
4645 used_tools.insert(get_filament_category(tool_change.new_tool));
4646 }
4647 first_tool = info.tool_changes.back().new_tool;
4648 }
4649 layers_used_tools.push_back(used_tools);
4650 }
4651
4652 for (WipeTowerBlock &block : m_wipe_tower_blocks) {
4653 for (int layer_id = 0; layer_id < all_layer_category_to_depth.size(); ++layer_id) {
4654 std::unordered_map<int, float> &category_to_depth = all_layer_category_to_depth[layer_id];
4655 if (category_to_depth[block.filament_adhesiveness_category] < block.layer_depths[layer_id] - m_perimeter_width) {
4656 bool cur_has_block_category = layers_used_tools[layer_id].count(block.filament_adhesiveness_category);
4657 int layer_count = solid_infill_layer_low;
4658 while (layer_count > 0) {
4659 if (layer_id + layer_count < all_layer_category_to_depth.size()) {
4660 std::unordered_map<int, float> &up_layer_depth = all_layer_category_to_depth[layer_id + layer_count];
4661 {
4662 bool up_has_block_category = layers_used_tools[layer_id + layer_count].count(block.filament_adhesiveness_category);
4663 if (cur_has_block_category != up_has_block_category) {
4664 block.layers_type[layer_id] = WipeTowerLayerType::Solid;
4665 break;
4666 }
4667 }
4668 }
4669 --layer_count;
4670 }
4671 }
4672 if (layer_id > 0) {
4673 bool cur_has_block_category = layers_used_tools[layer_id].count(block.filament_adhesiveness_category);
4674 bool pre_has_block_category = layers_used_tools[layer_id - 1].count(block.filament_adhesiveness_category);
4675 if (cur_has_block_category != pre_has_block_category) { block.layers_type[layer_id] = WipeTowerLayerType::Contact; }
4676 if (block.layers_type[layer_id - 1] == WipeTowerLayerType::Contact && block.layers_type[layer_id] != WipeTowerLayerType::Contact) {
4677 block.layers_type[layer_id] = WipeTowerLayerType::Contact_UP;
4678 }
4679 }
4680 }
4681 }
4682 }
4683
4684}
ToolChangeResult tool_change(size_t new_tool, bool extrude_perimeter=false, bool first_toolchange_to_nonsoluble=false)
Definition WipeTower.cpp:2285
void add_depth_to_block(int filament_id, int filament_adhesiveness_category, float depth, bool is_nozzle_change=false)
Definition WipeTower.cpp:4454

References add_depth_to_block(), Contact, Contact_UP, Slic3r::filament_adhesiveness_category(), get_block_by_category(), get_filament_category(), is_need_ramming(), m_all_layers_depth, m_cur_layer_id, m_perimeter_width, m_plan, m_tower_framework, m_wipe_tower_blocks, Normal, Solid, and tool_change().

Referenced by plan_tower_new().

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

◆ get_all_wall_skip_points()

void Slic3r::WipeTower::get_all_wall_skip_points ( )
private
3400 {
3401 m_wall_skip_points.clear();
3402 m_wall_skip_points.resize(m_plan.size());
3403 for (int i = 0; i < m_plan.size(); i++) {
3404 const WipeTowerInfo &layer = m_plan[i];
3406 }
3407}
void get_wall_skip_points(const WipeTowerInfo &layer, int layer_id)
Definition WipeTower.cpp:3410
Definition WipeTower.hpp:632

References get_wall_skip_points(), m_plan, and m_wall_skip_points.

Referenced by plan_tower_new().

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

◆ get_auto_brim_by_height()

float Slic3r::WipeTower::get_auto_brim_by_height ( float max_height)
static
1733 {
1734 if (max_height < 100) return max_height/100.f * 8.f;
1735 return 8.f;
1736}

Referenced by Slic3r::estimate_wipe_tower_footprint(), Slic3r::WipeTower2::finish_layer(), Slic3r::GUI::GLCanvas3D::get_wipe_tower_info(), plan_tower_new(), and Slic3r::WipeTower2::toolchange_Change().

Here is the caller graph for this function:

◆ get_bbx()

BoundingBoxf Slic3r::WipeTower::get_bbx ( ) const
inline
258 {
259 if (m_outer_wall.empty()) return BoundingBoxf({Vec2d(0,0)});
260 BoundingBox box = get_extents(m_outer_wall.begin()->second);
261 BoundingBoxf res = BoundingBoxf(unscale(box.min), unscale(box.max));
262 return res;
263 }
T unscale(Q v)
Definition libslic3r.h:138

References Slic3r::get_extents(), m_outer_wall, and Slic3r::unscale().

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

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

◆ get_block_by_category()

WipeTower::WipeTowerBlock * Slic3r::WipeTower::get_block_by_category ( int filament_adhesiveness_category,
bool create )
4434{
4435 auto iter = std::find_if(m_wipe_tower_blocks.begin(), m_wipe_tower_blocks.end(), [&filament_adhesiveness_category](const WipeTower::WipeTowerBlock &item) {
4436 return item.filament_adhesiveness_category == filament_adhesiveness_category;
4437 });
4438
4439 if (iter != m_wipe_tower_blocks.end()) {
4440 return &(*iter);
4441 }
4442
4443 if (create) {
4444 WipeTower::WipeTowerBlock new_block;
4445 new_block.block_id = m_wipe_tower_blocks.size();
4446 new_block.filament_adhesiveness_category = filament_adhesiveness_category;
4447 m_wipe_tower_blocks.emplace_back(new_block);
4448 return &m_wipe_tower_blocks.back();
4449 }
4450
4451 return nullptr;
4452}

References Slic3r::WipeTower::WipeTowerBlock::block_id, Slic3r::filament_adhesiveness_category(), Slic3r::WipeTower::WipeTowerBlock::filament_adhesiveness_category, and m_wipe_tower_blocks.

Referenced by generate_new(), generate_wipe_tower_blocks(), get_wall_skip_points(), ramming(), and tool_change_new().

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

◆ get_block_gap_width()

float Slic3r::WipeTower::get_block_gap_width ( int tool,
bool is_nozzlechangle = false )
private
5531{
5532 //assert(m_block_infill_gap_width.count(m_filpar[tool].category));//The code contains logic that attempts to access non-existent blocks,
5533 // such as in case of involving two extruders with only a single head and a single layer,
5534 // some code will attempt to access the block's nozzle_change_gap_width, even though the block does not exist.
5535 if (!m_block_infill_gap_width.count(m_filpar[tool].category)) {
5536 return is_nozzlechangle ? m_nozzle_change_perimeter_width : m_perimeter_width;
5537 }
5538 return is_nozzlechangle ? m_block_infill_gap_width[m_filpar[tool].category].second : m_block_infill_gap_width[m_filpar[tool].category].first;
5539
5540}

References m_block_infill_gap_width, m_filpar, m_nozzle_change_perimeter_width, and m_perimeter_width.

Referenced by get_next_pos(), get_wall_skip_points(), ramming(), set_toolchange(), and toolchange_wipe_new().

Here is the caller graph for this function:

◆ get_brim_width()

float Slic3r::WipeTower::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::WipeTower::get_depth ( ) const
inline
256{ 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_extruder_id()

int Slic3r::WipeTower::get_extruder_id ( int filament_id,
int layer_id ) const
5558 {
5559 return m_multi_nozzle_group_result->get_extruder_id(filament_id, layer_id);
5560}
const MultiNozzleUtils::LayeredNozzleGroupResult * m_multi_nozzle_group_result
Definition WipeTower.hpp:415

References m_multi_nozzle_group_result.

Referenced by finish_block_solid(), is_valid_last_layer(), ramming(), set_nozzle_last_layer_id(), and toolchange_wipe_new().

Here is the caller graph for this function:

◆ get_extrusion_flow()

float Slic3r::WipeTower::get_extrusion_flow ( ) const
inline
355{ return m_extrusion_flow; }

References m_extrusion_flow.

Referenced by Slic3r::WipeTowerWriter::line(), and Slic3r::WipeTowerWriter::rectangle_fill_box().

Here is the caller graph for this function:

◆ get_filament_category()

int Slic3r::WipeTower::get_filament_category ( int filament_id)
4477{
4478 if (filament_id >= m_filament_categories.size())
4479 return 0;
4480 return m_filament_categories[filament_id];
4481}
std::vector< int > m_filament_categories
Definition WipeTower.hpp:414

References m_filament_categories.

Referenced by generate_new(), generate_wipe_tower_blocks(), get_wall_filament_for_all_layer(), and get_wall_skip_points().

Here is the caller graph for this function:

◆ get_floating_area()

bool Slic3r::WipeTower::get_floating_area ( float & start_pos_y,
float & end_pos_y ) const
5490 {
5491 if (m_layer_info == m_plan.begin() || (m_layer_info - 1) == m_plan.begin())
5492 return false;
5493
5494 if (!m_cur_block)
5495 return false;
5496
5497 end_pos_y = m_cur_block->start_depth + m_cur_block->depth - m_perimeter_width;
5498 start_pos_y = m_cur_block->finish_depth[m_cur_layer_id - 1];
5499
5500#if 0
5501 float last_layer_fill_box_y = (m_layer_info - 1)->toolchanges_depth() + m_perimeter_width;
5502 float last_layer_wipe_depth = (m_layer_info - 1)->depth;
5503 if (last_layer_wipe_depth - last_layer_fill_box_y <= 2 * m_perimeter_width)
5504 return false;
5505
5506 start_pos_y = last_layer_fill_box_y + m_perimeter_width;
5507 end_pos_y = last_layer_wipe_depth - m_perimeter_width;
5508#endif
5509 return true;
5510}
WipeTowerBlock * m_cur_block
Definition WipeTower.hpp:444

References m_cur_block, m_cur_layer_id, m_layer_info, m_perimeter_width, and m_plan.

Referenced by need_thick_bridge_flow().

Here is the caller graph for this function:

◆ get_height()

float Slic3r::WipeTower::get_height ( ) const
inline
268{ 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_layer_height()

float Slic3r::WipeTower::get_layer_height ( ) const
inline
269{ return m_layer_height; }

References m_layer_height.

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

Here is the caller graph for this function:

◆ get_limit_depth_by_height()

float Slic3r::WipeTower::get_limit_depth_by_height ( float max_height)
static
1698{
1699 float min_wipe_tower_depth = 0.f;
1700 auto iter = WipeTower::min_depth_per_height.begin();
1701 while (iter != WipeTower::min_depth_per_height.end()) {
1702 auto curr_height_to_depth = *iter;
1703
1704 // This is the case that wipe tower height is lower than the first min_depth_to_height member.
1705 if (curr_height_to_depth.first >= max_height) {
1706 min_wipe_tower_depth = curr_height_to_depth.second;
1707 break;
1708 }
1709
1710 iter++;
1711
1712 // If curr_height_to_depth is the last member, use its min_depth.
1713 if (iter == WipeTower::min_depth_per_height.end()) {
1714 min_wipe_tower_depth = curr_height_to_depth.second;
1715 break;
1716 }
1717
1718 // If wipe tower height is between the current and next member, set the min_depth as linear interpolation between them
1719 auto next_height_to_depth = *iter;
1720 if (next_height_to_depth.first > max_height) {
1721 float height_base = curr_height_to_depth.first;
1722 float height_diff = next_height_to_depth.first - curr_height_to_depth.first;
1723 float min_depth_base = curr_height_to_depth.second;
1724 float depth_diff = next_height_to_depth.second - curr_height_to_depth.second;
1725
1726 min_wipe_tower_depth = min_depth_base + (max_height - curr_height_to_depth.first) / height_diff * depth_diff;
1727 break;
1728 }
1729 }
1730 return min_wipe_tower_depth;
1731}
static const std::map< float, float > min_depth_per_height
Definition WipeTower.hpp:49
T * end(Slic3r::Mat< N, M, T > &mat)
Definition Point.hpp:841

References min_depth_per_height.

Referenced by calc_block_infill_gap(), Slic3r::estimate_wipe_tower_footprint(), Slic3r::WipeTower2::generate(), plan_tower_new(), and rib_footprint_side().

Here is the caller graph for this function:

◆ get_next_pos()

Vec2f Slic3r::WipeTower::get_next_pos ( const WipeTower::box_coordinates & cleaning_box,
float wipe_length,
bool solid_toolchange )
private
2236{
2237 const float &xl = cleaning_box.ld.x();
2238 const float &xr = cleaning_box.rd.x();
2239 int line_count = wipe_length / (xr - xl);
2240
2241 float dy = m_layer_info->extra_spacing * get_block_gap_width(m_current_tool,false);
2242 float y_offset = float(line_count) * dy;
2243 const Vec2f pos_offset = Vec2f(0.f, m_depth_traversed);
2244
2245 Vec2f res;
2246 int index = m_cur_layer_id % 4;
2247 //Vec2f offset = m_use_gap_wall ? Vec2f(5 * m_perimeter_width, 0) : Vec2f{0, 0};
2248 Vec2f offset = Vec2f{0, 0};
2249 switch (index % 4) {
2250 case 0:
2251 res = offset +cleaning_box.ld + pos_offset;
2252 break;
2253 case 1:
2254 res = -offset +cleaning_box.rd + pos_offset + Vec2f(0, y_offset);
2255 break;
2256 case 2:
2257 res = -offset+ cleaning_box.rd + pos_offset;
2258 break;
2259 case 3:
2260 res = offset+cleaning_box.ld + pos_offset + Vec2f(0, y_offset);
2261 break;
2262 default: break;
2263 }
2264 bool is_contact_pre_extrusion = solid_toolchange && m_enable_tower_interface_features;
2265 bool is_petg_pre_extrusion = !is_contact_pre_extrusion && is_petg_filament(m_current_tool) && m_has_filament_switcher;
2266 if (is_contact_pre_extrusion || is_petg_pre_extrusion) {
2267 Vec2f stop_pos = res;
2268 float filament_tower_interface_pre_extrusion_dist = is_petg_pre_extrusion
2269 ? m_filpar[m_current_tool].filament_petg_pre_extrusion_offset_dist
2270 : m_filpar[m_current_tool].filament_tower_interface_pre_extrusion_dist;
2271 // Orca: unscaled(BoundingBox) here is a template returning BoundingBoxBase<Vec2d>, not BoundingBoxf
2272 auto printer_bbx = unscaled(get_extents(m_shared_print_bed));
2273 printer_bbx.translate((-m_wipe_tower_pos - m_rib_offset).cast<double>()); // first layer never be contact
2274 if (stop_pos.x() < m_wipe_tower_width / 2.f)
2275 stop_pos = Vec2f(stop_pos.x() - filament_tower_interface_pre_extrusion_dist, stop_pos.y());
2276 else
2277 stop_pos = Vec2f(stop_pos.x() + filament_tower_interface_pre_extrusion_dist, stop_pos.y());
2278 if (stop_pos.x() < printer_bbx.min[0]) stop_pos.x() = printer_bbx.min[0];
2279 if (stop_pos.x() > printer_bbx.max[0]) stop_pos.x() = printer_bbx.max[0];
2280 res = stop_pos;
2281 }
2282 return res;
2283}
bool is_petg_filament(int filament_id) const
Definition WipeTower.cpp:3329
float m_depth_traversed
Definition WipeTower.hpp:585
bool m_has_filament_switcher
Definition WipeTower.hpp:598
float get_block_gap_width(int tool, bool is_nozzlechangle=false)
Definition WipeTower.cpp:5530

References Slic3r::cast(), Slic3r::filament_tower_interface_pre_extrusion_dist(), get_block_gap_width(), Slic3r::get_extents(), is_petg_filament(), Slic3r::WipeTower::box_coordinates::ld, m_cur_layer_id, m_current_tool, m_depth_traversed, m_enable_tower_interface_features, m_filpar, m_has_filament_switcher, m_layer_info, m_rib_offset, m_shared_print_bed, m_wipe_tower_pos, m_wipe_tower_width, Slic3r::offset(), Slic3r::WipeTower::box_coordinates::rd, and Slic3r::unscaled().

Referenced by tool_change(), and tool_change_new().

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

◆ get_nozzle_id()

int Slic3r::WipeTower::get_nozzle_id ( int filament_id,
int layer_id ) const
5556{ return m_multi_nozzle_group_result->get_nozzle_id(filament_id, layer_id); }

References m_multi_nozzle_group_result.

Referenced by ramming().

Here is the caller graph for this function:

◆ get_number_of_toolchanges()

int Slic3r::WipeTower::get_number_of_toolchanges ( ) const
inline
363{ return m_num_tool_changes; }
unsigned int m_num_tool_changes
Definition WipeTower.hpp:576

References m_num_tool_changes.

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

Here is the caller graph for this function:

◆ get_outer_wall()

std::map< float, Polylines > Slic3r::WipeTower::get_outer_wall ( ) const
inline
265 {
266 return m_outer_wall;
267 }

References m_outer_wall.

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

Here is the caller graph for this function:

◆ get_rib_length()

float Slic3r::WipeTower::get_rib_length ( ) const
inline
270{ 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::WipeTower::get_rib_offset ( ) const
inline
471{ 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::WipeTower::get_rib_width ( ) const
inline
271{ 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::WipeTower::get_used_filament ( ) const
inline
362{ 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_wall_filament_for_all_layer()

int Slic3r::WipeTower::get_wall_filament_for_all_layer ( )
4868{
4869 std::map<int, int> category_counts;
4870 std::map<int, int> filament_counts;
4871 int current_tool = m_current_tool;
4872 for (const auto &layer : m_plan) {
4873 if (layer.tool_changes.empty()){
4874 filament_counts[current_tool]++;
4875 category_counts[get_filament_category(current_tool)]++;
4876 continue;
4877 }
4878 std::unordered_set<int> used_tools;
4879 std::unordered_set<int> used_category;
4880 for (size_t i = 0; i < layer.tool_changes.size(); ++i) {
4881 if (i == 0) {
4882 filament_counts[layer.tool_changes[i].old_tool]++;
4883 category_counts[get_filament_category(layer.tool_changes[i].old_tool)]++;
4884 used_tools.insert(layer.tool_changes[i].old_tool);
4885 used_category.insert(get_filament_category(layer.tool_changes[i].old_tool));
4886 }
4887 if (!used_category.count(get_filament_category(layer.tool_changes[i].new_tool)))
4888 category_counts[get_filament_category(layer.tool_changes[i].new_tool)]++;
4889 if (!used_tools.count(layer.tool_changes[i].new_tool))
4890 filament_counts[layer.tool_changes[i].new_tool]++;
4891 used_tools.insert(layer.tool_changes[i].new_tool);
4892 used_category.insert(get_filament_category(layer.tool_changes[i].new_tool));
4893 }
4894 current_tool = layer.tool_changes.empty()?current_tool:layer.tool_changes.back().new_tool;
4895 }
4896
4897 // std::vector<std::pair<int, int>> category_counts_vec;
4898 int selected_category = -1;
4899 int selected_count = 0;
4900
4901 for (auto iter = category_counts.begin(); iter != category_counts.end(); ++iter) {
4902 if (iter->second > selected_count) {
4903 selected_category = iter->first;
4904 selected_count = iter->second;
4905 }
4906 }
4907
4908 // std::sort(category_counts_vec.begin(), category_counts_vec.end(), [](const std::pair<int, int> &left, const std::pair<int, int>& right) {
4909 // return left.second > right.second;
4910 // });
4911
4912 int filament_id = -1;
4913 int filament_count = 0;
4914 for (auto iter = filament_counts.begin(); iter != filament_counts.end(); ++iter) {
4915 if (get_filament_category(iter->first) == selected_category && iter->second > filament_count) {
4916 filament_id = iter->first;
4917 filament_count = iter->second;
4918 }
4919 }
4920 return filament_id;
4921}

References get_filament_category(), m_current_tool, and m_plan.

Referenced by generate_new().

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

◆ get_wall_skip_points()

void Slic3r::WipeTower::get_wall_skip_points ( const WipeTowerInfo & layer,
int layer_id )
private
3411{
3412 const int pre_access_layer = 4;
3413 std::unordered_map<int, float> cur_block_depth;
3414 for (int i = 0; i < int(layer.tool_changes.size()); ++i) {
3415 const WipeTowerInfo::ToolChange &tool_change = layer.tool_changes[i];
3416 size_t old_filament = tool_change.old_tool;
3417 size_t new_filament = tool_change.new_tool;
3418 float nozzle_change_depth = tool_change.nozzle_change_depth;
3419 float wipe_depth = tool_change.required_depth - nozzle_change_depth;
3420 if (!is_valid_last_layer(old_filament, layer_id, m_plan[layer_id].z)) nozzle_change_depth = 0.f;
3421 auto *block = get_block_by_category(m_filpar[new_filament].category, false);
3422 if (!block) continue;
3423 float process_depth = 0.f;
3424 if (!cur_block_depth.count(m_filpar[new_filament].category)) cur_block_depth[m_filpar[new_filament].category] = block->start_depth;
3425 process_depth = cur_block_depth[m_filpar[new_filament].category];
3426 if (is_need_ramming(new_filament, old_filament, layer_id)) {
3427 if (get_filament_category(new_filament) == get_filament_category(old_filament))
3428 process_depth += nozzle_change_depth;
3429 else {
3430 if (!cur_block_depth.count(m_filpar[old_filament].category)) {
3431 auto *old_block = get_block_by_category(m_filpar[old_filament].category, false);
3432 if (!old_block) continue;
3433 cur_block_depth[m_filpar[old_filament].category] = old_block->start_depth;
3434 }
3435 cur_block_depth[m_filpar[old_filament].category] += nozzle_change_depth;
3436 }
3437 }
3438
3439 float infill_gap_width = get_block_gap_width(new_filament, false);
3440 Vec2f res;
3441 int index = layer_id % 4;
3442 switch (index % 4) {
3443 case 0: res = Vec2f(0, process_depth); break;
3444 case 1: res = Vec2f(m_wipe_tower_width, process_depth + wipe_depth - m_plan[layer_id].extra_spacing * infill_gap_width); break;
3445 case 2: res = Vec2f(m_wipe_tower_width, process_depth); break;
3446 case 3: res = Vec2f(0, process_depth + wipe_depth - m_plan[layer_id].extra_spacing * infill_gap_width); break;
3447 default: break;
3448 }
3449
3450 m_wall_skip_points[layer_id].emplace_back(res);
3451
3452 cur_block_depth[m_filpar[new_filament].category] = process_depth + wipe_depth;
3453
3454 bool solid_toolchange = block->layers_type[layer_id] == WipeTowerLayerType::Contact;
3455 if (solid_toolchange && m_enable_tower_interface_features) {
3456 for (int j = 0; j < pre_access_layer; j++) {
3457 int pre_layer_id = layer_id - j;
3458 if (pre_layer_id < 0) break;
3459 m_wall_skip_points[pre_layer_id].push_back(res);
3460 }
3461 }
3462 }
3464 for (auto &block : m_wipe_tower_blocks) {
3465 float block_depth = cur_block_depth.count(block.filament_adhesiveness_category) ? cur_block_depth[block.filament_adhesiveness_category] : block.start_depth;
3466 if (block_depth + EPSILON >= block.start_depth + block.layer_depths[layer_id] - m_perimeter_width) { continue; }
3467 bool block_solid = block.layers_type[layer_id] == WipeTowerLayerType::Contact;
3468 bool add_skip_point = block_solid && std::abs(block_depth - block.start_depth) < EPSILON;
3469 if (add_skip_point) {
3470 Vec2f res;
3471 int index = layer_id % 4;
3472
3473 float dy_skip = block.layer_depths[layer_id] - m_perimeter_width;
3474 int n_skip = (int) ((dy_skip + 0.25f * m_perimeter_width) / m_perimeter_width + 1);
3475 float gird_depth = m_perimeter_width * (n_skip - 1); // in sync with finish_block_solid
3476 switch (index % 4) {
3477 case 0: res = Vec2f(0, block_depth); break;
3478 case 1: res = Vec2f(m_wipe_tower_width, block_depth + gird_depth); break;
3479 case 2: res = Vec2f(m_wipe_tower_width, block_depth); break;
3480 case 3: res = Vec2f(0, block_depth + gird_depth); break;
3481 default: break;
3482 }
3483 m_wall_skip_points[layer_id].emplace_back(res);
3484 for (int j = 0; j < pre_access_layer; j++) {
3485 int pre_layer_id = layer_id - j;
3486 if (pre_layer_id < 0) break;
3487 m_wall_skip_points[pre_layer_id].push_back(res);
3488 }
3489 }
3490 }
3491 }
3492}

References Contact, EPSILON, get_block_by_category(), get_block_gap_width(), get_filament_category(), is_need_ramming(), is_valid_last_layer(), m_enable_tower_interface_features, m_filpar, m_perimeter_width, m_plan, m_wall_skip_points, m_wipe_tower_blocks, m_wipe_tower_width, tool_change(), and Slic3r::WipeTower::WipeTowerInfo::tool_changes.

Referenced by get_all_wall_skip_points().

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

◆ get_wrapping_detection_depth()

float Slic3r::WipeTower::get_wrapping_detection_depth ( )
static
1750{
1751 return float(wrapping_wipe_tower_depth);
1752}
const double wrapping_wipe_tower_depth
Definition WipeTower.cpp:1690

References Slic3r::wrapping_wipe_tower_depth.

Referenced by Slic3r::estimate_wipe_tower_footprint().

Here is the caller graph for this function:

◆ has_tpu_filament()

bool Slic3r::WipeTower::has_tpu_filament ( ) const
inline
367{ return m_has_tpu_filament; }
bool m_has_tpu_filament
Definition WipeTower.hpp:518

References m_has_tpu_filament.

◆ is_first_layer()

bool Slic3r::WipeTower::is_first_layer ( ) const
inlineprivate
594{ 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_block(), finish_block_solid(), finish_layer_new(), only_generate_out_wall(), ramming(), set_layer(), tool_change(), tool_change_new(), toolchange_Unload(), toolchange_Wipe(), and toolchange_wipe_new().

Here is the caller graph for this function:

◆ is_need_ramming()

bool Slic3r::WipeTower::is_need_ramming ( int filament_id_1,
int filament_id_2,
int layer_id ) const
5543{
5544 return !m_multi_nozzle_group_result->are_filaments_same_nozzle(filament_id_1, filament_id_2, layer_id);
5545}

References m_multi_nozzle_group_result.

Referenced by calc_block_infill_gap(), generate_wipe_tower_blocks(), get_wall_skip_points(), plan_toolchange(), set_toolchange(), and tool_change_new().

Here is the caller graph for this function:

◆ is_need_reverse_travel()

bool Slic3r::WipeTower::is_need_reverse_travel ( int filament,
bool extruder_change ) const
private
3335{
3336 if (extruder_change)
3337 return m_filpar[filament_id].ramming_travel_time.first > EPSILON && at_or_front(m_filaments_change_length.first, filament_id) > EPSILON;
3338 return m_filpar[filament_id].ramming_travel_time.second > EPSILON && at_or_front(m_filaments_change_length.second, filament_id) > EPSILON;
3339}
static T at_or_front(const std::vector< T > &v, size_t i)
Definition WipeTower.cpp:135

References Slic3r::at_or_front(), EPSILON, m_filaments_change_length, and m_filpar.

Referenced by calc_block_infill_gap(), ramming(), and tool_change_new().

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

◆ is_petg_filament()

bool Slic3r::WipeTower::is_petg_filament ( int filament_id) const
private
3330{
3331 return m_filpar[filament_id].material == "PETG";
3332}

References m_filpar.

Referenced by get_next_pos().

Here is the caller graph for this function:

◆ is_same_extruder()

bool Slic3r::WipeTower::is_same_extruder ( int filament_id_1,
int filament_id_2,
int layer_id ) const
5547{
5548 return m_multi_nozzle_group_result->are_filaments_same_extruder(filament_id_1, filament_id_2, layer_id);
5549}

References m_multi_nozzle_group_result.

Referenced by calc_block_infill_gap(), plan_toolchange(), set_toolchange(), and tool_change_new().

Here is the caller graph for this function:

◆ is_same_nozzle()

bool Slic3r::WipeTower::is_same_nozzle ( int filament_id_1,
int filament_id_2,
int layer_id ) const
5552{
5553 return m_multi_nozzle_group_result->are_filaments_same_nozzle(filament_id_1, filament_id_2, layer_id);
5554}

References m_multi_nozzle_group_result.

Referenced by plan_toolchange().

Here is the caller graph for this function:

◆ is_tpu_filament()

bool Slic3r::WipeTower::is_tpu_filament ( int filament_id) const
private
3325{
3326 return m_filpar[filament_id].material == "TPU";
3327}

References m_filpar.

Referenced by tool_change().

Here is the caller graph for this function:

◆ is_valid_last_layer()

bool Slic3r::WipeTower::is_valid_last_layer ( int tool,
int layer_id,
double layer_z ) const
private
5524{
5525 int extruder_id = get_extruder_id(tool, layer_id);
5526 if (extruder_id < 0 || extruder_id >= m_printable_height.size()) return true;
5527 if (m_last_layer_id[extruder_id] == layer_id && layer_z > m_printable_height[extruder_id]) return false;
5528 return true;
5529}

References get_extruder_id(), m_last_layer_id, and m_printable_height.

Referenced by generate_new(), get_wall_skip_points(), and tool_change_new().

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

◆ its_make_rib_brim()

TriangleMesh Slic3r::WipeTower::its_make_rib_brim ( const Polygon & brim,
float layer_height )
static
1950 {
1951 TriangleMesh res;
1952 if (brim.area() < scaled(EPSILON))return res;
1953 int offset = brim.size();
1954 res.its.vertices.reserve(brim.size() * 2);
1955 auto faces= Triangulation::triangulate(brim);
1956 res.its.indices.reserve(brim.size() * 2 + 2 * faces.size());
1957 for (auto &t : faces) res.its.indices.push_back({t[1], t[0], t[2]});
1958 for (auto &t : faces) res.its.indices.push_back({t[0] + offset, t[1] + offset, t[2] + offset});
1959
1960 for (int i = 0; i < brim.size(); i++) res.its.vertices.push_back({unscaled<float>(brim[i][0]), unscaled<float>(brim[i][1]), 0});
1961 for (int i = 0; i < brim.size(); i++) res.its.vertices.push_back({unscaled<float>(brim[i][0]), unscaled<float>(brim[i][1]), layer_height});
1962
1963 for (int i = 0; i < offset; i++) {
1964 int a = i;
1965 int b = (i + 1) % offset;
1966 int c = i + offset;
1967 int d = b + offset;
1968 res.its.indices.push_back({a, b, c});
1969 res.its.indices.push_back({d, c, b});
1970 }
1971 return res;
1972}
static Indices triangulate(const Points &points, const HalfEdges &half_edges)
Connect points by triangulation to create filled surface by triangles Input points have to be unique ...
Definition Triangulation.cpp:103

References Slic3r::Polygon::area(), EPSILON, Slic3r::TriangleMesh::its, Slic3r::layer_height(), Slic3r::offset(), Slic3r::scaled(), Slic3r::MultiPoint::size(), and Slic3r::Triangulation::triangulate().

Referenced by Slic3r::WipeTowerData::construct_mesh(), and Slic3r::GLVolumeCollection::load_wipe_tower_preview().

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

◆ its_make_rib_tower()

TriangleMesh Slic3r::WipeTower::its_make_rib_tower ( float width,
float depth,
float height,
float rib_length,
float rib_width,
bool fillet_wall )
static
1921{
1922 TriangleMesh res;
1923 Polygon bottom = rib_section(width, depth, rib_length, rib_width, fillet_wall);
1924 Polygon top = rib_section(width, depth, std::sqrt(width * width + depth * depth), rib_width, fillet_wall);
1925 if (fillet_wall)
1926 assert(bottom.points.size() == top.points.size());
1927 int offset = bottom.points.size();
1928 res.its.vertices.reserve(offset * 2);
1929 if (bottom.area() < scaled(EPSILON) || top.area() < scaled(EPSILON) || bottom.points.size() != top.points.size()) return res;
1930 auto faces_bottom = Triangulation::triangulate(bottom);
1931 auto faces_top = Triangulation::triangulate(top);
1932 res.its.indices.reserve(offset * 2 + faces_bottom.size() + faces_top.size());
1933 for (auto &t : faces_bottom) res.its.indices.push_back({t[1], t[0], t[2]});
1934 for (auto &t : faces_top) res.its.indices.push_back({t[0] + offset, t[1] + offset, t[2] + offset});
1935
1936 for (int i = 0; i < bottom.size(); i++) res.its.vertices.push_back({unscaled<float>(bottom[i][0]), unscaled<float>(bottom[i][1]), 0});
1937 for (int i = 0; i < top.size(); i++) res.its.vertices.push_back({unscaled<float>(top[i][0]), unscaled<float>(top[i][1]), height});
1938
1939 for (int i = 0; i < offset; i++) {
1940 int a = i;
1941 int b = (i + 1) % offset;
1942 int c = i + offset;
1943 int d = b + offset;
1944 res.its.indices.push_back({a, b, c});
1945 res.its.indices.push_back({d, c, b});
1946 }
1947 return res;
1948}
PointType size() const
Definition BoundingBox.cpp:178
double area() const
Definition BoundingBox.hpp:45
static Polygon rib_section(float width, float depth, float rib_length, float rib_width, bool fillet_wall)
Definition WipeTower.cpp:1878

References Slic3r::Polygon::area(), EPSILON, Slic3r::TriangleMesh::its, Slic3r::offset(), Slic3r::MultiPoint::points, rib_section(), Slic3r::scaled(), Slic3r::MultiPoint::size(), Slic3r::Triangulation::triangulate(), and width().

Referenced by Slic3r::WipeTowerData::construct_mesh().

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

◆ layer_finished()

bool Slic3r::WipeTower::layer_finished ( ) const
inline
358 {
360 }

References m_current_layer_finished.

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

Here is the caller graph for this function:

◆ layer_is_printed()

bool Slic3r::WipeTower::layer_is_printed ( bool toolchanges_on_layer) const
private
4770{
4771 if (m_layer_info != m_plan.end() && m_layer_info->combined_away)
4772 return false;
4773 return ! m_sparse_layers_skipped || toolchanges_on_layer;
4774}

References m_layer_info, m_plan, and m_sparse_layers_skipped.

Referenced by finish_block(), finish_block_solid(), finish_layer_new(), and only_generate_out_wall().

Here is the caller graph for this function:

◆ length_to_volume()

float Slic3r::WipeTower::length_to_volume ( float length,
float line_width,
float layer_height ) const
inlineprivate
607 {
608 return std::max(0.f, length * (layer_height * (line_width - layer_height * (1.f - float(M_PI) / 4.f))));
609 }
double length(const Points &pts)
Definition MultiPoint.hpp:181

References Slic3r::layer_height(), Slic3r::length(), and M_PI.

Referenced by plan_tower_new().

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

◆ make_wipe_tower_square()

void Slic3r::WipeTower::make_wipe_tower_square ( )
private

◆ merge_tcr()

WipeTower::ToolChangeResult Slic3r::WipeTower::merge_tcr ( ToolChangeResult & first,
ToolChangeResult & second )
private
3354{
3355 assert(first.new_tool == second.initial_tool);
3356 WipeTower::ToolChangeResult out = first;
3357 if ((first.end_pos - second.start_pos).norm() > (float)EPSILON) {
3358 std::string travel_gcode = "G1 X" + Slic3r::float_to_string_decimal_point(second.start_pos.x(), 3) + " Y" +
3360 bool need_insert_travel = true;
3361 if (second.is_tool_change
3362 && is_approx(second.start_pos.x(), second.tool_change_start_pos.x())
3363 && is_approx(second.start_pos.y(), second.tool_change_start_pos.y())) {
3364 // will insert travel in gcode.cpp
3365 need_insert_travel = false;
3366 }
3367
3368 if (need_insert_travel)
3369 out.gcode += travel_gcode;
3370 }
3371 out.gcode += second.gcode;
3372 out.extrusions.insert(out.extrusions.end(), second.extrusions.begin(), second.extrusions.end());
3373 out.end_pos = second.end_pos;
3374 out.wipe_path = second.wipe_path;
3375 out.initial_tool = first.initial_tool;
3376 out.new_tool = second.new_tool;
3377 out.is_contact = first.is_contact || second.is_contact;
3378 if (!first.nozzle_change_result.gcode.empty())
3379 out.nozzle_change_result = first.nozzle_change_result;
3380 else if (!second.nozzle_change_result.gcode.empty())
3381 out.nozzle_change_result = second.nozzle_change_result;
3382
3383 if (first.is_tool_change) {
3384 out.is_tool_change = true;
3385 out.tool_change_start_pos = first.tool_change_start_pos;
3386 }
3387 else if (second.is_tool_change) {
3388 out.is_tool_change = true;
3389 out.tool_change_start_pos = second.tool_change_start_pos;
3390 }
3391 else {
3392 out.is_tool_change = false;
3393 }
3394
3395 // BBS
3396 out.purge_volume += second.purge_volume;
3397 return out;
3398}
constexpr bool is_approx(Number value, Number test_value, Number precision=EPSILON)
Definition libslic3r.h:320
std::string float_to_string_decimal_point(double value, int precision)
Definition LocalesUtils.cpp:108

References Slic3r::WipeTower::ToolChangeResult::end_pos, EPSILON, Slic3r::WipeTower::ToolChangeResult::extrusions, Slic3r::float_to_string_decimal_point(), Slic3r::WipeTower::NozzleChangeResult::gcode, Slic3r::WipeTower::ToolChangeResult::gcode, Slic3r::WipeTower::ToolChangeResult::initial_tool, Slic3r::is_approx(), Slic3r::WipeTower::ToolChangeResult::is_contact, Slic3r::WipeTower::ToolChangeResult::is_tool_change, m_max_speed, Slic3r::WipeTower::ToolChangeResult::new_tool, Slic3r::WipeTower::ToolChangeResult::nozzle_change_result, Slic3r::WipeTower::ToolChangeResult::purge_volume, Slic3r::WipeTower::ToolChangeResult::start_pos, Slic3r::WipeTower::ToolChangeResult::tool_change_start_pos, and Slic3r::WipeTower::ToolChangeResult::wipe_path.

Referenced by generate_new().

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

◆ move_box_inside_polygon()

Vec2f Slic3r::WipeTower::move_box_inside_polygon ( const BoundingBox & box,
const Polygons & polygons,
coord_t offset = 0 )
static
1827{
1828 if (polygons.empty()) return Vec2f{0.f, 0.f};
1829
1830 const BoundingBox bed = get_extents(polygons);
1831 // No position fits the footprint.
1832 if (box.size().x() >= bed.size().x() - 2 * offset || box.size().y() >= bed.size().y() - 2 * offset)
1833 return Vec2f{0.f, 0.f};
1834
1835 // Clamp against the bounding box first, moving only along the axis that is violated so a dragged
1836 // prime tower slides along the bed edge instead of jumping inwards.
1837 Point shift(0, 0);
1838 for (int axis = 0; axis < 2; ++axis) {
1839 if (box.max[axis] > bed.max[axis] - offset)
1840 shift[axis] = (bed.max[axis] - offset) - box.max[axis];
1841 else if (box.min[axis] < bed.min[axis] + offset)
1842 shift[axis] = (bed.min[axis] + offset) - box.min[axis];
1843 }
1844
1845 // A bed that fills its own bounding box is fully clamped by that, so every rectangular bed — all
1846 // but the delta-style profiles — stops here and keeps its historic placement, including when a
1847 // negative margin lets the footprint hang over the edge. The tolerance is relative because an
1848 // exact rectangle loses a few ulps once the areas are squared world coordinates.
1849 double area = 0.;
1850 for (const Polygon &poly : polygons) area += std::abs(poly.area());
1851 const double bed_area = double(bed.size().x()) * double(bed.size().y());
1852 if (area >= bed_area * (1. - EPSILON)) return unscaled<float>(shift);
1853
1854 // Clamp a negative margin (an auto brim width that has not been resolved yet) to zero: padding by
1855 // it would shrink the footprint and hand back a position the validation still rejects. The
1856 // epsilon lets the move's round trip through millimeters land on the outline without counting as
1857 // a violation.
1858 BoundingBox padded = box.inflated(std::max<coord_t>(offset, 0) - SCALED_EPSILON);
1859 padded.translate(shift);
1860 auto fits = [&padded, &polygons](const Point &move) {
1861 BoundingBox moved = padded;
1862 moved.translate(move);
1863 return diff(Polygons{moved.polygon()}, polygons).empty();
1864 };
1865 if (fits(Point(0, 0))) return unscaled<float>(shift);
1866
1867 // Walk towards the middle of the bed. On every non-rectangular bed we ship, the fitting positions
1868 // form a convex region around it, so bisecting stops just inside the outline.
1869 Point lo(0, 0), hi = bed.center() - padded.center();
1870 if (!fits(hi)) return unscaled<float>(shift);
1871 for (int i = 0; i < 12; ++i) {
1872 const Point mid = (lo + hi) / 2;
1873 if (fits(mid)) hi = mid; else lo = mid;
1874 }
1875 return unscaled<float>(Point(shift + hi));
1876}
#define SCALED_EPSILON
Definition libslic3r.h:109
double area(const ExPolygon &poly)
Definition ExPolygon.hpp:511
bool empty(const BoundingBoxBase< PointType, PointsType > &bb)
Definition BoundingBox.hpp:273
Slic3r::Polygons diff(const Slic3r::Polygon &subject, const Slic3r::Polygon &clip, ApplySafetyOffset do_safety_offset)
Definition ClipperUtils.cpp:731

References Slic3r::area(), Slic3r::BoundingBoxBase< PointType, APointsType >::center(), Slic3r::diff(), Slic3r::empty(), EPSILON, Slic3r::get_extents(), Slic3r::BoundingBox::inflated(), Slic3r::BoundingBoxBase< PointType, APointsType >::max, Slic3r::BoundingBoxBase< PointType, APointsType >::min, Slic3r::offset(), Slic3r::BoundingBox::polygon(), SCALED_EPSILON, Slic3r::BoundingBoxBase< PointType, APointsType >::size(), Slic3r::BoundingBoxBase< PointType, APointsType >::translate(), and Slic3r::unscaled().

Referenced by anonymous_namespace{OrcaSlicer_profile_validator.cpp}::place_wipe_tower(), Slic3r::GUI::PartPlateList::set_default_wipe_tower_pos_for_plate(), and Slic3r::GUI::Selection::translate().

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

◆ need_thick_bridge_flow()

bool Slic3r::WipeTower::need_thick_bridge_flow ( float pos_y) const
5512 {
5513 if (m_layer_height >= 0.2)
5514 return false;
5515
5516 float y_min = 0., y_max = 0.;
5517 if (get_floating_area(y_min, y_max)) {
5518 return pos_y > y_min && pos_y < y_max;
5519 }
5520 return false;
5521}
bool get_floating_area(float &start_pos_y, float &end_pos_y) const
Definition WipeTower.cpp:5490

References get_floating_area(), and m_layer_height.

Referenced by Slic3r::WipeTowerWriter::line(), ramming(), Slic3r::WipeTowerWriter::rectangle_fill_box(), toolchange_Wipe(), and toolchange_wipe_new().

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

◆ never_skip_tag()

const std::string Slic3r::WipeTower::never_skip_tag ( )
inlinestatic
46{ return "_GCODE_WIPE_TOWER_NEVER_SKIP_TAG"; }

Referenced by Slic3r::WipeTowerIntegration::post_process_wipe_tower_moves(), toolchange_Change(), and Slic3r::transform_gcode().

Here is the caller graph for this function:

◆ nozzle_change()

NozzleChangeResult Slic3r::WipeTower::nozzle_change ( int old_filament_id,
int new_filament_id )

◆ nozzle_change_extrusion_flow()

float Slic3r::WipeTower::nozzle_change_extrusion_flow ( float layer_height = -1.f) const
inline
347 {
348 if (layer_height < 0)
349 return m_extrusion_flow;
350 return layer_height * (m_nozzle_change_perimeter_width - layer_height * (1.f - float(M_PI) / 4.f)) / filament_area();
351 }

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

Referenced by plan_toolchange(), ramming(), and set_toolchange().

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

◆ nozzle_change_perimeter_width()

float Slic3r::WipeTower::nozzle_change_perimeter_width ( float nozzle_diameter)
static
1755{
1757 return it != nozzle_diameter_to_nozzle_change_width.end() ? it->second : 2.f * nozzle_diameter * 1.25f;
1758}
static const std::map< float, float > nozzle_diameter_to_nozzle_change_width
Definition WipeTower.cpp:51

References Slic3r::nozzle_diameter(), and Slic3r::nozzle_diameter_to_nozzle_change_width.

Referenced by estimate_tower_blocks_depth().

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

◆ only_generate_out_wall()

WipeTower::ToolChangeResult Slic3r::WipeTower::only_generate_out_wall ( bool is_new_mode = false)
5243{
5244 size_t old_tool = m_current_tool;
5245
5247 writer.set_extrusion_flow(m_extrusion_flow)
5248 .set_z(m_z_pos)
5249 .set_initial_tool(m_current_tool)
5250 .set_y_shift(m_y_shift - (m_current_shape == SHAPE_REVERSED ? m_layer_info->toolchanges_depth() : 0.f));
5251
5253
5254 // Slow down on the 1st layer.
5255 bool first_layer = is_first_layer();
5256 // BBS: speed up perimeter speed to 90mm/s for non-first layer
5257 float feedrate = first_layer ? std::min(m_first_layer_speed * 60.f, m_max_speed) : std::min(60.0f * m_filpar[m_current_tool].max_e_speed / m_extrusion_flow, m_max_speed);
5258 float fill_box_y = m_layer_info->toolchanges_depth() + m_perimeter_width;
5259 box_coordinates fill_box(Vec2f(m_perimeter_width, fill_box_y), m_wipe_tower_width - 2 * m_perimeter_width, m_layer_info->depth - fill_box_y);
5260
5261 writer.set_initial_position((m_left_to_right ? fill_box.ru : fill_box.lu), // so there is never a diagonal travel
5263
5264 bool toolchanges_on_layer = m_layer_info->toolchanges_depth() > WT_EPSILON;
5265
5266 // we are in one of the corners, travel to ld along the perimeter:
5267 // BBS: Delete some unnecessary travel
5268 //if (writer.x() > fill_box.ld.x() + EPSILON) writer.travel(fill_box.ld.x(), writer.y());
5269 //if (writer.y() > fill_box.ld.y() + EPSILON) writer.travel(writer.x(), fill_box.ld.y());
5271 // outer perimeter (always):
5272 // BBS
5273
5274 float wipe_tower_depth = m_layer_info->depth + m_perimeter_width;
5276 wipe_tower_depth = m_wipe_tower_depth;
5277 box_coordinates wt_box(Vec2f(0.f, (m_current_shape == SHAPE_REVERSED ? m_layer_info->toolchanges_depth() : 0.f)), m_wipe_tower_width, wipe_tower_depth);
5278 wt_box = align_perimeter(wt_box);
5279 Polygon outer_wall;
5280 //if (m_use_gap_wall)
5281 // generate_support_wall(writer, wt_box, feedrate, first_layer);
5282 //else
5283 // writer.rectangle(wt_box, feedrate);
5284 outer_wall = generate_support_wall_new(writer, wt_box, feedrate, first_layer, m_use_rib_wall, true, m_use_gap_wall);
5285 m_outer_wall[m_z_pos].push_back(to_polyline(outer_wall));
5286 // Now prepare future wipe. box contains rectangle that was extruded last (ccw).
5287
5288 // Vec2f target = (writer.pos() == wt_box.ld ? wt_box.rd : (writer.pos() == wt_box.rd ? wt_box.ru : (writer.pos() == wt_box.ru ? wt_box.lu : wt_box.ld)));
5289 //writer.add_wipe_point(writer.pos()).add_wipe_point(target);
5290
5291 writer.add_wipe_path(outer_wall, m_filpar[m_current_tool].wipe_dist);
5293
5294 // Ask our writer about how much material was consumed.
5295 // Skip this in case the layer is sparse and config option to not print sparse layers is enabled.
5296 if (layer_is_printed(toolchanges_on_layer))
5297 if (m_current_tool < m_used_filament_length.size()) m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length();
5298
5299 return construct_tcr(writer, false, old_tool, true, false, 0.f, false);
5300}

References Slic3r::WipeTowerWriter::add_wipe_path(), align_perimeter(), Slic3r::WipeTowerWriter::append(), construct_tcr(), generate_support_wall_new(), Slic3r::WipeTowerWriter::get_and_reset_used_filament_length(), is_first_layer(), layer_is_printed(), Slic3r::WipeTower::box_coordinates::lu, m_current_shape, m_current_tool, m_enable_arc_fitting, m_enable_timelapse_print, m_enable_wrapping_detection, m_extrusion_flow, m_filpar, m_first_layer_speed, m_gcode_flavor, m_internal_rotation, m_layer_height, m_layer_info, m_left_to_right, m_max_speed, m_outer_wall, m_perimeter_width, m_use_gap_wall, m_use_rib_wall, m_used_filament_length, m_wipe_tower_depth, m_wipe_tower_width, m_y_shift, m_z_pos, Slic3r::GCodeProcessor::reserved_tag(), Slic3r::WipeTower::box_coordinates::ru, Slic3r::WipeTowerWriter::set_extrusion_flow(), set_for_wipe_tower_writer(), Slic3r::WipeTowerWriter::set_initial_position(), Slic3r::WipeTowerWriter::set_initial_tool(), Slic3r::WipeTowerWriter::set_y_shift(), Slic3r::WipeTowerWriter::set_z(), SHAPE_REVERSED, Slic3r::to_polyline(), Slic3r::GCodeProcessor::Wipe_Tower_End, Slic3r::GCodeProcessor::Wipe_Tower_Start, WipeTowerWriter, and WT_EPSILON.

Referenced by generate_new().

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

◆ plan_toolchange()

void Slic3r::WipeTower::plan_toolchange ( float z_par,
float layer_height_par,
unsigned int old_tool,
unsigned int new_tool,
float wipe_volume_ec = 0.f,
float wipe_volume_nc = 0.f,
float prime_volume = 0.f )
3133{
3134 assert(m_plan.empty() || m_plan.back().z <= z_par + WT_EPSILON); // refuses to add a layer below the last one
3135
3136 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
3137 m_plan.push_back(WipeTowerInfo(z_par, layer_height_par));
3138
3139 if (m_first_layer_idx == size_t(-1) && (! m_sparse_layers_skipped || old_tool != new_tool))
3140 m_first_layer_idx = m_plan.size() - 1;
3141
3142 if (old_tool == new_tool) // new layer without toolchanges - we are done
3143 return;
3144
3145 // this is an actual toolchange - let's calculate depth to reserve on the wipe tower
3146 float depth = 0.f;
3148
3149 // BBS: if the wipe tower width is too small, the depth will be infinity
3150 if (width <= EPSILON)
3151 return;
3152 int layer_id = static_cast<int>(m_plan.size()) - 1;
3153 float wipe_volume = is_same_extruder(old_tool, new_tool, layer_id) && !is_same_nozzle(old_tool, new_tool, layer_id) ? wipe_volume_nc : wipe_volume_ec;
3154 // BBS: remove old filament ramming and first line
3155#if 0
3156 float length_to_extrude = volume_to_length(0.25f * std::accumulate(m_filpar[old_tool].ramming_speed.begin(), m_filpar[old_tool].ramming_speed.end(), 0.f),
3157 m_perimeter_width * m_filpar[old_tool].ramming_line_width_multiplicator,
3158 layer_height_par);
3159 depth = (int(length_to_extrude / width) + 1) * (m_perimeter_width * m_filpar[old_tool].ramming_line_width_multiplicator * m_filpar[old_tool].ramming_step_multiplicator);
3160 float ramming_depth = depth;
3161 length_to_extrude = width*((length_to_extrude / width)-int(length_to_extrude / width)) - width;
3162 float first_wipe_line = -length_to_extrude;
3163 length_to_extrude += volume_to_length(wipe_volume, m_perimeter_width, layer_height_par);
3164 length_to_extrude = std::max(length_to_extrude,0.f);
3165
3166 depth += (int(length_to_extrude / width) + 1) * m_perimeter_width;
3167 depth *= m_extra_spacing;
3168
3169 m_plan.back().tool_changes.push_back(WipeTowerInfo::ToolChange(old_tool, new_tool, depth, ramming_depth, first_wipe_line, wipe_volume));
3170#else
3171 float length_to_extrude = volume_to_length(wipe_volume, m_perimeter_width, layer_height_par);
3172
3173 depth += std::ceil(length_to_extrude / width) * m_perimeter_width;
3174 //depth *= m_extra_spacing;
3175 float filament_change_length = !is_same_extruder(old_tool, new_tool, layer_id) ? at_or_front(m_filaments_change_length.first, old_tool) : at_or_front(m_filaments_change_length.second, old_tool);
3176 float nozzle_change_depth = 0;
3177 float nozzle_change_length = 0;
3178 if (is_need_ramming(old_tool, new_tool, layer_id)) {
3179 double e_flow = nozzle_change_extrusion_flow(layer_height_par);
3180 double length = filament_change_length / e_flow;
3181 int nozzle_change_line_count = std::ceil(length / (m_wipe_tower_width - 2*m_nozzle_change_perimeter_width));
3182 nozzle_change_depth = nozzle_change_line_count * m_nozzle_change_perimeter_width;
3183 depth += nozzle_change_depth;
3184 nozzle_change_length = length;
3185 }
3186 WipeTowerInfo::ToolChange tool_change = WipeTowerInfo::ToolChange(old_tool, new_tool, depth, 0.f, 0.f, wipe_volume, length_to_extrude, purge_volume);
3187 tool_change.nozzle_change_depth = nozzle_change_depth;
3188 tool_change.nozzle_change_length = nozzle_change_length;
3189 m_plan.back().tool_changes.push_back(tool_change);
3190#endif
3191}
bool is_same_nozzle(int filament_id_1, int filament_id_2, int layer_id) const
Definition WipeTower.cpp:5551
float nozzle_change_extrusion_flow(float layer_height=-1.f) const
Definition WipeTower.hpp:346
float volume_to_length(float volume, float line_width, float layer_height) const
Definition WipeTower.hpp:602

References Slic3r::at_or_front(), EPSILON, is_need_ramming(), is_same_extruder(), is_same_nozzle(), Slic3r::length(), m_extra_spacing, m_filaments_change_length, m_filpar, m_first_layer_idx, m_nozzle_change_perimeter_width, m_perimeter_width, m_plan, m_sparse_layers_skipped, m_wipe_tower_width, nozzle_change_extrusion_flow(), tool_change(), volume_to_length(), width(), 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::WipeTower::plan_tower ( )
private

◆ plan_tower_new()

void Slic3r::WipeTower::plan_tower_new ( )
4777{
4780 if (m_use_rib_wall) {
4781 // recalculate wipe_tower_with and layer's depth
4783 float max_depth = std::accumulate(m_wipe_tower_blocks.begin(), m_wipe_tower_blocks.end(), 0.f, [](float a, const auto &t) { return a + t.depth; }) + m_perimeter_width;
4784 float square_width = align_ceil(std::sqrt(max_depth * m_wipe_tower_width * m_extra_spacing), m_perimeter_width);
4785 m_wipe_tower_width = square_width;
4786 for (int idx = 0; idx < m_plan.size(); idx++) {
4787 for (auto &toolchange : m_plan[idx].tool_changes) {
4788 toolchange = set_toolchange(toolchange.old_tool, toolchange.new_tool, m_plan[idx].height, toolchange.wipe_volume, toolchange.purge_volume,idx);
4789 }
4790 }
4791 }
4792
4794
4795 float max_depth = 0.f;
4796 for (const auto &block : m_wipe_tower_blocks) {
4797 max_depth += block.depth;
4798 }
4799 //std::cout << " after square " << m_wipe_tower_width << " depth " << max_depth << std::endl;
4800
4801 float min_wipe_tower_depth = get_limit_depth_by_height(m_wipe_tower_height);
4802
4803 // only for get m_extra_spacing
4804 {
4805 if (m_enable_wrapping_detection && max_depth < EPSILON) {
4806 max_depth = wrapping_wipe_tower_depth;
4807 if (m_use_rib_wall) {
4808 m_wipe_tower_width = max_depth;
4809 }
4810 }
4811
4812 if (m_enable_timelapse_print && max_depth < EPSILON) {
4813 max_depth = min_wipe_tower_depth;
4814 if (m_use_rib_wall) { m_wipe_tower_width = max_depth; }
4815 }
4816
4817 if (max_depth + EPSILON < min_wipe_tower_depth) {
4818 //if enable rib_wall, there is no need to set extra_spacing
4819 if (m_use_rib_wall)
4820 m_rib_length = std::max(m_rib_length, min_wipe_tower_depth * (float) std::sqrt(2));
4821 else
4822 m_extra_spacing = std::max(min_wipe_tower_depth / max_depth, m_extra_spacing);
4823 }
4824
4825 for (int idx = 0; idx < m_plan.size(); idx++) {
4826 auto &info = m_plan[idx];
4827 if (idx == 0 /*&& m_extra_spacing > 1.f + EPSILON*/) {
4828 // apply solid fill for the first layer
4829 info.extra_spacing = 1.f;
4830 for (auto &toolchange : info.tool_changes) {
4831 //float x_to_wipe = volume_to_length(toolchange.wipe_volume, m_perimeter_width, info.height);
4832 float line_len = m_wipe_tower_width - 2 * m_perimeter_width;
4833 float wipe_depth = (toolchange.required_depth - toolchange.nozzle_change_depth) * m_extra_spacing;
4834 float wipe_line_count = wipe_depth / m_perimeter_width;
4835 float nozzle_change_depth = toolchange.nozzle_change_depth * m_extra_spacing;
4836
4837 int nozzle_change_line_count = (toolchange.nozzle_change_depth * m_extra_spacing + WT_EPSILON) / m_nozzle_change_perimeter_width;
4838
4839 toolchange.required_depth = wipe_depth + nozzle_change_depth;
4840 toolchange.wipe_length = wipe_line_count * line_len;
4841 toolchange.wipe_volume = length_to_volume(toolchange.wipe_length, m_perimeter_width, info.height);
4842 toolchange.nozzle_change_length = nozzle_change_line_count * (m_wipe_tower_width - (m_nozzle_change_perimeter_width + m_perimeter_width));
4843 toolchange.nozzle_change_depth = nozzle_change_depth;
4844 }
4845 } else {
4846 info.extra_spacing = m_extra_spacing;
4847 for (auto &toolchange : info.tool_changes) {
4848 toolchange.required_depth *= m_extra_spacing;
4849 toolchange.nozzle_change_depth *= m_extra_spacing;
4850 toolchange.wipe_length = volume_to_length(toolchange.wipe_volume, m_perimeter_width, info.height);
4851 }
4852 }
4853 }
4854 }
4855
4856 update_all_layer_depth(max_depth);
4860 m_rib_length = std::max({m_rib_length, diagonal});
4862 m_rib_length = std::max(diagonal, m_rib_length);
4863 m_rib_width = std::min(m_rib_width, std::min(m_wipe_tower_depth, m_wipe_tower_width) / 2.f); // Ensure that the rib wall of the wipetower are attached to the infill.
4864
4865}
void set_nozzle_last_layer_id()
Definition WipeTower.cpp:4491
void calc_block_infill_gap()
Definition WipeTower.cpp:4685
static float get_auto_brim_by_height(float max_height)
Definition WipeTower.cpp:1733
float length_to_volume(float length, float line_width, float layer_height) const
Definition WipeTower.hpp:606
void generate_wipe_tower_blocks(bool add_solid_flag)
Definition WipeTower.cpp:4558
void get_all_wall_skip_points()
Definition WipeTower.cpp:3400
void update_all_layer_depth(float wipe_tower_depth)
Definition WipeTower.cpp:4527

References Slic3r::align_ceil(), calc_block_infill_gap(), EPSILON, generate_wipe_tower_blocks(), get_all_wall_skip_points(), get_auto_brim_by_height(), get_limit_depth_by_height(), length_to_volume(), m_enable_timelapse_print, m_enable_wrapping_detection, m_extra_rib_length, m_extra_spacing, m_nozzle_change_perimeter_width, m_perimeter_width, m_plan, m_rib_length, m_rib_width, m_use_gap_wall, m_use_rib_wall, m_wipe_tower_blocks, m_wipe_tower_brim_width, m_wipe_tower_depth, m_wipe_tower_height, m_wipe_tower_width, set_nozzle_last_layer_id(), set_toolchange(), update_all_layer_depth(), volume_to_length(), Slic3r::wrapping_wipe_tower_depth, and WT_EPSILON.

Referenced by generate_new().

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

◆ position()

const Vec2f & Slic3r::WipeTower::position ( ) const
inline
313{ 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::WipeTower::prime ( float initial_layer_print_height,
const std::vector< unsigned int > & tools,
bool last_wipe_inside_wipe_tower )
2231{
2232 return std::vector<ToolChangeResult>();
2233}

References Slic3r::initial_layer_print_height().

Here is the call graph for this function:

◆ ramming()

WipeTower::NozzleChangeResult Slic3r::WipeTower::ramming ( int old_filament_id,
int new_filament_id,
bool solid_change = false,
bool extruder_change = true )
3619{
3620 auto format_line_M106 = []() { return std::string{"M106 S255\n"};};
3621 auto format_line_M633 = []() { return std::string{"M633\n"};};
3622 auto format_line_M632 = [](int filament_id, int nozzle_id) {
3623 std::string buffer = "M632 S" + std::to_string(filament_id);
3624 if (nozzle_id >= 0)
3625 buffer += " H" + std::to_string(nozzle_id);
3626 buffer += " M N\n";
3627 return buffer;
3628 };
3629
3630 int nozzle_change_line_count = 0;
3632 float nozzle_change_box_width = m_wipe_tower_width - 2 * x_offset;
3633 float nozzle_change_depth = 0.f;
3634 if (new_filament_id != (unsigned int) (-1)) {
3635 for (const auto &b : m_layer_info->tool_changes)
3636 if (b.new_tool == new_filament_id) {
3637 nozzle_change_line_count = std::ceil(b.nozzle_change_length / nozzle_change_box_width);
3638 nozzle_change_depth = b.nozzle_change_depth;
3639 break;
3640 }
3641 }
3642 auto format_nozzle_change_line = [this](bool start, int old_filament_id, int new_filament_id) -> std::string {
3643 char buff[64];
3644 // Orca: the nozzle-change markers are standalone tag constants, not ETags entries
3645 // (the Reserved_Tags parallel arrays have a non-BBL variant that must stay aligned).
3647 int old_nozzle_id = get_nozzle_id(old_filament_id, m_cur_layer_id);
3648 int new_nozzle_id = get_nozzle_id(new_filament_id, m_cur_layer_id);
3649 snprintf(buff, sizeof(buff), ";%s OF%d NF%d ON%d NN%d\n", tag.c_str(), old_filament_id, new_filament_id,old_nozzle_id,new_nozzle_id);
3650 return std::string(buff);
3651 };
3652
3653 float nz_extrusion_flow = nozzle_change_extrusion_flow(m_layer_height);
3655 writer.set_extrusion_flow(nz_extrusion_flow)
3656 .set_z(m_z_pos)
3657 .set_initial_tool(m_current_tool)
3658 .set_y_shift(m_y_shift + (new_filament_id != (unsigned int) (-1) && (m_current_shape == SHAPE_REVERSED) ? m_layer_info->depth - m_layer_info->toolchanges_depth() : 0.f));
3660
3661 WipeTowerBlock* block = get_block_by_category(m_filpar[old_filament_id].category, false);
3662 if (!block) {
3663 assert(false);
3664 return WipeTower::NozzleChangeResult();
3665 }
3666 m_cur_block = block;
3667
3669 box_coordinates cleaning_box(Vec2f(x_offset, block->cur_depth + (m_nozzle_change_perimeter_width - m_perimeter_width) / 2),
3670 nozzle_change_box_width,
3671 nozzle_change_depth);
3672 Vec2f initial_position = cleaning_box.ld;
3673 writer.set_initial_position(initial_position, m_wipe_tower_width, m_wipe_tower_depth, m_internal_rotation);
3674
3675 // --- Nozzle change preamble: notify firmware + precool ---
3676 writer.append(format_nozzle_change_line(true, old_filament_id, new_filament_id));
3677 if (!extruder_change) {
3678 int new_nozzle_id = m_multi_nozzle_group_result->is_support_dynamic_nozzle_map()
3679 ? get_nozzle_id(new_filament_id, m_cur_layer_id) : -1;
3680 writer.append(format_line_M632(new_filament_id, new_nozzle_id));
3681 if (m_filpar[m_current_tool].precool_target_temp.second != 0) {
3682 writer.format_line_M104(m_filpar[m_current_tool].precool_target_temp.second, get_extruder_id(m_current_tool, m_cur_layer_id))
3683 .append(format_line_M106());
3684 }
3685 writer.append(format_line_M633());
3686 }
3687
3688 NozzleChangeResult result;
3689
3690 if (nozzle_change_line_count > 0) {
3691 float max_e_ramming_speed = extruder_change ? m_filpar[m_current_tool].max_e_ramming_speed.first : m_filpar[m_current_tool].max_e_ramming_speed.second;
3692 float nozzle_change_speed = 60.0f * max_e_ramming_speed / nz_extrusion_flow;
3693 if (solid_infill)
3694 nozzle_change_speed = std::min(40.f * 60.f, nozzle_change_speed);
3695 float bridge_speed = std::min(60.0f * max_e_ramming_speed / nozzle_change_extrusion_flow(0.2), nozzle_change_speed);
3696
3697 const float &xl = cleaning_box.ld.x();
3698 const float &xr = cleaning_box.rd.x();
3699 dy = solid_infill ? m_nozzle_change_perimeter_width : dy;
3700 if (solid_infill)
3701 nozzle_change_line_count = std::floor(EPSILON + (cleaning_box.ru[1] - cleaning_box.rd[1] + (m_nozzle_change_perimeter_width - m_perimeter_width) / 2.f) /
3703 m_left_to_right = true;
3704 bool need_change_flow = false;
3705 float ramming_length = nozzle_change_line_count * (xr - xl);
3706 int extruder_id = get_extruder_id(m_current_tool, m_cur_layer_id);
3707 // -1: the filament is not in this layer's nozzle map.
3708 float precool_t = extruder_id < 0 ? 0.f :
3709 extruder_change ? m_filpar[m_current_tool].precool_t.first[extruder_id] : m_filpar[m_current_tool].precool_t.second[extruder_id];
3710 float precool_t_first_layer = extruder_id < 0 ? 0.f :
3711 extruder_change ? m_filpar[m_current_tool].precool_t_first_layer.first[extruder_id] :
3712 m_filpar[m_current_tool].precool_t_first_layer.second[extruder_id];
3713 float per_cooling_max_speed = nozzle_change_speed;
3714 if (extruder_change) {
3715 if (is_first_layer() && precool_t_first_layer > EPSILON)
3716 per_cooling_max_speed = ramming_length / precool_t_first_layer * 60.f;
3717 else if (precool_t > EPSILON)
3718 per_cooling_max_speed = ramming_length / precool_t * 60.f;
3719 }//BBS:nozzle change does not require forcing a cooldown to a specific temperature.
3720 if (nozzle_change_speed > per_cooling_max_speed) nozzle_change_speed = per_cooling_max_speed;
3721 if (bridge_speed > per_cooling_max_speed) bridge_speed = per_cooling_max_speed;
3722 LimitFlow LimitRamming = extruder_change ? LimitFlow::LimitRammingFlow : LimitFlow::LimitRammingFlowNC;
3723 for (int i = 0; true; ++i) {
3724 if (need_thick_bridge_flow(writer.pos().y())) {
3725 writer.set_extrusion_flow(nozzle_change_extrusion_flow(0.2));
3727 need_change_flow = true;
3728 }
3729 if (m_left_to_right)
3730 writer.extrude(xr + wipe_tower_wall_infill_overlap * m_perimeter_width, writer.y(), need_change_flow ? bridge_speed : nozzle_change_speed, LimitRamming);
3731 else
3732 writer.extrude(xl - wipe_tower_wall_infill_overlap * m_perimeter_width, writer.y(), need_change_flow ? bridge_speed : nozzle_change_speed, LimitRamming);
3733 if (i == nozzle_change_line_count - 1)
3734 break;
3735 if ((writer.y() + dy - cleaning_box.ru.y()+(m_nozzle_change_perimeter_width+m_perimeter_width)/2) > (float)EPSILON) break;
3736 if (need_change_flow) {
3737 writer.set_extrusion_flow(nozzle_change_extrusion_flow(m_layer_height));
3739 need_change_flow = false;
3740 }
3741 writer.extrude(writer.x(), writer.y() + dy, nozzle_change_speed, LimitRamming);
3743 }
3744 if (need_change_flow) {
3746 }
3747
3748 writer.set_extrusion_flow(nz_extrusion_flow);
3749 block->cur_depth += nozzle_change_depth;
3750 block->last_nozzle_change_id = old_filament_id;
3751 // --- Post-ramming: re-arm nozzle change for travel phase ---
3752 if (!extruder_change) {
3753 int new_nozzle_id = m_multi_nozzle_group_result->is_support_dynamic_nozzle_map()
3754 ? get_nozzle_id(new_filament_id, m_cur_layer_id) : -1;
3755 writer.append(format_line_M632(new_filament_id, new_nozzle_id));
3756 }
3757
3758 if (is_need_reverse_travel(m_current_tool, extruder_change)) {
3759 bool left_to_right = !m_left_to_right;
3760 int tpu_line_count = nozzle_change_line_count;
3761 nozzle_change_speed *= 2; // due to nozzle change 2 perimeter
3762 float ramming_travel_time = extruder_change ? m_filpar[m_current_tool].ramming_travel_time.first : m_filpar[m_current_tool].ramming_travel_time.second;
3763 float need_reverse_travel_dis = ramming_travel_time * nozzle_change_speed / 60.f;
3764 float real_travel_dis = tpu_line_count * (xr - xl - 2 * m_perimeter_width);
3765 if (real_travel_dis < need_reverse_travel_dis)
3766 nozzle_change_speed *= real_travel_dis / need_reverse_travel_dis;
3767 writer.travel(writer.x(), writer.y() + dy/2);
3768
3769 for (int i = 0; true; ++i) {
3770 need_reverse_travel_dis -= (xr - xl - 2 * m_perimeter_width);
3771 float offset_dis = 0.f;
3772 if (need_reverse_travel_dis < 0) {
3773 offset_dis = -need_reverse_travel_dis;
3774 }
3775 if (left_to_right)
3776 writer.travel(xr - m_perimeter_width - offset_dis, writer.y(), nozzle_change_speed);
3777 else
3778 writer.travel(xl + m_perimeter_width + offset_dis , writer.y(), nozzle_change_speed);
3779 if (need_reverse_travel_dis < EPSILON) break;
3780 if (i == tpu_line_count - 1)
3781 break;
3782
3783 writer.travel(writer.x(), writer.y() - dy);
3784 left_to_right = !left_to_right;
3785 }
3786 } else {
3787 result.wipe_path.push_back(writer.pos_rotated());
3788 if (m_left_to_right) {
3789 result.wipe_path.push_back(Vec2f(0, writer.pos_rotated().y()));
3790 } else {
3791 result.wipe_path.push_back(Vec2f(m_wipe_tower_width, writer.pos_rotated().y()));
3792 }
3793 }
3794 if (!extruder_change) writer.append(format_line_M633());
3795 }
3796
3797 writer.append(format_nozzle_change_line(false, old_filament_id, new_filament_id));
3798
3799 result.start_pos = writer.start_pos_rotated();
3800 result.origin_start_pos = initial_position;
3801 result.end_pos = writer.pos_rotated();
3802 result.gcode = writer.gcode();
3803 result.is_extruder_change = extruder_change;
3804 return result;
3805}
static const std::string Nozzle_Change_Start_Tag
Definition GCodeProcessor.hpp:598
@ Height
Definition GCodeProcessor.hpp:607
static const std::string Nozzle_Change_End_Tag
Definition GCodeProcessor.hpp:599
Vec2f start_pos
Definition WipeTower.hpp:104
bool need_thick_bridge_flow(float pos_y) const
Definition WipeTower.cpp:5512
int get_nozzle_id(int filament_id, int layer_id) const
Definition WipeTower.cpp:5556
Definition WipeTower.hpp:101
static const double wipe_tower_wall_infill_overlap
Definition WipeTower.cpp:44
LimitFlow
Definition WipeTower.cpp:50
@ LimitRammingFlow
Definition WipeTower.cpp:50
@ LimitRammingFlowNC
Definition WipeTower.cpp:50

References Slic3r::WipeTowerWriter::append(), Slic3r::WipeTower::WipeTowerBlock::cur_depth, Slic3r::WipeTower::NozzleChangeResult::end_pos, EPSILON, Slic3r::WipeTowerWriter::extrude(), Slic3r::float_to_string_decimal_point(), Slic3r::WipeTowerWriter::format_line_M104(), Slic3r::WipeTower::NozzleChangeResult::gcode, Slic3r::WipeTowerWriter::gcode(), get_block_by_category(), get_block_gap_width(), get_extruder_id(), get_nozzle_id(), Slic3r::GCodeProcessor::Height, Slic3r::WipeTower::NozzleChangeResult::is_extruder_change, is_first_layer(), is_need_reverse_travel(), Slic3r::WipeTower::WipeTowerBlock::last_nozzle_change_id, Slic3r::WipeTower::box_coordinates::ld, Slic3r::LimitRammingFlow, Slic3r::LimitRammingFlowNC, m_cur_block, m_cur_layer_id, m_current_shape, m_current_tool, m_enable_arc_fitting, m_filpar, m_gcode_flavor, m_internal_rotation, m_layer_height, m_layer_info, m_left_to_right, m_multi_nozzle_group_result, m_nozzle_change_perimeter_width, m_perimeter_width, m_wipe_tower_depth, m_wipe_tower_width, m_y_shift, m_z_pos, need_thick_bridge_flow(), Slic3r::GCodeProcessor::Nozzle_Change_End_Tag, nozzle_change_extrusion_flow(), Slic3r::GCodeProcessor::Nozzle_Change_Start_Tag, Slic3r::WipeTower::NozzleChangeResult::origin_start_pos, Slic3r::WipeTowerWriter::pos(), Slic3r::WipeTowerWriter::pos_rotated(), Slic3r::WipeTower::box_coordinates::rd, Slic3r::GCodeProcessor::reserved_tag(), Slic3r::WipeTower::box_coordinates::ru, Slic3r::WipeTowerWriter::set_extrusion_flow(), set_for_wipe_tower_writer(), Slic3r::WipeTowerWriter::set_initial_position(), Slic3r::WipeTowerWriter::set_initial_tool(), Slic3r::WipeTowerWriter::set_y_shift(), Slic3r::WipeTowerWriter::set_z(), SHAPE_REVERSED, Slic3r::WipeTower::NozzleChangeResult::start_pos, Slic3r::WipeTowerWriter::start_pos_rotated(), Slic3r::WipeTowerWriter::travel(), Slic3r::WipeTower::NozzleChangeResult::wipe_path, Slic3r::wipe_tower_wall_infill_overlap, WipeTowerWriter, Slic3r::WipeTowerWriter::x(), and Slic3r::WipeTowerWriter::y().

Referenced by tool_change_new().

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

◆ reset_block_status()

void Slic3r::WipeTower::reset_block_status ( )
4484{
4485 for (auto &block : m_wipe_tower_blocks) {
4486 block.cur_depth = block.start_depth;
4487 block.last_filament_change_id = -1;
4488 block.last_nozzle_change_id = -1;
4489 }
4490}

References m_wipe_tower_blocks.

Referenced by generate_new().

Here is the caller graph for this function:

◆ rib_footprint_side()

float Slic3r::WipeTower::rib_footprint_side ( float width,
float depth,
float rib_width,
float extra_rib_length,
float max_height )
static
1800{
1801 if (width < EPSILON || depth < EPSILON)
1802 return 0.f;
1803 // Ribs run the diagonal; below the height-based minimum they are extended rather than the
1804 // body, then by the extra length, never ending up shorter than the diagonal.
1805 const float diagonal = std::sqrt(width * width + depth * depth);
1806 float rib_length = diagonal;
1807 if (depth + EPSILON < get_limit_depth_by_height(max_height))
1808 rib_length = std::max(rib_length, get_limit_depth_by_height(max_height) * float(std::sqrt(2.)));
1809 rib_length = std::max(diagonal, rib_length + extra_rib_length);
1810 // Half the extension at each end of the diagonal plus half the rib width, projected onto the axes.
1811 const float rib_w = std::min(rib_width, std::min(width, depth) / 2.f);
1812 const float per_side = ((rib_length - diagonal) / 2.f + rib_w / 2.f) / float(std::sqrt(2.));
1813 return std::max(width, depth) + 2.f * per_side;
1814}

References EPSILON, get_limit_depth_by_height(), and width().

Referenced by estimate_rib_tower_bbox_side(), and Slic3r::estimate_wipe_tower_footprint().

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

◆ rib_section()

Polygon Slic3r::WipeTower::rib_section ( float width,
float depth,
float rib_length,
float rib_width,
bool fillet_wall )
static
1879{
1880 Polygon res;
1881 res.points.resize(16);
1882 float theta = std::atan(width / depth);
1883 float costheta = std::cos(theta);
1884 float sintheta = std::sin(theta);
1885 float w = rib_width / 2.f;
1886 float diag = std::sqrt(width * width + depth * depth);
1887 float l = (rib_length - diag) / 2;
1888 Vec2f diag_dir1 = Vec2f{width, depth}.normalized();
1889 Vec2f diag_dir1_perp{-diag_dir1[1], diag_dir1[0]};
1890 Vec2f diag_dir2 = Vec2f{-width, depth}.normalized();
1891 Vec2f diag_dir2_perp{-diag_dir2[1], diag_dir2[0]};
1892 std::vector<Vec2f> p{{0, 0}, {width, 0}, {width, depth}, {0, depth}};
1893 Polyline p_render;
1894 for (auto &x : p) p_render.points.push_back(scaled(x));
1895 res.points[0] = scaled(Vec2f{p[0].x(), p[0].y() + w / sintheta});
1896 res.points[1] = scaled(Vec2f{p[0] - diag_dir1 * l + diag_dir1_perp * w});
1897 res.points[2] = scaled(Vec2f{p[0] - diag_dir1 * l - diag_dir1_perp * w});
1898 res.points[3] = scaled(Vec2f{p[0].x() + w / costheta, p[0].y()});
1899
1900 res.points[4] = scaled(Vec2f{p[1].x() - w / costheta, p[1].y()});
1901 res.points[5] = scaled(Vec2f{p[1] - diag_dir2 * l + diag_dir2_perp * w});
1902 res.points[6] = scaled(Vec2f{p[1] - diag_dir2 * l - diag_dir2_perp * w});
1903 res.points[7] = scaled(Vec2f{p[1].x(), p[1].y() + w / sintheta});
1904
1905 res.points[8] = scaled(Vec2f{p[2].x(), p[2].y() - w / sintheta});
1906 res.points[9] = scaled(Vec2f{p[2] + diag_dir1 * l - diag_dir1_perp * w});
1907 res.points[10] = scaled(Vec2f{p[2] + diag_dir1 * l + diag_dir1_perp * w});
1908 res.points[11] = scaled(Vec2f{p[2].x() - w / costheta, p[2].y()});
1909
1910 res.points[12] = scaled(Vec2f{p[3].x() + w / costheta, p[3].y()});
1911 res.points[13] = scaled(Vec2f{p[3] + diag_dir2 * l - diag_dir2_perp * w});
1912 res.points[14] = scaled(Vec2f{p[3] + diag_dir2 * l + diag_dir2_perp * w});
1913 res.points[15] = scaled(Vec2f{p[3].x(), p[3].y() - w / sintheta});
1914 res.remove_duplicate_points();
1915 if (fillet_wall) { res = rounding_polygon(res); }
1916 res.points.shrink_to_fit();
1917 return res;
1918}
Points points
Definition MultiPoint.hpp:22

References Slic3r::MultiPoint::points, Slic3r::MultiPoint::remove_duplicate_points(), rounding_polygon(), Slic3r::scaled(), and width().

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

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

◆ rounding_polygon()

Polygon Slic3r::WipeTower::rounding_polygon ( Polygon & polygon,
double rounding = 2.,
double angle_tol = 30. / 180. * PI )
static
206{
207 if (polygon.points.size() < 3) return polygon;
208 Polygon res;
209 res.points.reserve(polygon.points.size() * 2);
210 int mod = polygon.points.size();
211 double cos_angle_tol = abs(std::cos(angle_tol));
212
213 for (int i = 0; i < polygon.points.size(); i++) {
214 Vec2d a = unscaled(polygon.points[(i - 1 + mod) % mod]);
215 Vec2d b = unscaled(polygon.points[i]);
216 Vec2d c = unscaled(polygon.points[(i + 1) % mod]);
217 double ab_len = (a - b).norm();
218 double bc_len = (b - c).norm();
219 Vec2d ab = (b - a) / ab_len;
220 Vec2d bc = (c - b) / bc_len;
221 assert(ab_len != 0);
222 assert(bc_len != 0);
223 float cosangle = ab.dot(bc);
224 cosangle = std::clamp(cosangle, -1.f, 1.f);
225 bool is_ccw = cross2(ab, bc) > 0;
226 if (abs(cosangle) < cos_angle_tol) {
227 float real_rounding_dis = std::min({rounding, ab_len / 2.1, bc_len / 2.1}); // 2.1 to ensure the points do not coincide
228 Vec2d left = b - ab * real_rounding_dis;
229 Vec2d right = b + bc * real_rounding_dis;
230 //Point r_left = scaled(left);
231 //Point r_right = scaled(right);
232 // std::cout << " r_left " << r_left[0] << " " << r_left[1] << std::endl;
233 //std::cout << " r_right " << r_right[0] << " " << r_right[1] << std::endl;
234 {
235 float half_angle = std::acos(cosangle)/2.f;
236 //std::cout << " half_angle " << cos(half_angle) << std::endl;
237
238 Vec2d dir = (right - left).normalized();
239 dir = Vec2d{-dir[1], dir[0]};
240 dir = is_ccw ? dir : -dir;
241 double dis = real_rounding_dis / sin(half_angle);
242 //std::cout << " dis " << dis << std::endl;
243
244 Vec2d center = b + dir * dis;
245 double radius = (left - center).norm();
247 int n = arc_fit_size;
248 //std::cout << "start " << arc.start_point[0] << " " << arc.start_point[1] << std::endl;
249 //std::cout << "end " << arc.end_point[0] << " " << arc.end_point[1] << std::endl;
250 //std::cout << "start angle " << arc.polar_start_theta << " end angle " << arc.polar_end_theta << std::endl;
251 for (int j = 0; j < n; j++) {
252 float cur_angle = arc.polar_start_theta + (float)j/n * arc.angle_radians ;
253 //std::cout << " cur_angle " << cur_angle << std::endl;
254 if (cur_angle > 2 * PI)
255 cur_angle -= 2 * PI;
256 else if (cur_angle < 0)
257 cur_angle += 2 * PI;
258 Point tmp = arc.center + Point{arc.radius * std::cos(cur_angle), arc.radius *std::sin(cur_angle)};
259 //std::cout << "j = " << j << std::endl;
260 //std::cout << "tmp = " << tmp[0]<<" "<<tmp[1] << std::endl;
261 res.points.push_back(tmp);
262 }
263 }
264 res.points.push_back(scaled(right));
265 } else
266 res.points.push_back(polygon.points[i]);
267 }
268 res.remove_duplicate_points();
269 res.points.shrink_to_fit();
270 return res;
271}
static constexpr double PI
Definition libslic3r.h:81
void arc(std::vector< std::pair< Vec2d, Vec2d > > &out, double cx, double cy, double rx, double ry, double a0, double a1, int n=14)
Definition DesignSketchTool.cpp:7759
static bool is_ccw(const Polygon &poly)
Definition Geometry.hpp:66
int32_t cross2(const Eigen::MatrixBase< Eigen::Matrix< int32_t, 2, 1, Options > > &v1, const Eigen::MatrixBase< Eigen::Matrix< int32_t, 2, 1, Options > > &v2)=delete
static constexpr int arc_fit_size
Definition WipeTower.cpp:48
@ Arc_Dir_CW
Definition Circle.hpp:64
@ Arc_Dir_CCW
Definition Circle.hpp:63

References Slic3r::Arc_Dir_CCW, Slic3r::Arc_Dir_CW, Slic3r::arc_fit_size, Slic3r::center(), Slic3r::cross2(), Slic3r::Geometry::is_ccw(), PI, Slic3r::MultiPoint::points, Slic3r::MultiPoint::remove_duplicate_points(), Slic3r::scaled(), and Slic3r::unscaled().

Referenced by generate_support_wall_new(), and rib_section().

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

◆ save_on_last_wipe()

void Slic3r::WipeTower::save_on_last_wipe ( )
private

References WipeTowerWriter.

Here is the call graph for this function:

◆ set_accelerations()

void Slic3r::WipeTower::set_accelerations ( const std::vector< double > & normal,
const std::vector< double > & first_layer_normal,
const std::vector< double > & travel,
const std::vector< double > & first_layer_travel )
4515{
4516 auto to_accels = [](const std::vector<double> &values, std::vector<unsigned int> &accels) {
4517 accels.clear();
4518 for (double value : values)
4519 accels.emplace_back((unsigned int) floor(value + 0.5));
4520 };
4521 to_accels(normal, m_normal_accels);
4522 to_accels(first_layer_normal, m_first_layer_normal_accels);
4523 to_accels(travel, m_travel_accels);
4524 to_accels(first_layer_travel, m_first_layer_travel_accels);
4525}
std::vector< unsigned int > m_normal_accels
Definition WipeTower.hpp:544
std::vector< unsigned int > m_travel_accels
Definition WipeTower.hpp:546
std::vector< unsigned int > m_first_layer_normal_accels
Definition WipeTower.hpp:545
std::vector< unsigned int > m_first_layer_travel_accels
Definition WipeTower.hpp:547
Point normal(Point pt, double scale)
Definition TreeSupport.cpp:112

References m_first_layer_normal_accels, m_first_layer_travel_accels, m_normal_accels, m_travel_accels, and Slic3r::normal().

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

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

◆ set_extruder()

void Slic3r::WipeTower::set_extruder ( size_t idx,
const PrintConfig & config )
2078{
2079 //while (m_filpar.size() < idx+1) // makes sure the required element is in the vector
2080 m_filpar.push_back(FilamentParameters());
2081
2082 m_filpar[idx].material = config.filament_type.get_at(idx);
2083 // Orca: wipe_tower_filament (issue #10971) forces a specific filament to print the tower wall by
2084 // marking every other filament as "soluble"; 0 keeps the plain per-filament soluble flag.
2085 m_filpar[idx].is_soluble = config.wipe_tower_filament == 0 ? config.filament_soluble.get_at(idx) : (idx != size_t(config.wipe_tower_filament - 1));
2086 // BBS
2087 m_filpar[idx].is_support = config.filament_is_support.get_at(idx);
2088 m_filpar[idx].nozzle_temperature = config.nozzle_temperature.get_at(idx);
2089 m_filpar[idx].nozzle_temperature_initial_layer = config.nozzle_temperature_initial_layer.get_at(idx);
2090 m_filpar[idx].category = config.filament_adhesiveness_category.get_at(idx);
2091 m_filpar[idx].flat_iron_area = config.filament_tower_ironing_area.get_at(idx);
2092
2093 // If this is a single extruder MM printer, we will use all the SE-specific config values.
2094 // Otherwise, the defaults will be used to turn off the SE stuff.
2095 // BBS: remove useless config
2096#if 0
2097 if (m_semm) {
2098 m_filpar[idx].loading_speed = float(config.filament_loading_speed.get_at(idx));
2099 m_filpar[idx].loading_speed_start = float(config.filament_loading_speed_start.get_at(idx));
2100 m_filpar[idx].unloading_speed = float(config.filament_unloading_speed.get_at(idx));
2101 m_filpar[idx].unloading_speed_start = float(config.filament_unloading_speed_start.get_at(idx));
2102 m_filpar[idx].delay = float(config.filament_toolchange_delay.get_at(idx));
2103 m_filpar[idx].cooling_moves = config.filament_cooling_moves.get_at(idx);
2104 m_filpar[idx].cooling_initial_speed = float(config.filament_cooling_initial_speed.get_at(idx));
2105 m_filpar[idx].cooling_final_speed = float(config.filament_cooling_final_speed.get_at(idx));
2106 }
2107#endif
2108
2109 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
2110 float nozzle_diameter = float(config.nozzle_diameter.get_at(idx));
2111 m_filpar[idx].nozzle_diameter = nozzle_diameter; // to be used in future with (non-single) multiextruder MM
2112
2113 // Orca: max_layer_height is per nozzle, so read it through the filament->nozzle map rather than
2114 // by filament id. Zero means three quarters of the nozzle diameter, as in Slicing.cpp.
2115 {
2116 const std::vector<int> &filament_map = config.filament_map.values; // 1 based nozzle indices
2117 const size_t nozzle_idx = idx < filament_map.size() && filament_map[idx] > 0 ? size_t(filament_map[idx] - 1) : 0;
2118 const float max_layer_height = float(config.max_layer_height.get_at(nozzle_idx));
2119 m_filpar[idx].max_layer_height = max_layer_height > 0.f ? max_layer_height
2120 : 0.75f * float(config.nozzle_diameter.get_at(nozzle_idx));
2121 }
2122
2123 float max_vol_speed = float(config.filament_max_volumetric_speed.get_at(idx));
2124 if (max_vol_speed!= 0.f)
2125 m_filpar[idx].max_e_speed = (max_vol_speed / filament_area());
2126
2127 //set extruder change and nozzle change ramming speed
2128 {
2129 float ramming_vol_speed = float(config.filament_ramming_volumetric_speed.get_at(idx));
2130 if (config.filament_ramming_volumetric_speed.is_nil(idx) || is_approx(config.filament_ramming_volumetric_speed.get_at(idx), -1.)) ramming_vol_speed = max_vol_speed;
2131 m_filpar[idx].max_e_ramming_speed.first = (ramming_vol_speed / filament_area());
2132
2133 float ramming_vol_speed_nc = float(config.filament_ramming_volumetric_speed_nc.get_at(idx));
2134 if (config.filament_ramming_volumetric_speed_nc.is_nil(idx) || is_approx(config.filament_ramming_volumetric_speed_nc.get_at(idx), -1.))
2135 ramming_vol_speed_nc = max_vol_speed;
2136 m_filpar[idx].max_e_ramming_speed.second = (ramming_vol_speed_nc / filament_area());
2137 }
2138
2139 //set precooling time/precooling target temp during extruder change and nozzle change
2140 {
2141 int extruder_count = m_multi_nozzle_group_result->get_extruder_count();
2142 m_filpar[idx].precool_t.first.resize(extruder_count, 0.f);
2143 m_filpar[idx].precool_t_first_layer.first.resize(extruder_count, 0.f);
2144 m_filpar[idx].precool_t.second.resize(extruder_count, 0.f);
2145 m_filpar[idx].precool_t_first_layer.second.resize(extruder_count, 0.f);
2146 m_filpar[idx].precool_target_temp.first = 0;
2147 m_filpar[idx].precool_target_temp.second = 0;
2148 float nozzle_temp_first_layer = config.nozzle_temperature_initial_layer.is_nil(idx) ? -1.f : float(config.nozzle_temperature_initial_layer.get_at(idx));
2149 float nozzle_temp_other_layer = config.nozzle_temperature.is_nil(idx) ? -1.f : float(config.nozzle_temperature.get_at(idx));
2150 auto is_need_precooling = [&](bool extruder_change) -> bool
2151 {
2152 bool res = config.enable_pre_heating.value;
2153 if (extruder_change) return res &&!config.filament_pre_cooling_temperature.is_nil(idx) && config.filament_pre_cooling_temperature.get_at(idx) != 0;
2154 return res &&!config.filament_pre_cooling_temperature_nc.is_nil(idx) && config.filament_pre_cooling_temperature_nc.get_at(idx) != 0;
2155 };
2156 if (is_need_precooling(true)) {
2157 for (int i = 0; i < m_filpar[idx].precool_t.first.size(); i++) {
2158 if (config.hotend_cooling_rate.is_nil(i)) continue;
2159 m_filpar[idx].precool_t.first[i] = std::max(0.f, nozzle_temp_other_layer - float(config.filament_pre_cooling_temperature.get_at(idx))) / float(config.hotend_cooling_rate.get_at(i));
2160 m_filpar[idx].precool_t_first_layer.first[i] = std::max(0.f, nozzle_temp_first_layer -float(config.filament_pre_cooling_temperature.get_at(idx))) /float(config.hotend_cooling_rate.get_at(i));
2161 }
2162 m_filpar[idx].precool_target_temp.first = config.filament_pre_cooling_temperature.get_at(idx);
2163 }
2164
2165 if (is_need_precooling(false)) {
2166 for (int i = 0; i < m_filpar[idx].precool_t.second.size(); i++) {
2167 if (config.hotend_cooling_rate.is_nil(i)) continue;
2168 m_filpar[idx].precool_t.second[i] = std::max(0.f, nozzle_temp_other_layer - float(config.filament_pre_cooling_temperature_nc.get_at(idx))) / float(config.hotend_cooling_rate.get_at(i));
2169 m_filpar[idx].precool_t_first_layer.second[i] = std::max(0.f, nozzle_temp_first_layer -float(config.filament_pre_cooling_temperature_nc.get_at(idx))) /float(config.hotend_cooling_rate.get_at(i));
2170 }
2171 m_filpar[idx].precool_target_temp.second = config.filament_pre_cooling_temperature_nc.get_at(idx);
2172 }
2173
2174 }
2175 //set ramming reverse travel time during extruder change and nozzle change
2176 {
2177 m_filpar[idx].ramming_travel_time = {0, 0};
2178 if (!config.filament_ramming_travel_time.is_nil(idx)) m_filpar[idx].ramming_travel_time.first = float(config.filament_ramming_travel_time.get_at(idx));
2179 if (!config.filament_ramming_travel_time_nc.is_nil(idx)) m_filpar[idx].ramming_travel_time.second = float(config.filament_ramming_travel_time_nc.get_at(idx));
2180 }
2181 m_perimeter_width = nozzle_diameter * Width_To_Nozzle_Ratio; // all extruders are now assumed to have the same diameter
2182 // Orca: custom presets may use nozzle diameters outside the BBS table; fall back to the
2183 // previous 2*perimeter_width rule (identical to the table for 0.4) instead of throwing.
2184 {
2186 m_nozzle_change_perimeter_width = nc_width_it != nozzle_diameter_to_nozzle_change_width.end() ? nc_width_it->second : 2.f * m_perimeter_width;
2187 }
2188 // BBS: remove useless config
2189#if 0
2190 if (m_semm) {
2191 std::istringstream stream{config.filament_ramming_parameters.get_at(idx)};
2192 float speed = 0.f;
2193 stream >> m_filpar[idx].ramming_line_width_multiplicator >> m_filpar[idx].ramming_step_multiplicator;
2194 m_filpar[idx].ramming_line_width_multiplicator /= 100;
2195 m_filpar[idx].ramming_step_multiplicator /= 100;
2196 while (stream >> speed)
2197 m_filpar[idx].ramming_speed.push_back(speed);
2198 }
2199#endif
2200
2201 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
2202
2203 m_filpar[idx].retract_length = config.retraction_length.get_at(idx);
2204 m_filpar[idx].retract_speed = config.retraction_speed.get_at(idx);
2205 m_filpar[idx].wipe_dist = config.wipe_distance.get_at(idx);
2206 m_filpar[idx].filament_cooling_before_tower = config.filament_cooling_before_tower.get_at(idx);
2207 m_filpar[idx].filament_petg_pre_extrusion_offset_dist = config.filament_tower_interface_pre_extrusion_dist.get_at(idx);
2208 if (config.enable_tower_interface_features.value) {
2209 m_filpar[idx].filament_tower_interface_print_temp = config.filament_tower_interface_print_temp.get_at(idx) == -1 ? config.nozzle_temperature_range_high.get_at(idx) :
2210 config.filament_tower_interface_print_temp.get_at(idx);
2211 m_filpar[idx].filament_tower_interface_pre_extrusion_dist = config.filament_tower_interface_pre_extrusion_dist.get_at(idx);
2212 m_filpar[idx].filament_tower_interface_pre_extrusion_length = config.filament_tower_interface_pre_extrusion_length.get_at(idx);
2213 } else {
2214 m_filpar[idx].filament_tower_interface_print_temp = config.nozzle_temperature.get_at(idx);
2215 m_filpar[idx].filament_tower_interface_pre_extrusion_dist = 0.f;
2216 m_filpar[idx].filament_tower_interface_pre_extrusion_length = 0.f;
2217 }
2218}
const float Width_To_Nozzle_Ratio
Definition WipeTower.hpp:485
Definition WipeTower.hpp:368
zaa_minimize_perimeter_height filament_map((ConfigOptionInts, filament_volume_map))((ConfigOptionInts

References filament_area(), Slic3r::filament_map(), Slic3r::is_approx(), m_filpar, m_multi_nozzle_group_result, m_nozzle_change_perimeter_width, m_perimeter_width, M_PI, m_semm, m_used_filament_length, Slic3r::nozzle_diameter(), Slic3r::nozzle_diameter_to_nozzle_change_width, 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_filament_categories()

void Slic3r::WipeTower::set_filament_categories ( const std::vector< int > & filament_categories)
inline
411{ m_filament_categories = filament_categories;};

References m_filament_categories.

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

Here is the caller graph for this function:

◆ set_first_layer_flow_ratio()

void Slic3r::WipeTower::set_first_layer_flow_ratio ( const float flow_ratio)
4507{
4508 m_first_layer_flow_ratio = flow_ratio;
4509}
float m_first_layer_flow_ratio
Definition WipeTower.hpp:565

References m_first_layer_flow_ratio.

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

Here is the caller graph for this function:

◆ set_for_wipe_tower_writer()

void Slic3r::WipeTower::set_for_wipe_tower_writer ( WipeTowerWriter & writer)
private
2922{
2923 writer.set_normal_acceleration(m_normal_accels);
2924 writer.set_travel_acceleration(m_travel_accels);
2925 writer.set_first_layer_normal_acceleration(m_first_layer_normal_accels);
2926 writer.set_first_layer_travel_acceleration(m_first_layer_travel_accels);
2927 writer.set_max_acceleration(m_max_accels);
2928 writer.set_multi_nozzle_group_result(m_multi_nozzle_group_result);
2929 writer.set_accel_to_decel_enable(m_accel_to_decel_enable);
2930 writer.set_accel_to_decel_factor(m_accel_to_decel_factor);
2931 writer.set_first_layer(m_cur_layer_id == 0);
2932 writer.set_layer_id(m_cur_layer_id);
2933 writer.set_physical_extruder_map(m_physical_extruder_map);
2934}

References m_accel_to_decel_enable, m_accel_to_decel_factor, m_cur_layer_id, m_first_layer_normal_accels, m_first_layer_travel_accels, m_max_accels, m_multi_nozzle_group_result, m_normal_accels, m_physical_extruder_map, m_travel_accels, Slic3r::WipeTowerWriter::set_accel_to_decel_enable(), Slic3r::WipeTowerWriter::set_accel_to_decel_factor(), Slic3r::WipeTowerWriter::set_first_layer(), Slic3r::WipeTowerWriter::set_first_layer_normal_acceleration(), Slic3r::WipeTowerWriter::set_first_layer_travel_acceleration(), Slic3r::WipeTowerWriter::set_layer_id(), Slic3r::WipeTowerWriter::set_max_acceleration(), Slic3r::WipeTowerWriter::set_multi_nozzle_group_result(), Slic3r::WipeTowerWriter::set_normal_acceleration(), Slic3r::WipeTowerWriter::set_physical_extruder_map(), Slic3r::WipeTowerWriter::set_travel_acceleration(), and WipeTowerWriter.

Referenced by finish_block(), finish_block_solid(), finish_layer_new(), only_generate_out_wall(), ramming(), tool_change(), and tool_change_new().

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

◆ set_has_filament_switcher()

void Slic3r::WipeTower::set_has_filament_switcher ( bool v)
inline

References m_has_filament_switcher.

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

Here is the caller graph for this function:

◆ set_has_tpu_filament()

void Slic3r::WipeTower::set_has_tpu_filament ( bool has_tpu)
inline
365{ m_has_tpu_filament = has_tpu; }

References m_has_tpu_filament.

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

Here is the caller graph for this function:

◆ set_last_layer_extruder_fill()

void Slic3r::WipeTower::set_last_layer_extruder_fill ( bool extruder_fill)
inline
273 {
274 if (!m_plan.empty()) {
275 m_plan.back().extruder_fill = extruder_fill;
276 }
277 }

References m_plan.

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

Here is the caller graph for this function:

◆ set_layer()

void Slic3r::WipeTower::set_layer ( float print_z,
float layer_height,
size_t max_tool_changes,
bool is_first_layer,
bool is_last_layer )
inline
292 {
293 m_z_pos = print_z;
295 m_depth_traversed = 0.f;
297 //m_current_shape = (! is_first_layer && m_current_shape == SHAPE_NORMAL) ? SHAPE_REVERSED : SHAPE_NORMAL;
299 if (is_first_layer) {
302 } else
304
305 // Calculate extrusion flow from desired line width, nozzle diameter, filament diameter and layer_height:
307 // Advance m_layer_info iterator, making sure we got it right
308 while (!m_plan.empty() && m_layer_info->z < print_z - WT_EPSILON && m_layer_info+1 != m_plan.end())
309 ++m_layer_info;
310 }

References extrusion_flow(), is_first_layer(), Slic3r::layer_height(), m_current_layer_finished, 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_z_pos, SHAPE_NORMAL, and WT_EPSILON.

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

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

◆ set_nozzle_group_result()

void Slic3r::WipeTower::set_nozzle_group_result ( const MultiNozzleUtils::LayeredNozzleGroupResult & multi_nozzle_group_result)
inline
412{ m_multi_nozzle_group_result = &multi_nozzle_group_result; };

References m_multi_nozzle_group_result.

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

Here is the caller graph for this function:

◆ set_nozzle_last_layer_id()

void Slic3r::WipeTower::set_nozzle_last_layer_id ( )
4492{
4493 for (int idx = 0; idx < m_plan.size(); idx++) {
4494 auto &info = m_plan[idx];
4495 for(int i =0 ; i<info.tool_changes.size();i++) {
4496 int old_tool = info.tool_changes[i].old_tool;
4497 int new_tool = info.tool_changes[i].new_tool;
4498 if (int ex = old_tool >= 0 ? get_extruder_id(old_tool, idx) : -1; ex >= 0 && ex < (int) m_last_layer_id.size())
4499 m_last_layer_id[ex] = idx;
4500 if (int ex = get_extruder_id(new_tool, idx); ex >= 0 && ex < (int) m_last_layer_id.size())
4501 m_last_layer_id[ex] = idx;
4502 }
4503 }
4504}

References get_extruder_id(), m_last_layer_id, and m_plan.

Referenced by plan_tower_new().

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

◆ set_shared_print_bed()

void Slic3r::WipeTower::set_shared_print_bed ( const Polygons & bed)
inline
239{ m_shared_print_bed = bed; }

References m_shared_print_bed.

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

Here is the caller graph for this function:

◆ set_toolchange()

WipeTower::WipeTowerInfo::ToolChange Slic3r::WipeTower::set_toolchange ( int old_tool,
int new_tool,
float layer_height,
float wipe_volume,
float purge_volume,
int layer_id )
private
3103{
3104 float depth = 0.f;
3107 float length_to_extrude = volume_to_length(wipe_volume, m_perimeter_width, layer_height);
3108 float toolchange_gap_width = get_block_gap_width(new_tool,false);
3109 float nozzlechange_gap_width = get_block_gap_width(old_tool,true);
3110 float filament_change_length = !is_same_extruder(old_tool, new_tool, layer_id) ? at_or_front(m_filaments_change_length.first, old_tool) : at_or_front(m_filaments_change_length.second, old_tool);
3111 depth += std::ceil(length_to_extrude / width) * toolchange_gap_width;
3112 // depth *= m_extra_spacing;
3113
3114 float nozzle_change_depth = 0;
3115 float nozzle_change_length = 0;
3116 if (is_need_ramming(old_tool, new_tool, layer_id)) {
3118 double length = filament_change_length / e_flow;
3119 int nozzle_change_line_count = std::ceil(length / nozzle_change_width);
3120 nozzle_change_depth = nozzle_change_line_count * nozzlechange_gap_width;
3121 depth += nozzle_change_depth;
3122 nozzle_change_length = length;
3123 }
3124 WipeTowerInfo::ToolChange tool_change = WipeTowerInfo::ToolChange(old_tool, new_tool, depth, 0.f, 0.f, wipe_volume, length_to_extrude, purge_volume);
3125 tool_change.nozzle_change_depth = nozzle_change_depth;
3126 tool_change.nozzle_change_length = nozzle_change_length;
3127 return tool_change;
3128}

References Slic3r::at_or_front(), get_block_gap_width(), is_need_ramming(), is_same_extruder(), Slic3r::layer_height(), Slic3r::length(), m_filaments_change_length, m_nozzle_change_perimeter_width, m_perimeter_width, m_wipe_tower_width, nozzle_change_extrusion_flow(), tool_change(), volume_to_length(), and width().

Referenced by calc_block_infill_gap(), and plan_tower_new().

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

◆ set_used_filament_ids()

void Slic3r::WipeTower::set_used_filament_ids ( const std::vector< int > & used_filament_ids)
inline
410{ m_used_filament_ids = used_filament_ids; };
std::vector< int > m_used_filament_ids
Definition WipeTower.hpp:413

References m_used_filament_ids.

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

Here is the caller graph for this function:

◆ tool_change()

WipeTower::ToolChangeResult Slic3r::WipeTower::tool_change ( size_t new_tool,
bool extrude_perimeter = false,
bool first_toolchange_to_nonsoluble = false )
2286{
2287 //only for tool = unsigned (-1) ,never get here
2288 //m_nozzle_change_result.gcode.clear();
2289 //if (!m_filament_map.empty() && tool < m_filament_map.size() && m_filament_map[m_current_tool] != m_filament_map[tool]) {
2290 // m_nozzle_change_result = nozzle_change(m_current_tool, tool);
2291 //}
2292
2293 size_t old_tool = m_current_tool;
2294
2295 float wipe_depth = 0.f;
2296 float wipe_length = 0.f;
2297 float purge_volume = 0.f;
2298 float nozzle_change_depth = 0.f;
2299 // Finds this toolchange info
2300 if (tool != (unsigned int)(-1))
2301 {
2302 for (const auto &b : m_layer_info->tool_changes)
2303 if ( b.new_tool == tool ) {
2304 wipe_length = b.wipe_length;
2305 wipe_depth = b.required_depth;
2306 purge_volume = b.purge_volume;
2307 nozzle_change_depth = b.nozzle_change_depth;
2308 break;
2309 }
2310 }
2311 else {
2312 // Otherwise we are going to Unload only. And m_layer_info would be invalid.
2313 }
2314
2315 box_coordinates cleaning_box(
2318 (tool != (unsigned int)(-1) ? wipe_depth + m_depth_traversed - m_perimeter_width
2320
2322 writer.set_extrusion_flow(m_extrusion_flow)
2323 .set_z(m_z_pos)
2324 .set_initial_tool(m_current_tool)
2325 .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))
2326 .append(";--------------------\n"
2327 "; CP TOOLCHANGE START\n")
2328 .comment_with_value(" toolchange #", m_num_tool_changes + 1); // the number is zero-based
2329
2331
2332 if (tool != (unsigned)(-1))
2333 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())
2334 .append(";--------------------\n");
2335
2336 writer.speed_override_backup();
2337 writer.speed_override(100);
2338
2339 float feedrate = is_first_layer() ? std::min(m_first_layer_speed * 60.f, 5400.f) : std::min(60.0f * m_filpar[m_current_tool].max_e_speed / m_extrusion_flow, 5400.f);
2340
2341 // Increase the extruder driver current to allow fast ramming.
2342 //BBS
2343 //if (m_set_extruder_trimpot)
2344 // writer.set_extruder_trimpot(750);
2345
2346 // Ram the hot material out of the melt zone, retract the filament into the cooling tubes and let it cool.
2347 if (tool != (unsigned int)-1){ // This is not the last change.
2349 toolchange_Unload(writer, cleaning_box, m_filpar[m_current_tool].material,
2350 is_first_layer() ? m_filpar[tool].nozzle_temperature_initial_layer : m_filpar[tool].nozzle_temperature);
2351 toolchange_Change(writer, tool, m_filpar[tool].material); // Change the tool, set a speed override for soluble and flex materials.
2352 toolchange_Load(writer, cleaning_box);
2353 // BBS
2354 //writer.travel(writer.x(), writer.y()-m_perimeter_width); // cooling and loading were done a bit down the road
2355
2356 if (m_is_multi_extruder && is_tpu_filament(tool)) {
2357 float dy = 2 * m_perimeter_width;
2358 float nozzle_change_speed = 60.0f * m_filpar[tool].max_e_speed / m_extrusion_flow;
2359 nozzle_change_speed *= 0.25;
2360
2361 const float &xl = cleaning_box.ld.x();
2362 const float &xr = cleaning_box.rd.x();
2363
2364 Vec2f start_pos = m_nozzle_change_result.start_pos + Vec2f(0, m_perimeter_width);
2365 bool left_to_right = true;
2366 double tpu_travel_length = 5;
2367 double e_flow = extrusion_flow(m_layer_height);
2368 double length = tpu_travel_length / e_flow;
2369 int tpu_line_count = length / (m_wipe_tower_width - 2 * m_perimeter_width) + 1;
2370
2371 writer.travel(start_pos);
2372
2373 for (int i = 0; true; ++i) {
2374 if (left_to_right)
2375 writer.travel(xr - m_perimeter_width, writer.y(), nozzle_change_speed);
2376 else
2377 writer.travel(xl + m_perimeter_width, writer.y(), nozzle_change_speed);
2378
2379 if (i == tpu_line_count - 1)
2380 break;
2381
2382 writer.travel(writer.x(), writer.y() + dy);
2383 left_to_right = !left_to_right;
2384 }
2385 }
2386
2387 Vec2f initial_position = get_next_pos(cleaning_box, wipe_length,false);
2388 writer.set_initial_position(initial_position, m_wipe_tower_width, m_wipe_tower_depth, m_internal_rotation);
2389
2390 if (extrude_perimeter) {
2391 box_coordinates wt_box(Vec2f(0.f, (m_current_shape == SHAPE_REVERSED) ? m_layer_info->toolchanges_depth() - m_layer_info->depth : 0.f), m_wipe_tower_width,
2393
2394 // align the perimeter
2395 Vec2f pos = initial_position;
2396 switch (m_cur_layer_id % 4){
2397 case 0:
2398 pos = wt_box.ld;
2399 break;
2400 case 1:
2401 pos = wt_box.rd;
2402 break;
2403 case 2:
2404 pos = wt_box.ru;
2405 break;
2406 case 3:
2407 pos = wt_box.lu;
2408 break;
2409 default: break;
2410 }
2411 writer.set_initial_position(pos, m_wipe_tower_width, m_wipe_tower_depth, m_internal_rotation);
2412
2413 wt_box = align_perimeter(wt_box);
2414 writer.rectangle(wt_box, feedrate);
2415 }
2416
2417 writer.travel(initial_position);
2418
2419 toolchange_Wipe(writer, cleaning_box, wipe_length); // Wipe the newly loaded filament until the end of the assigned wipe area.
2420
2423 } else
2424 toolchange_Unload(writer, cleaning_box, m_filpar[m_current_tool].material, m_filpar[m_current_tool].nozzle_temperature);
2425
2426 m_depth_traversed += (wipe_depth - nozzle_change_depth);
2427
2428 //BBS
2429 //if (m_set_extruder_trimpot)
2430 // writer.set_extruder_trimpot(550); // Reset the extruder current to a normal value.
2431 writer.speed_override_restore();
2432 writer.feedrate(m_travel_speed * 60.f)
2433 .flush_planner_queue()
2434 .reset_extruder()
2435 .append("; CP TOOLCHANGE END\n"
2436 ";------------------\n"
2437 "\n\n");
2438
2439 // Ask our writer about how much material was consumed:
2441 m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length();
2442
2443 return construct_tcr(writer, false, old_tool, false, true, purge_volume,false);
2444}
void toolchange_Change(WipeTowerWriter &writer, const size_t new_tool, const std::string &new_material)
Definition WipeTower.cpp:2714
void toolchange_Load(WipeTowerWriter &writer, const box_coordinates &cleaning_box)
Definition WipeTower.cpp:2749
bool is_tpu_filament(int filament_id) const
Definition WipeTower.cpp:3324
void toolchange_Wipe(WipeTowerWriter &writer, const box_coordinates &cleaning_box, float wipe_volume)
Definition WipeTower.cpp:2781
void toolchange_Unload(WipeTowerWriter &writer, const box_coordinates &cleaning_box, const std::string &current_material, const int new_temperature)
Definition WipeTower.cpp:2575
Vec2f get_next_pos(const WipeTower::box_coordinates &cleaning_box, float wipe_length, bool solid_toolchange)
Definition WipeTower.cpp:2235
Vec3d pos(const Pt &p)
Definition ReprojectPointsOnMesh.hpp:16

References align_perimeter(), Slic3r::WipeTowerWriter::append(), Slic3r::WipeTowerWriter::comment_with_value(), construct_tcr(), extrusion_flow(), Slic3r::WipeTowerWriter::feedrate(), Slic3r::WipeTowerWriter::flush_planner_queue(), Slic3r::WipeTowerWriter::get_and_reset_used_filament_length(), get_next_pos(), is_first_layer(), is_tpu_filament(), Slic3r::WipeTower::box_coordinates::ld, Slic3r::length(), Slic3r::WipeTower::box_coordinates::lu, m_cur_layer_id, m_current_shape, m_current_tool, m_depth_traversed, m_enable_arc_fitting, m_extrusion_flow, m_filpar, m_first_layer_speed, m_gcode_flavor, m_internal_rotation, m_is_multi_extruder, m_layer_height, m_layer_info, m_nozzle_change_result, m_num_tool_changes, m_perimeter_width, m_travel_speed, m_used_filament_length, m_wipe_tower_depth, m_wipe_tower_width, m_y_shift, m_z_pos, Slic3r::WipeTower::box_coordinates::rd, Slic3r::WipeTowerWriter::rectangle(), Slic3r::GCodeProcessor::reserved_tag(), Slic3r::WipeTowerWriter::reset_extruder(), Slic3r::WipeTower::box_coordinates::ru, Slic3r::WipeTowerWriter::set_extrusion_flow(), set_for_wipe_tower_writer(), Slic3r::WipeTowerWriter::set_initial_position(), Slic3r::WipeTowerWriter::set_initial_tool(), Slic3r::WipeTowerWriter::set_y_shift(), Slic3r::WipeTowerWriter::set_z(), SHAPE_REVERSED, Slic3r::WipeTowerWriter::speed_override(), Slic3r::WipeTowerWriter::speed_override_backup(), Slic3r::WipeTowerWriter::speed_override_restore(), toolchange_Change(), toolchange_Load(), toolchange_Unload(), toolchange_Wipe(), Slic3r::WipeTowerWriter::travel(), Slic3r::GCodeProcessor::Wipe_Tower_End, Slic3r::GCodeProcessor::Wipe_Tower_Start, WipeTowerWriter, Slic3r::WipeTowerWriter::x(), and Slic3r::WipeTowerWriter::y().

Referenced by Slic3r::Print::_make_wipe_tower(), generate_wipe_tower_blocks(), get_wall_skip_points(), plan_toolchange(), and set_toolchange().

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

◆ tool_change_new()

WipeTower::ToolChangeResult Slic3r::WipeTower::tool_change_new ( size_t new_tool,
bool solid_change = false,
bool solid_nozzlechange = false )
3495{
3496 m_nozzle_change_result.gcode.clear();
3497 bool hotend_change = false;
3499 hotend_change = is_same_extruder(m_current_tool, new_tool, m_cur_layer_id);
3500 //If it is the last layer and exceeds the printable height, cancel ramming
3501 if (is_valid_last_layer(m_current_tool, m_cur_layer_id, m_z_pos)) m_nozzle_change_result = ramming(m_current_tool, new_tool, solid_nozzlechange, !hotend_change);
3502 }
3503
3504 size_t old_tool = m_current_tool;
3505 float wipe_depth = 0.f;
3506 float wipe_length = 0.f;
3507 float purge_volume = 0.f;
3508 float nozzle_change_depth = 0.f;
3509 int nozzle_change_line_count = 0;
3510
3511 if (new_tool != (unsigned int) (-1)) {
3512 for (const auto &b : m_layer_info->tool_changes)
3513 if (b.new_tool == new_tool) {
3514 wipe_length = b.wipe_length;
3515 wipe_depth = b.required_depth;
3516 purge_volume = b.purge_volume;
3517 nozzle_change_depth = b.nozzle_change_depth;
3518 break;
3519 }
3520 }
3521 m_current_tool = new_tool;
3522 WipeTowerBlock* block = get_block_by_category(m_filpar[new_tool].category, false);
3523 if (!block) {
3524 assert(block != nullptr);
3525 return WipeTower::ToolChangeResult();
3526 }
3527 m_cur_block = block;
3528 box_coordinates cleaning_box(Vec2f(m_perimeter_width, block->cur_depth), m_wipe_tower_width - 2 * m_perimeter_width, wipe_depth-nozzle_change_depth);
3529
3531 writer.set_extrusion_flow(m_extrusion_flow)
3532 .set_z(m_z_pos)
3533 .set_initial_tool(m_current_tool)
3534 .set_y_shift(m_y_shift + (new_tool != (unsigned int) (-1) && (m_current_shape == SHAPE_REVERSED) ? m_layer_info->depth - m_layer_info->toolchanges_depth() : 0.f))
3535 .append(";--------------------\n"
3536 "; CP TOOLCHANGE START\n")
3537 .comment_with_value(" toolchange #", m_num_tool_changes + 1); // the number is zero-based
3538
3540
3541 if (new_tool != (unsigned) (-1))
3542 writer.append( std::string("; material : " + (m_current_tool < m_filpar.size() ? m_filpar[m_current_tool].material : "(NONE)") + " -> " + m_filpar[new_tool].material + "\n").c_str())
3543 .append(";--------------------\n");
3544
3545 writer.speed_override_backup();
3546 writer.speed_override(100);
3547
3548 // Ram the hot material out of the melt zone, retract the filament into the cooling tubes and let it cool.
3549 if (new_tool != (unsigned int) -1) { // This is not the last change.
3550 Vec2f initial_position = get_next_pos(cleaning_box, wipe_length, solid_toolchange);
3551 writer.set_initial_position(initial_position, m_wipe_tower_width, m_wipe_tower_depth, m_internal_rotation);
3552
3554 toolchange_Unload(writer, cleaning_box, m_filpar[m_current_tool].material,
3555 is_first_layer() ? m_filpar[new_tool].nozzle_temperature_initial_layer : m_filpar[new_tool].nozzle_temperature);
3556 toolchange_Change(writer, new_tool, m_filpar[new_tool].material); // Change the tool, set a speed override for soluble and flex materials.
3557 toolchange_Load(writer, cleaning_box);
3558# if 0
3560 float dy = m_layer_info->extra_spacing * m_nozzle_change_perimeter_width;
3561 if (m_layer_info->extra_spacing < m_tpu_fixed_spacing) {
3563 }
3564
3565 float nozzle_change_speed = 60.0f * m_filpar[new_tool].max_e_speed / m_extrusion_flow;
3566 nozzle_change_speed *= 0.25;
3567
3568 const float &xl = cleaning_box.ld.x();
3569 const float &xr = cleaning_box.rd.x();
3570
3571 Vec2f start_pos = m_nozzle_change_result.origin_start_pos + Vec2f(0, m_nozzle_change_perimeter_width);
3572 bool left_to_right = true;
3573 int tpu_line_count = (nozzle_change_line_count + 2 - 1) / 2; // nozzle_change_line_count / 2 round up
3574
3575 writer.travel(start_pos);
3576
3577 for (int i = 0; true; ++i) {
3578 if (left_to_right)
3579 writer.travel(xr - m_perimeter_width, writer.y(), nozzle_change_speed);
3580 else
3581 writer.travel(xl + m_perimeter_width, writer.y(), nozzle_change_speed);
3582
3583 if (i == tpu_line_count - 1) break;
3584
3585 writer.travel(writer.x(), writer.y() + dy);
3586 left_to_right = !left_to_right;
3587 }
3588 writer.travel(initial_position);
3589 }
3590#endif
3591 toolchange_wipe_new(writer, cleaning_box, wipe_length, solid_toolchange);
3592
3595 } else
3596 toolchange_Unload(writer, cleaning_box, m_filpar[m_current_tool].material, m_filpar[m_current_tool].nozzle_temperature);
3597
3598 block->cur_depth += (wipe_depth - nozzle_change_depth);
3599 block->last_filament_change_id = new_tool;
3600
3601 // BBS
3602 writer.speed_override_restore();
3603 writer.feedrate(m_travel_speed * 60.f)
3604 .flush_planner_queue()
3605 .reset_extruder()
3606 .append("; CP TOOLCHANGE END\n"
3607 ";------------------\n"
3608 "\n\n");
3609
3610 // Ask our writer about how much material was consumed:
3612 m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length();
3613
3614 return construct_tcr(writer, false, old_tool, false, true, purge_volume, solid_toolchange);
3615}
NozzleChangeResult ramming(int old_filament_id, int new_filament_id, bool solid_change=false, bool extruder_change=true)
Definition WipeTower.cpp:3618
void toolchange_wipe_new(WipeTowerWriter &writer, const box_coordinates &cleaning_box, float wipe_length, bool solid_toolchange=false)
Definition WipeTower.cpp:4229

References Slic3r::WipeTowerWriter::append(), Slic3r::WipeTowerWriter::comment_with_value(), construct_tcr(), Slic3r::WipeTower::WipeTowerBlock::cur_depth, Slic3r::WipeTowerWriter::feedrate(), Slic3r::WipeTowerWriter::flush_planner_queue(), Slic3r::WipeTowerWriter::get_and_reset_used_filament_length(), get_block_by_category(), get_next_pos(), is_first_layer(), is_need_ramming(), is_need_reverse_travel(), is_same_extruder(), is_valid_last_layer(), Slic3r::WipeTower::WipeTowerBlock::last_filament_change_id, Slic3r::WipeTower::box_coordinates::ld, m_cur_block, m_cur_layer_id, m_current_shape, m_current_tool, m_enable_arc_fitting, m_extrusion_flow, m_filpar, m_gcode_flavor, m_internal_rotation, m_is_multi_extruder, m_layer_height, m_layer_info, m_nozzle_change_perimeter_width, m_nozzle_change_result, m_num_tool_changes, m_perimeter_width, m_tpu_fixed_spacing, m_travel_speed, m_used_filament_length, m_wipe_tower_depth, m_wipe_tower_width, m_y_shift, m_z_pos, ramming(), Slic3r::WipeTower::box_coordinates::rd, Slic3r::GCodeProcessor::reserved_tag(), Slic3r::WipeTowerWriter::reset_extruder(), Slic3r::WipeTowerWriter::set_extrusion_flow(), set_for_wipe_tower_writer(), Slic3r::WipeTowerWriter::set_initial_position(), Slic3r::WipeTowerWriter::set_initial_tool(), Slic3r::WipeTowerWriter::set_y_shift(), Slic3r::WipeTowerWriter::set_z(), SHAPE_REVERSED, Slic3r::WipeTowerWriter::speed_override(), Slic3r::WipeTowerWriter::speed_override_backup(), Slic3r::WipeTowerWriter::speed_override_restore(), toolchange_Change(), toolchange_Load(), toolchange_Unload(), toolchange_wipe_new(), Slic3r::WipeTowerWriter::travel(), Slic3r::GCodeProcessor::Wipe_Tower_End, Slic3r::GCodeProcessor::Wipe_Tower_Start, WipeTowerWriter, Slic3r::WipeTowerWriter::x(), and Slic3r::WipeTowerWriter::y().

Referenced by generate_new().

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

◆ toolchange_Change()

void Slic3r::WipeTower::toolchange_Change ( WipeTowerWriter & writer,
const size_t new_tool,
const std::string & new_material )
private
2718{
2719 // Ask the writer about how much of the old filament we consumed:
2721 m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length();
2722
2723 // This is where we want to place the custom gcodes. We will use placeholders for this.
2724 // These will be substituted by the actual gcodes when the gcode is generated.
2725 writer.append("[filament_end_gcode]\n");
2726 writer.append("[change_filament_gcode]\n");
2727
2728 // BBS: do travel in GCode::append_tcr() for lazy_lift
2729#if 0
2730 // Travel to where we assume we are. Custom toolchange or some special T code handling (parking extruder etc)
2731 // gcode could have left the extruder somewhere, we cannot just start extruding. We should also inform the
2732 // postprocessor that we absolutely want to have this in the gcode, even if it thought it is the same as before.
2733 Vec2f current_pos = writer.pos_rotated();
2734 writer.feedrate(m_travel_speed * 60.f)
2735 .append(std::string("G1 X") + Slic3r::float_to_string_decimal_point(current_pos.x())
2736 + " Y" + Slic3r::float_to_string_decimal_point(current_pos.y())
2737 + never_skip_tag() + "\n");
2738#endif
2739
2740 // The toolchange Tn command will be inserted later, only in case that the user does
2741 // not provide a custom toolchange gcode.
2742 writer.set_tool(new_tool); // This outputs nothing, the writer just needs to know the tool has changed.
2743 writer.append("[filament_start_gcode]\n");
2744
2745 writer.flush_planner_queue();
2746 m_current_tool = new_tool;
2747}
static const std::string never_skip_tag()
Definition WipeTower.hpp:46

References Slic3r::WipeTowerWriter::append(), Slic3r::WipeTowerWriter::feedrate(), Slic3r::float_to_string_decimal_point(), Slic3r::WipeTowerWriter::flush_planner_queue(), Slic3r::WipeTowerWriter::get_and_reset_used_filament_length(), m_current_tool, m_travel_speed, m_used_filament_length, never_skip_tag(), Slic3r::WipeTowerWriter::pos_rotated(), Slic3r::WipeTowerWriter::set_tool(), and WipeTowerWriter.

Referenced by tool_change(), and tool_change_new().

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

◆ toolchange_Load()

void Slic3r::WipeTower::toolchange_Load ( WipeTowerWriter & writer,
const box_coordinates & cleaning_box )
private
2752{
2753 // BBS: tool load is done in change_filament_gcode
2754#if 0
2755 if (m_semm && (m_parking_pos_retraction != 0 || m_extra_loading_move != 0)) {
2756 float xl = cleaning_box.ld.x() + m_perimeter_width * 0.75f;
2757 float xr = cleaning_box.rd.x() - m_perimeter_width * 0.75f;
2758 float oldx = writer.x(); // the nozzle is in place to do the first wiping moves, we will remember the position
2759
2760 // Load the filament while moving left / right, so the excess material will not create a blob at a single position.
2761 float turning_point = ( oldx-xl < xr-oldx ? xr : xl );
2762 float edist = m_parking_pos_retraction+m_extra_loading_move;
2763
2764 writer.append("; CP TOOLCHANGE LOAD\n")
2765 .suppress_preview()
2766 .load(0.2f * edist, 60.f * m_filpar[m_current_tool].loading_speed_start)
2767 .load_move_x_advanced(turning_point, 0.7f * edist, m_filpar[m_current_tool].loading_speed) // Fast phase
2768 .load_move_x_advanced(oldx, 0.1f * edist, 0.1f * m_filpar[m_current_tool].loading_speed) // Super slow*/
2769
2770 .travel(oldx, writer.y()) // in case last move was shortened to limit x feedrate
2771 .resume_preview();
2772
2773 // Reset the extruder current to the normal value.
2774 if (m_set_extruder_trimpot)
2775 writer.set_extruder_trimpot(550);
2776 }
2777#endif
2778}

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

Referenced by tool_change(), and tool_change_new().

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

◆ toolchange_Unload()

void Slic3r::WipeTower::toolchange_Unload ( WipeTowerWriter & writer,
const box_coordinates & cleaning_box,
const std::string & current_material,
const int new_temperature )
private
2580{
2581 // BBS: toolchange unload is done in change_filament_gcode
2582#if 0
2583 float xl = cleaning_box.ld.x() + 1.f * m_perimeter_width;
2584 float xr = cleaning_box.rd.x() - 1.f * m_perimeter_width;
2585
2586 const float line_width = m_perimeter_width * m_filpar[m_current_tool].ramming_line_width_multiplicator; // desired ramming line thickness
2587 const float y_step = line_width * m_filpar[m_current_tool].ramming_step_multiplicator * m_extra_spacing; // spacing between lines in mm
2588
2589 writer.append("; CP TOOLCHANGE UNLOAD\n")
2590 .change_analyzer_line_width(line_width);
2591
2592 unsigned i = 0; // iterates through ramming_speed
2593 m_left_to_right = true; // current direction of ramming
2594 float remaining = xr - xl ; // keeps track of distance to the next turnaround
2595 float e_done = 0; // measures E move done from each segment
2596
2597 writer.travel(xl, cleaning_box.ld.y() + m_depth_traversed + y_step/2.f ); // move to starting position
2598
2599 // if the ending point of the ram would end up in mid air, align it with the end of the wipe tower:
2600 if (m_layer_info > m_plan.begin() && m_layer_info < m_plan.end() && (m_layer_info-1!=m_plan.begin() || !m_adhesion )) {
2601
2602 // this is y of the center of previous sparse infill border
2603 float sparse_beginning_y = 0.f;
2605 sparse_beginning_y += ((m_layer_info-1)->depth - (m_layer_info-1)->toolchanges_depth())
2606 - ((m_layer_info)->depth-(m_layer_info)->toolchanges_depth()) ;
2607 else
2608 sparse_beginning_y += (m_layer_info-1)->toolchanges_depth() + m_perimeter_width;
2609
2610 float sum_of_depths = 0.f;
2611 for (const auto& tch : m_layer_info->tool_changes) { // let's find this toolchange
2612 if (tch.old_tool == m_current_tool) {
2613 sum_of_depths += tch.ramming_depth;
2614 float ramming_end_y = sum_of_depths;
2615 ramming_end_y -= (y_step/m_extra_spacing-m_perimeter_width) / 2.f; // center of final ramming line
2616
2617 if ( (m_current_shape == SHAPE_REVERSED && ramming_end_y < sparse_beginning_y - 0.5f*m_perimeter_width ) ||
2618 (m_current_shape == SHAPE_NORMAL && ramming_end_y > sparse_beginning_y + 0.5f*m_perimeter_width ) )
2619 {
2620 writer.extrude(xl + tch.first_wipe_line-1.f*m_perimeter_width,writer.y());
2621 remaining -= tch.first_wipe_line-1.f*m_perimeter_width;
2622 }
2623 break;
2624 }
2625 sum_of_depths += tch.required_depth;
2626 }
2627 }
2628
2629 writer.disable_linear_advance();
2630
2631 // now the ramming itself:
2632 while (i < m_filpar[m_current_tool].ramming_speed.size())
2633 {
2634 const float x = volume_to_length(m_filpar[m_current_tool].ramming_speed[i] * 0.25f, line_width, m_layer_height);
2635 const float e = m_filpar[m_current_tool].ramming_speed[i] * 0.25f / filament_area(); // transform volume per sec to E move;
2636 const float dist = std::min(x - e_done, remaining); // distance to travel for either the next 0.25s, or to the next turnaround
2637 const float actual_time = dist/x * 0.25f;
2638 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));
2639 remaining -= dist;
2640
2641 if (remaining < WT_EPSILON) { // we reached a turning point
2642 writer.travel(writer.x(), writer.y() + y_step, 7200);
2644 remaining = xr - xl;
2645 }
2646 e_done += dist; // subtract what was actually done
2647 if (e_done > x - WT_EPSILON) { // current segment finished
2648 ++i;
2649 e_done = 0;
2650 }
2651 }
2652 Vec2f end_of_ramming(writer.x(),writer.y());
2653 writer.change_analyzer_line_width(m_perimeter_width); // so the next lines are not affected by ramming_line_width_multiplier
2654
2655 // Retraction:
2656 float old_x = writer.x();
2657 float turning_point = (!m_left_to_right ? xl : xr );
2658 if (m_semm && (m_cooling_tube_retraction != 0 || m_cooling_tube_length != 0)) {
2659 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
2660 writer.suppress_preview()
2661 .retract(15.f, m_filpar[m_current_tool].unloading_speed_start * 60.f) // feedrate 5000mm/min = 83mm/s
2662 .retract(0.70f * total_retraction_distance, 1.0f * m_filpar[m_current_tool].unloading_speed * 60.f)
2663 .retract(0.20f * total_retraction_distance, 0.5f * m_filpar[m_current_tool].unloading_speed * 60.f)
2664 .retract(0.10f * total_retraction_distance, 0.3f * m_filpar[m_current_tool].unloading_speed * 60.f)
2665 .resume_preview();
2666 }
2667 // Wipe tower should only change temperature with single extruder MM. Otherwise, all temperatures should
2668 // be already set and there is no need to change anything. Also, the temperature could be changed
2669 // for wrong extruder.
2670 if (m_semm) {
2671 if (new_temperature != 0 && (new_temperature != m_old_temperature || is_first_layer()) ) { // Set the extruder temperature, but don't wait.
2672 // 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)
2673 // However, always change temperatures on the first layer (this is to avoid issues with priming lines turned off).
2674 writer.set_extruder_temp(new_temperature, false);
2675 m_old_temperature = new_temperature;
2676 }
2677 }
2678
2679 // Cooling:
2680 const int& number_of_moves = m_filpar[m_current_tool].cooling_moves;
2681 if (number_of_moves > 0) {
2682 const float& initial_speed = m_filpar[m_current_tool].cooling_initial_speed;
2683 const float& final_speed = m_filpar[m_current_tool].cooling_final_speed;
2684
2685 float speed_inc = (final_speed - initial_speed) / (2.f * number_of_moves - 1.f);
2686
2687 writer.suppress_preview()
2688 .travel(writer.x(), writer.y() + y_step);
2689 old_x = writer.x();
2690 turning_point = xr-old_x > old_x-xl ? xr : xl;
2691 for (int i=0; i<number_of_moves; ++i) {
2692 float speed = initial_speed + speed_inc * 2*i;
2693 writer.load_move_x_advanced(turning_point, m_cooling_tube_length, speed);
2694 speed += speed_inc;
2695 writer.load_move_x_advanced(old_x, -m_cooling_tube_length, speed);
2696 }
2697 }
2698
2699 // let's wait is necessary:
2700 writer.wait(m_filpar[m_current_tool].delay);
2701 // we should be at the beginning of the cooling tube again - let's move to parking position:
2702 writer.retract(-m_cooling_tube_length/2.f+m_parking_pos_retraction-m_cooling_tube_retraction, 2000);
2703
2704 // this is to align ramming and future wiping extrusions, so the future y-steps can be uniform from the start:
2705 // the perimeter_width will later be subtracted, it is there to not load while moving over just extruded material
2706 writer.travel(end_of_ramming.x(), end_of_ramming.y() + (y_step/m_extra_spacing-m_perimeter_width) / 2.f + m_perimeter_width, 2400.f);
2707
2708 writer.resume_preview()
2709 .flush_planner_queue();
2710#endif
2711}
int m_old_temperature
Definition WipeTower.hpp:509
T dist(const boost::polygon::point_data< T > &p1, const boost::polygon::point_data< T > &p2)
Definition Geometry.cpp:298

References Slic3r::WipeTowerWriter::append(), Slic3r::WipeTowerWriter::change_analyzer_line_width(), Slic3r::WipeTowerWriter::disable_linear_advance(), Slic3r::Geometry::dist(), Slic3r::WipeTowerWriter::extrude(), filament_area(), Slic3r::WipeTowerWriter::flush_planner_queue(), is_first_layer(), Slic3r::WipeTower::box_coordinates::ld, Slic3r::WipeTowerWriter::load_move_x_advanced(), m_adhesion, m_current_shape, m_current_tool, m_depth_traversed, m_extra_spacing, m_filpar, m_layer_height, m_layer_info, m_left_to_right, m_old_temperature, m_perimeter_width, m_plan, m_semm, Slic3r::WipeTowerWriter::ram(), Slic3r::WipeTower::box_coordinates::rd, Slic3r::WipeTowerWriter::resume_preview(), Slic3r::WipeTowerWriter::retract(), Slic3r::WipeTowerWriter::set_extruder_temp(), SHAPE_NORMAL, SHAPE_REVERSED, Slic3r::WipeTowerWriter::suppress_preview(), Slic3r::WipeTowerWriter::travel(), volume_to_length(), Slic3r::WipeTowerWriter::wait(), WipeTowerWriter, WT_EPSILON, Slic3r::WipeTowerWriter::x(), and Slic3r::WipeTowerWriter::y().

Referenced by tool_change(), and tool_change_new().

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

◆ toolchange_Wipe()

void Slic3r::WipeTower::toolchange_Wipe ( WipeTowerWriter & writer,
const box_coordinates & cleaning_box,
float wipe_volume )
private
2785{
2786 // Increase flow on first layer, slow down print.
2787 writer.set_extrusion_flow(m_extrusion_flow * (is_first_layer() ? m_first_layer_flow_ratio : 1.f))
2788 .append("; CP TOOLCHANGE WIPE\n");
2789
2790 // BBS: add the note for gcode-check, when the flow changed, the width should follow the change
2791 if (is_first_layer()) {
2793 }
2794
2795 const float& xl = cleaning_box.ld.x();
2796 const float& xr = cleaning_box.rd.x();
2797
2798 // Variables x_to_wipe and traversed_x are here to be able to make sure it always wipes at least
2799 // the ordered volume, even if it means violating the box. This can later be removed and simply
2800 // wipe until the end of the assigned area.
2801
2802 float x_to_wipe = wipe_length;
2803 float dy = m_layer_info->extra_spacing * m_perimeter_width;
2804
2805 const float target_speed = is_first_layer() ? std::min(m_first_layer_speed * 60.f, 4800.f) : 4800.f;
2806 float wipe_speed = 0.33f * target_speed;
2807
2808 float start_y = writer.y();
2809
2810#if 0
2811 // if there is less than 2.5*m_perimeter_width to the edge, advance straightaway (there is likely a blob anyway)
2812 if ((m_left_to_right ? xr-writer.x() : writer.x()-xl) < 2.5f*m_perimeter_width) {
2813 writer.travel((m_left_to_right ? xr-m_perimeter_width : xl+m_perimeter_width),writer.y()+dy);
2815 }
2816#endif
2817
2818 m_left_to_right = ((m_cur_layer_id + 3) % 4 >= 2);
2819 bool is_from_up = (m_cur_layer_id % 2 == 1);
2820
2821 // BBS: do not need to move dy
2822#if 0
2823 if (m_depth_traversed != 0)
2824 writer.travel(xl, writer.y() + dy);
2825#endif
2826
2827 bool need_change_flow = false;
2828 // now the wiping itself:
2829 for (int i = 0; true; ++i) {
2830 if (i!=0) {
2831 if (wipe_speed < 0.34f * target_speed) wipe_speed = 0.375f * target_speed;
2832 else if (wipe_speed < 0.377 * target_speed) wipe_speed = 0.458f * target_speed;
2833 else if (wipe_speed < 0.46f * target_speed) wipe_speed = 0.875f * target_speed;
2834 else wipe_speed = std::min(target_speed, wipe_speed + 50.f);
2835 }
2836
2837 // BBS: check the bridging area and use the bridge flow
2838 if (need_change_flow || need_thick_bridge_flow(writer.y())) {
2839 writer.set_extrusion_flow(extrusion_flow(0.2));
2841 need_change_flow = true;
2842 }
2843
2844 if (m_left_to_right)
2845 writer.extrude(xr + wipe_tower_wall_infill_overlap * m_perimeter_width, writer.y(), wipe_speed);
2846 else
2847 writer.extrude(xl - wipe_tower_wall_infill_overlap * m_perimeter_width, writer.y(), wipe_speed);
2848
2849 // BBS: recover the flow in non-bridging area
2850 if (need_change_flow) {
2851 writer.set_extrusion_flow(m_extrusion_flow);
2853 }
2854
2855 if (!is_from_up && (writer.y() - float(EPSILON) > cleaning_box.lu.y()))
2856 break; // in case next line would not fit
2857
2858 if (is_from_up && (writer.y() + float(EPSILON) < cleaning_box.ld.y()))
2859 break;
2860
2861 x_to_wipe -= (xr - xl);
2862 if (x_to_wipe < WT_EPSILON) {
2863 // BBS: Delete some unnecessary travel
2864 //writer.travel(m_left_to_right ? xl + 1.5f*m_perimeter_width : xr - 1.5f*m_perimeter_width, writer.y(), 7200);
2865 break;
2866 }
2867 // stepping to the next line:
2868 if (is_from_up)
2869 writer.extrude(writer.x(), writer.y() - dy);
2870 else
2871 writer.extrude(writer.x(), writer.y() + dy);
2872
2874 }
2875
2876 float end_y = writer.y();
2877
2878 // We may be going back to the model - wipe the nozzle. If this is followed
2879 // by finish_layer, this wipe path will be overwritten.
2880 //writer.add_wipe_point(writer.x(), writer.y())
2881 // .add_wipe_point(writer.x(), writer.y() - dy)
2882 // .add_wipe_point(! m_left_to_right ? m_wipe_tower_width : 0.f, writer.y() - dy);
2883 // BBS: modify the wipe_path after toolchange
2884 writer.add_wipe_point(writer.x(), writer.y())
2885 .add_wipe_point(! m_left_to_right ? m_wipe_tower_width : 0.f, writer.y());
2886
2887 if (m_layer_info != m_plan.end() && m_current_tool != m_layer_info->tool_changes.back().new_tool)
2889
2890 writer.set_extrusion_flow(m_extrusion_flow); // Reset the extrusion flow.
2891 // BBS: add the note for gcode-check when the flow changed
2892 if (is_first_layer()) {
2894 }
2895}
@ Width
Definition GCodeProcessor.hpp:608

References Slic3r::WipeTowerWriter::add_wipe_point(), Slic3r::WipeTowerWriter::append(), EPSILON, Slic3r::WipeTowerWriter::extrude(), extrusion_flow(), Slic3r::float_to_string_decimal_point(), Slic3r::GCodeProcessor::Height, is_first_layer(), Slic3r::WipeTower::box_coordinates::ld, Slic3r::WipeTower::box_coordinates::lu, m_cur_layer_id, m_current_tool, m_depth_traversed, m_extrusion_flow, m_first_layer_flow_ratio, m_first_layer_speed, m_layer_height, m_layer_info, m_left_to_right, m_perimeter_width, m_plan, m_wipe_tower_width, need_thick_bridge_flow(), Slic3r::WipeTower::box_coordinates::rd, Slic3r::GCodeProcessor::reserved_tag(), Slic3r::WipeTowerWriter::set_extrusion_flow(), Slic3r::WipeTowerWriter::travel(), Slic3r::GCodeProcessor::Width, Slic3r::wipe_tower_wall_infill_overlap, WipeTowerWriter, WT_EPSILON, Slic3r::WipeTowerWriter::x(), and Slic3r::WipeTowerWriter::y().

Referenced by tool_change().

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

◆ toolchange_wipe_new()

void Slic3r::WipeTower::toolchange_wipe_new ( WipeTowerWriter & writer,
const box_coordinates & cleaning_box,
float wipe_length,
bool solid_toolchange = false )
4230{
4231 writer.set_extrusion_flow(m_extrusion_flow * (is_first_layer() ? m_first_layer_flow_ratio : 1.f))
4232 // Orca: CP_TOOLCHANGE_WIPE is a standalone tag constant, not an ETags entry
4233 .append(";" + GCodeProcessor::Toolchange_Wipe_Tag + " CT" + std::to_string(solid_tool_toolchange) + " FL" + std::to_string(is_first_layer()) + "\n");
4234 if (!m_nozzle_change_result.gcode.empty())
4235 writer.change_analyzer_line_width(m_perimeter_width);
4236
4237 // BBS: add the note for gcode-check, when the flow changed, the width should follow the change
4238 if (is_first_layer()) {
4240 }
4241
4242 //if (solid_tool_toolchange && m_filpar[m_current_tool].filament_tower_interface_print_temp != m_filpar[m_current_tool].nozzle_temperature)
4243 // writer.append(format_line_M109(m_filpar[m_current_tool].filament_tower_interface_print_temp, m_filament_map[this->m_current_tool] - 1));
4244 //if (solid_tool_toolchange && m_filpar[m_current_tool].filament_tower_interface_pre_extrusion_length != 0)
4245 // writer.retract(-m_filpar[m_current_tool].filament_tower_interface_pre_extrusion_length, 100.f);
4246
4247 float retract_length = m_filpar[m_current_tool].retract_length;
4248 float retract_speed = m_filpar[m_current_tool].retract_speed * 60;
4249 const float &xl = cleaning_box.ld.x();
4250 const float &xr = cleaning_box.rd.x();
4251 bool should_flat_ironging = m_flat_ironing;
4252 bool should_line_ironing = true;
4253 if (!m_contact_ironing && solid_tool_toolchange) {
4254 should_flat_ironging = false;
4255 should_line_ironing = false;
4256 }
4257 bool should_cooling_before_tower = !solid_tool_toolchange;
4258 bool should_cooling_before_object = false;//interface layer heating print tower, then cooling print object
4259 int cooling_begin_line = 2;
4260 float x_to_wipe = wipe_length;
4261 float dy = is_first_layer() ? m_perimeter_width : m_layer_info->extra_spacing * get_block_gap_width(m_current_tool,false);
4262 if (solid_tool_toolchange)
4263 dy = m_perimeter_width;
4264 x_to_wipe = solid_tool_toolchange ? std::numeric_limits<float>::max(): x_to_wipe;
4265 float target_speed = is_first_layer() ? std::min(m_first_layer_speed * 60.f, m_max_speed) : m_max_speed;
4266 target_speed = solid_tool_toolchange ? m_contact_speed : target_speed;
4267 const std::vector<float> WipeSpeedMap{0.33f * target_speed, 0.375f * target_speed, 0.458f * target_speed, 0.875f * target_speed,
4268 std::min(target_speed, 0.875f * target_speed + 50.f)};
4269 float wipe_speed = WipeSpeedMap[0];
4270
4271 m_left_to_right = ((m_cur_layer_id + 3) % 4 >= 2);
4272
4273 bool is_from_up = (m_cur_layer_id % 2 == 1);
4274
4275 auto estimate_time_kernel = [&WipeSpeedMap,&xr,&xl](int n) {
4276 float time = std::numeric_limits<float>::max();
4277 float one_line_len = xr - xl;
4278 if (n <= 1)
4279 time = one_line_len / WipeSpeedMap[0];
4280 else if (n <= 2)
4281 time = one_line_len / WipeSpeedMap[0] + one_line_len / WipeSpeedMap[1];
4282 else if (n <= 3)
4283 time = one_line_len / WipeSpeedMap[0] + one_line_len / WipeSpeedMap[1] + one_line_len / WipeSpeedMap[2];
4284 else if (n <= 4)
4285 time = one_line_len / WipeSpeedMap[0] + one_line_len / WipeSpeedMap[1] + one_line_len / WipeSpeedMap[2] + one_line_len / WipeSpeedMap[3];
4286 else {
4287 time = one_line_len / WipeSpeedMap[0] + one_line_len / WipeSpeedMap[1] + one_line_len / WipeSpeedMap[2] + one_line_len / WipeSpeedMap[3];
4288 time += (n - 4) * one_line_len / WipeSpeedMap[4];
4289 }
4290 return time * 60.f;
4291 };
4292 auto estimate_wipe_time = [&estimate_time_kernel, & cleaning_box, &x_to_wipe, &xr, &xl, &dy, &solid_tool_toolchange](int begin_line) -> float {
4293 int n = std::ceil(x_to_wipe / (xr - xl));
4294 if (solid_tool_toolchange) n = (cleaning_box.lu[1] - cleaning_box.ld[1]) / dy;
4295 float total_time = estimate_time_kernel(n);
4296 float beg_time = n <= 0 ? 0 : estimate_time_kernel(begin_line);
4297 return total_time-beg_time;
4298 };
4299
4300 bool should_heating = m_filpar[m_current_tool].filament_cooling_before_tower > EPSILON && !solid_tool_toolchange && !is_first_layer();
4301 auto add_M104_by_requirement = [&writer, &should_heating, this]() {
4302 if (m_filpar[m_current_tool].filament_cooling_before_tower < EPSILON) return;
4303 if (!should_heating) return;
4304 float target_temp = is_first_layer() ? m_filpar[m_current_tool].nozzle_temperature_initial_layer : m_filpar[m_current_tool].nozzle_temperature;
4305 writer.format_line_M104(target_temp, get_extruder_id(m_current_tool, m_cur_layer_id));
4306 };
4307 float speed_factor = 1.f;
4308 if (should_heating)
4309 {
4310 //No additional heating time is required.
4311 //float estimate_time = estimate_wipe_time(0);
4312 //int extruder_id = m_filament_map[m_current_tool] - 1;
4313 //float heat_time = m_filpar[m_current_tool].filament_cooling_before_tower / m_hotend_heating_rate[extruder_id];
4314 //heat_time /= 2.f;
4315 //speed_factor = estimate_time / (heat_time+estimate_time);
4316 //wipe_speed *= speed_factor;
4317 }
4318 if (should_cooling_before_object) {
4319 int n = (cleaning_box.lu[1] - cleaning_box.ld[1]) / dy;
4320 int extruder_id = get_extruder_id(m_current_tool, m_cur_layer_id);
4321 float cooling_time = (m_filpar[m_current_tool].filament_tower_interface_print_temp - m_filpar[m_current_tool].nozzle_temperature) / at_or_front(m_hotend_cooling_rate, extruder_id);
4322 if (n < 2) {
4323 float estimate_time = estimate_wipe_time(0);
4324 speed_factor = estimate_time > cooling_time? 1: estimate_time / cooling_time;
4325 cooling_begin_line = 0;
4326 } else {
4327 float estimate_time = estimate_wipe_time(2);
4328 speed_factor = estimate_time > cooling_time ? 1 : estimate_time / cooling_time;
4329 cooling_begin_line = 2; //TODO: No slowdown for the first two lines.
4330 }
4331 wipe_speed *= speed_factor;
4332 }
4333
4334
4335 for (int i = 0; true; ++i) {
4336 if (i < WipeSpeedMap.size()) wipe_speed = WipeSpeedMap[i] * speed_factor;
4337
4338 bool need_change_flow = need_thick_bridge_flow(writer.y());
4339 // BBS: check the bridging area and use the bridge flow
4340 if (need_change_flow) {
4341 writer.set_extrusion_flow(extrusion_flow(0.2));
4343 }
4344 float flat_iron_area = m_filpar[m_current_tool].flat_iron_area;
4345 float ironing_length = 3.;
4346
4347 if (should_cooling_before_object && i == cooling_begin_line) {
4348 writer.format_line_M104(m_filpar[m_current_tool].nozzle_temperature, get_extruder_id(m_current_tool, m_cur_layer_id));
4349 }
4350
4351 if (i == 0 && m_use_gap_wall) { // BBS: add ironing after extruding start
4352 if (m_left_to_right) {
4353 if (should_line_ironing) {
4354 float dx = xr + wipe_tower_wall_infill_overlap * m_perimeter_width - writer.pos().x();
4355 if (abs(dx) < ironing_length) ironing_length = abs(dx);
4356 writer.extrude(writer.x() + ironing_length, writer.y(), wipe_speed);
4357 writer.retract(retract_length, retract_speed);
4358 writer.travel(writer.x() - 1.5 * ironing_length, writer.y(), 600.);
4359 if (should_flat_ironging) {
4360 writer.travel(writer.x() + 0.5f * ironing_length, writer.y(), 240.);
4361 Vec2f pos{writer.x() + 1.f * ironing_length, writer.y()};
4362 writer.spiral_flat_ironing(writer.pos(), flat_iron_area, m_perimeter_width, flat_iron_speed);
4363 writer.travel(pos, wipe_speed);
4364 } else
4365 writer.travel(writer.x() + 1.5 * ironing_length, writer.y(), 240.);
4366 writer.retract(-retract_length, retract_speed);
4367 }
4368 add_M104_by_requirement();
4369 writer.extrude(xr + wipe_tower_wall_infill_overlap * m_perimeter_width, writer.y(), wipe_speed);
4370 } else {
4371 if (should_line_ironing) {
4372 float dx = xl - wipe_tower_wall_infill_overlap * m_perimeter_width - writer.pos().x();
4373 if (abs(dx) < ironing_length) ironing_length = abs(dx);
4374 writer.extrude(writer.x() - ironing_length, writer.y(), wipe_speed);
4375 writer.retract(retract_length, retract_speed);
4376 writer.travel(writer.x() + 1.5 * ironing_length, writer.y(), 600.);
4377 if (should_flat_ironging) {
4378 writer.travel(writer.x() - 0.5f * ironing_length, writer.y(), 240.);
4379 Vec2f pos{writer.x() - 1.0f * ironing_length, writer.y()};
4380 writer.spiral_flat_ironing(writer.pos(), flat_iron_area, m_perimeter_width, flat_iron_speed);
4381 writer.travel(pos, wipe_speed);
4382 } else
4383 writer.travel(writer.x() - 1.5 * ironing_length, writer.y(), 240.);
4384 writer.retract(-retract_length, retract_speed);
4385 }
4386 add_M104_by_requirement();
4387 writer.extrude(xl - wipe_tower_wall_infill_overlap * m_perimeter_width, writer.y(), wipe_speed);
4388 }
4389 } else {
4390 if (i == 0) add_M104_by_requirement();
4391 if (m_left_to_right)
4392 writer.extrude(xr + wipe_tower_wall_infill_overlap * m_perimeter_width, writer.y(), wipe_speed);
4393 else
4394 writer.extrude(xl - wipe_tower_wall_infill_overlap * m_perimeter_width, writer.y(), wipe_speed);
4395 }
4396
4397 // BBS: recover the flow in non-bridging area
4398 if (need_change_flow) {
4399 writer.set_extrusion_flow(m_extrusion_flow);
4401 }
4402
4403 if (!is_from_up && (writer.y() + dy - float(EPSILON) >cleaning_box.lu.y() - m_perimeter_width))
4404 break; // in case next line would not fit
4405
4406 if (is_from_up && (writer.y() - dy+ float(EPSILON))<cleaning_box.ld.y()) // Because the top of the clean box cannot have wiring, but the bottom can have wiring.
4407 break;
4408
4409 x_to_wipe -= (xr - xl);
4410 if (x_to_wipe < WT_EPSILON) {
4411 // BBS: Delete some unnecessary travel
4412 // writer.travel(m_left_to_right ? xl + 1.5f*m_perimeter_width : xr - 1.5f*m_perimeter_width, writer.y(), 7200);
4413 break;
4414 }
4415 // stepping to the next line:
4416 if (is_from_up)
4417 writer.extrude(writer.x(), writer.y() - dy);
4418 else
4419 writer.extrude(writer.x(), writer.y() + dy);
4420
4422 }
4423
4424 writer.add_wipe_point(writer.x(), writer.y()).add_wipe_point(!m_left_to_right ? m_wipe_tower_width : 0.f, writer.y());
4425
4426 if (m_layer_info != m_plan.end() && m_current_tool != m_layer_info->tool_changes.back().new_tool) m_left_to_right = !m_left_to_right;
4427
4428 writer.set_extrusion_flow(m_extrusion_flow); // Reset the extrusion flow.
4429 // BBS: add the note for gcode-check when the flow changed
4431}
static const std::string Toolchange_Wipe_Tag
Definition GCodeProcessor.hpp:600
bool m_contact_ironing
Definition WipeTower.hpp:597
float flat_iron_speed
Definition WipeTower.cpp:43

References Slic3r::WipeTowerWriter::add_wipe_point(), Slic3r::WipeTowerWriter::append(), Slic3r::at_or_front(), Slic3r::WipeTowerWriter::change_analyzer_line_width(), EPSILON, Slic3r::WipeTowerWriter::extrude(), extrusion_flow(), Slic3r::flat_iron_speed, Slic3r::float_to_string_decimal_point(), Slic3r::WipeTowerWriter::format_line_M104(), get_block_gap_width(), get_extruder_id(), Slic3r::GCodeProcessor::Height, is_first_layer(), Slic3r::WipeTower::box_coordinates::ld, Slic3r::WipeTower::box_coordinates::lu, m_contact_ironing, m_contact_speed, m_cur_layer_id, m_current_tool, m_extrusion_flow, m_filpar, m_first_layer_flow_ratio, m_first_layer_speed, m_flat_ironing, m_hotend_cooling_rate, m_layer_height, m_layer_info, m_left_to_right, m_max_speed, m_nozzle_change_result, m_perimeter_width, m_plan, m_use_gap_wall, m_wipe_tower_width, need_thick_bridge_flow(), Slic3r::WipeTowerWriter::pos(), Slic3r::WipeTower::box_coordinates::rd, Slic3r::GCodeProcessor::reserved_tag(), Slic3r::WipeTowerWriter::retract(), Slic3r::WipeTowerWriter::set_extrusion_flow(), Slic3r::WipeTowerWriter::spiral_flat_ironing(), Slic3r::GCodeProcessor::Toolchange_Wipe_Tag, Slic3r::WipeTowerWriter::travel(), Slic3r::GCodeProcessor::Width, Slic3r::wipe_tower_wall_infill_overlap, WipeTowerWriter, WT_EPSILON, Slic3r::WipeTowerWriter::x(), and Slic3r::WipeTowerWriter::y().

Referenced by tool_change_new().

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

◆ update_all_layer_depth()

void Slic3r::WipeTower::update_all_layer_depth ( float wipe_tower_depth)
4528{
4529 m_wipe_tower_depth = 0.f;
4530 float start_offset = m_perimeter_width;
4531 float start_depth = start_offset;
4532 for (auto& block : m_wipe_tower_blocks) {
4533 block.depth *= m_extra_spacing;
4534 block.start_depth = start_depth;
4535 start_depth += block.depth;
4536 m_wipe_tower_depth += block.depth;
4537
4538 for (auto& layer_depth : block.layer_depths) {
4539 layer_depth *= m_extra_spacing;
4540 }
4541
4542 for (WipeTowerInfo& plan_info : m_plan) {
4543 plan_info.depth *= m_extra_spacing;
4544 }
4545 }
4546 if (m_wipe_tower_depth > 0)
4547 m_wipe_tower_depth += start_offset;
4548
4550 if (is_approx(m_wipe_tower_depth, 0.f))
4551 m_wipe_tower_depth = wipe_tower_depth;
4552 for (WipeTowerInfo &plan_info : m_plan) {
4553 plan_info.depth = m_wipe_tower_depth;
4554 }
4555 }
4556}

References Slic3r::is_approx(), m_enable_timelapse_print, m_enable_wrapping_detection, m_extra_spacing, m_perimeter_width, m_plan, m_wipe_tower_blocks, and m_wipe_tower_depth.

Referenced by plan_tower_new().

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

◆ volume_to_length()

float Slic3r::WipeTower::volume_to_length ( float volume,
float line_width,
float layer_height ) const
inlineprivate
602 {
603 return std::max(0.f, volume / (layer_height * (line_width - layer_height * (1.f - float(M_PI) / 4.f))));
604 }

References Slic3r::layer_height(), and M_PI.

Referenced by plan_toolchange(), plan_tower_new(), set_toolchange(), and toolchange_Unload().

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

◆ width()

float Slic3r::WipeTower::width ( ) const
inline

◆ WipeTowerWriter

Member Data Documentation

◆ m_accel_to_decel_enable

bool Slic3r::WipeTower::m_accel_to_decel_enable
private

◆ m_accel_to_decel_factor

float Slic3r::WipeTower::m_accel_to_decel_factor
private

◆ m_adhesion

bool Slic3r::WipeTower::m_adhesion = true
private

◆ m_all_layers_depth

std::vector<std::vector<BlockDepthInfo> > Slic3r::WipeTower::m_all_layers_depth

◆ m_bed_bottom_left

Vec2f Slic3r::WipeTower::m_bed_bottom_left
private

Referenced by WipeTower().

◆ []

enum { ... } Slic3r::WipeTower::m_bed_shape

Referenced by WipeTower().

◆ m_bed_width

float Slic3r::WipeTower::m_bed_width
private

Referenced by WipeTower().

◆ m_block_infill_gap_width

std::unordered_map<int, std::pair<float,float> > Slic3r::WipeTower::m_block_infill_gap_width
private

◆ m_bridging

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

◆ m_contact_ironing

bool Slic3r::WipeTower::m_contact_ironing = false
private

Referenced by toolchange_wipe_new().

◆ m_contact_speed

float Slic3r::WipeTower::m_contact_speed = 20 * 60.f
private

Referenced by WipeTower(), and toolchange_wipe_new().

◆ m_cur_block

WipeTowerBlock* Slic3r::WipeTower::m_cur_block {nullptr}
444{nullptr};

Referenced by get_floating_area(), ramming(), and tool_change_new().

◆ m_cur_layer_id

◆ m_current_layer_finished

bool Slic3r::WipeTower::m_current_layer_finished = false
private

◆ m_current_shape

◆ m_current_tool

◆ m_depth_traversed

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

◆ m_enable_arc_fitting

bool Slic3r::WipeTower::m_enable_arc_fitting = true
private

◆ m_enable_timelapse_print

bool Slic3r::WipeTower::m_enable_timelapse_print = false
private

◆ m_enable_tower_interface_features

bool Slic3r::WipeTower::m_enable_tower_interface_features {false}
private

◆ m_enable_wrapping_detection

bool Slic3r::WipeTower::m_enable_wrapping_detection = false
private

◆ m_extra_rib_length

float Slic3r::WipeTower::m_extra_rib_length =0.f
private

Referenced by WipeTower(), and plan_tower_new().

◆ m_extra_spacing

◆ m_extrusion_flow

◆ m_filament_categories

std::vector<int> Slic3r::WipeTower::m_filament_categories

◆ m_filaments_change_length

std::pair<std::vector<double>,std::vector<double> > Slic3r::WipeTower::m_filaments_change_length
private

◆ m_filpar

◆ m_first_layer_flow_ratio

float Slic3r::WipeTower::m_first_layer_flow_ratio
private

◆ m_first_layer_idx

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

◆ m_first_layer_normal_accels

std::vector<unsigned int> Slic3r::WipeTower::m_first_layer_normal_accels
private

◆ m_first_layer_speed

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

◆ m_first_layer_travel_accels

std::vector<unsigned int> Slic3r::WipeTower::m_first_layer_travel_accels
private

◆ m_flat_ironing

bool Slic3r::WipeTower::m_flat_ironing =false
private

Referenced by WipeTower(), and toolchange_wipe_new().

◆ m_gcode_flavor

◆ m_has_filament_switcher

bool Slic3r::WipeTower::m_has_filament_switcher = false
private

◆ m_has_tpu_filament

bool Slic3r::WipeTower::m_has_tpu_filament {false}
private
518{false};

Referenced by has_tpu_filament(), and set_has_tpu_filament().

◆ m_hotend_cooling_rate

std::vector<double> Slic3r::WipeTower::m_hotend_cooling_rate
private

Referenced by WipeTower(), and toolchange_wipe_new().

◆ m_hotend_heating_rate

std::vector<double> Slic3r::WipeTower::m_hotend_heating_rate
private

Referenced by WipeTower().

◆ m_internal_rotation

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

◆ m_is_multi_extruder

bool Slic3r::WipeTower::m_is_multi_extruder {false}
private
519{false};

Referenced by WipeTower(), tool_change(), and tool_change_new().

◆ m_is_multiple_nozzle

bool Slic3r::WipeTower::m_is_multiple_nozzle = false
private

Referenced by WipeTower().

◆ m_last_block_id

int Slic3r::WipeTower::m_last_block_id

◆ m_last_layer_id

std::vector<int> Slic3r::WipeTower::m_last_layer_id
private

◆ m_layer_height

◆ m_layer_info

◆ m_left_to_right

◆ m_max_accels

unsigned int Slic3r::WipeTower::m_max_accels
private

◆ m_max_color_changes

size_t Slic3r::WipeTower::m_max_color_changes = 0
private

Referenced by finished().

◆ m_max_speed

float Slic3r::WipeTower::m_max_speed = 5400.f
private

◆ m_multi_nozzle_group_result

◆ m_need_reverse_travel

bool Slic3r::WipeTower::m_need_reverse_travel {false}
private
528{false};

◆ m_normal_accels

std::vector<unsigned int> Slic3r::WipeTower::m_normal_accels
private

◆ m_nozzle_change_perimeter_width

◆ m_nozzle_change_result

NozzleChangeResult Slic3r::WipeTower::m_nozzle_change_result
private

◆ m_num_layer_changes

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

◆ m_num_tool_changes

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

◆ m_old_temperature

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

Referenced by toolchange_Unload().

◆ m_origin

Vec2f Slic3r::WipeTower::m_origin
private

Referenced by WipeTower().

◆ m_outer_wall

std::map<float,Polylines> Slic3r::WipeTower::m_outer_wall
private

◆ m_perimeter_width

◆ m_physical_extruder_map

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

◆ m_plan

◆ m_print_brim

bool Slic3r::WipeTower::m_print_brim = true
private

unsigned int m_idx_tool_change_in_layer = 0; // Layer change counter in this layer. Counting up to m_max_color_changes.

◆ m_printable_height

std::vector<double> Slic3r::WipeTower::m_printable_height
private

Referenced by WipeTower(), and is_valid_last_layer().

◆ m_rib_length

float Slic3r::WipeTower::m_rib_length =0.f
private

◆ m_rib_offset

Vec2f Slic3r::WipeTower::m_rib_offset {Vec2f(0.f, 0.f)}
private

◆ m_rib_width

float Slic3r::WipeTower::m_rib_width =0.f
private

◆ m_semm

bool Slic3r::WipeTower::m_semm = true
private

◆ m_shared_print_bed

Polygons Slic3r::WipeTower::m_shared_print_bed
private

◆ m_slice_used_filaments

int Slic3r::WipeTower::m_slice_used_filaments = 0
private

Referenced by WipeTower(), and generate_new().

◆ m_sparse_layers_combined

bool Slic3r::WipeTower::m_sparse_layers_combined = false
private

Referenced by WipeTower(), and generate_new().

◆ m_sparse_layers_skipped

bool Slic3r::WipeTower::m_sparse_layers_skipped = false
private

◆ m_tower_framework

bool Slic3r::WipeTower::m_tower_framework {false}
private
527{false};

Referenced by WipeTower(), and generate_wipe_tower_blocks().

◆ m_tpu_fixed_spacing

float Slic3r::WipeTower::m_tpu_fixed_spacing = 2
private

◆ m_travel_accels

std::vector<unsigned int> Slic3r::WipeTower::m_travel_accels
private

◆ m_travel_speed

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

◆ m_use_gap_wall

bool Slic3r::WipeTower::m_use_gap_wall {false}
private

◆ m_use_rib_wall

bool Slic3r::WipeTower::m_use_rib_wall {false}
private

◆ m_used_filament_ids

std::vector<int> Slic3r::WipeTower::m_used_filament_ids

Referenced by set_used_filament_ids().

◆ m_used_filament_length

◆ m_used_fillet

bool Slic3r::WipeTower::m_used_fillet {false}
private
525{false};

Referenced by WipeTower(), and generate_support_wall_new().

◆ m_wall_skip_points

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

◆ m_wipe_tower_blocks

◆ m_wipe_tower_brim_width

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

◆ m_wipe_tower_brim_width_real

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

Referenced by finish_layer_new(), and get_brim_width().

◆ m_wipe_tower_depth

◆ m_wipe_tower_height

float Slic3r::WipeTower::m_wipe_tower_height = 0.f
private

◆ m_wipe_tower_pos

Vec2f Slic3r::WipeTower::m_wipe_tower_pos
private

◆ m_wipe_tower_rotation_angle

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

Referenced by WipeTower().

◆ m_wipe_tower_width

◆ m_wrapping_detection_layers

int Slic3r::WipeTower::m_wrapping_detection_layers = 0
private

Referenced by WipeTower().

◆ m_y_shift

◆ m_z_pos

◆ min_depth_per_height

const std::map< float, float > Slic3r::WipeTower::min_depth_per_height
static
Initial value:
= {
{5.f,5.f}, {100.f, 20.f}, {250.f, 40.f}, {350.f, 60.f}
}

Referenced by get_limit_depth_by_height().

◆ Width_To_Nozzle_Ratio

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

Referenced by set_extruder().

◆ WT_EPSILON


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