2022-07-15 15:37:19 +00:00
|
|
|
#ifndef WipeTower_
|
|
|
|
#define WipeTower_
|
|
|
|
|
|
|
|
#include <cmath>
|
|
|
|
#include <string>
|
|
|
|
#include <sstream>
|
|
|
|
#include <utility>
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
|
|
#include "libslic3r/Point.hpp"
|
2024-12-16 11:41:45 +00:00
|
|
|
#include <unordered_set>
|
2022-07-15 15:37:19 +00:00
|
|
|
|
|
|
|
namespace Slic3r
|
|
|
|
{
|
|
|
|
|
|
|
|
class WipeTowerWriter;
|
|
|
|
class PrintConfig;
|
|
|
|
enum GCodeFlavor : unsigned char;
|
|
|
|
|
|
|
|
|
|
|
|
class WipeTower
|
|
|
|
{
|
|
|
|
public:
|
2025-02-07 09:25:21 +00:00
|
|
|
friend class WipeTowerWriter;
|
2022-07-15 15:37:19 +00:00
|
|
|
static const std::string never_skip_tag() { return "_GCODE_WIPE_TOWER_NEVER_SKIP_TAG"; }
|
|
|
|
|
|
|
|
// WipeTower height to minimum depth map
|
|
|
|
static const std::map<float, float> min_depth_per_height;
|
2025-01-19 02:34:51 +00:00
|
|
|
static float get_limit_depth_by_height(float max_height);
|
2025-01-20 08:20:49 +00:00
|
|
|
static float get_auto_brim_by_height(float max_height);
|
2025-03-04 07:27:12 +00:00
|
|
|
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 Vec2f move_box_inside_box(const BoundingBox &box1, const BoundingBox &box2, int offset = 0);
|
|
|
|
static Polygon rounding_polygon(Polygon &polygon, double rounding = 2., double angle_tol = 30. / 180. * PI);
|
2022-07-15 15:37:19 +00:00
|
|
|
struct Extrusion
|
|
|
|
{
|
|
|
|
Extrusion(const Vec2f &pos, float width, unsigned int tool) : pos(pos), width(width), tool(tool) {}
|
|
|
|
// End position of this extrusion.
|
|
|
|
Vec2f pos;
|
|
|
|
// Width of a squished extrusion, corrected for the roundings of the squished extrusions.
|
|
|
|
// This is left zero if it is a travel move.
|
|
|
|
float width;
|
|
|
|
// Current extruder index.
|
|
|
|
unsigned int tool;
|
|
|
|
};
|
|
|
|
|
2024-07-30 11:25:45 +00:00
|
|
|
struct NozzleChangeResult
|
|
|
|
{
|
|
|
|
std::string gcode;
|
|
|
|
|
2024-12-28 12:27:01 +00:00
|
|
|
Vec2f start_pos; // rotated
|
2024-07-30 11:25:45 +00:00
|
|
|
Vec2f end_pos;
|
|
|
|
|
2024-12-28 12:27:01 +00:00
|
|
|
Vec2f origin_start_pos; // not rotated
|
|
|
|
|
2024-07-30 11:25:45 +00:00
|
|
|
std::vector<Vec2f> wipe_path;
|
|
|
|
};
|
|
|
|
|
2022-07-15 15:37:19 +00:00
|
|
|
struct ToolChangeResult
|
|
|
|
{
|
|
|
|
// Print heigh of this tool change.
|
|
|
|
float print_z;
|
|
|
|
float layer_height;
|
|
|
|
// G-code section to be directly included into the output G-code.
|
|
|
|
std::string gcode;
|
|
|
|
// For path preview.
|
|
|
|
std::vector<Extrusion> extrusions;
|
|
|
|
// Initial position, at which the wipe tower starts its action.
|
|
|
|
// At this position the extruder is loaded and there is no Z-hop applied.
|
|
|
|
Vec2f start_pos;
|
|
|
|
// Last point, at which the normal G-code generator of Slic3r shall continue.
|
|
|
|
// At this position the extruder is loaded and there is no Z-hop applied.
|
|
|
|
Vec2f end_pos;
|
|
|
|
// Time elapsed over this tool change.
|
|
|
|
// This is useful not only for the print time estimation, but also for the control of layer cooling.
|
|
|
|
float elapsed_time;
|
|
|
|
|
|
|
|
// Is this a priming extrusion? (If so, the wipe tower rotation & translation will not be applied later)
|
|
|
|
bool priming;
|
|
|
|
|
2025-01-03 10:02:19 +00:00
|
|
|
bool is_tool_change{false};
|
2025-01-03 04:12:54 +00:00
|
|
|
Vec2f tool_change_start_pos;
|
|
|
|
|
2022-07-15 15:37:19 +00:00
|
|
|
// Pass a polyline so that normal G-code generator can do a wipe for us.
|
|
|
|
// The wipe cannot be done by the wipe tower because it has to pass back
|
|
|
|
// a loaded extruder, so it would have to either do a wipe with no retraction
|
|
|
|
// (leading to https://github.com/prusa3d/PrusaSlicer/issues/2834) or do
|
|
|
|
// an extra retraction-unretraction pair.
|
|
|
|
std::vector<Vec2f> wipe_path;
|
|
|
|
|
|
|
|
// BBS
|
|
|
|
float purge_volume = 0.f;
|
|
|
|
|
|
|
|
// Initial tool
|
|
|
|
int initial_tool;
|
|
|
|
|
|
|
|
// New tool
|
|
|
|
int new_tool;
|
|
|
|
|
|
|
|
// BBS: in bbl filament_change_gcode, toolhead will be moved to the wipe tower automatically.
|
|
|
|
// But if finish_layer_tcr is before tool_change_tcr, we have to travel to the wipe tower before
|
|
|
|
// executing the gcode finish_layer_tcr.
|
|
|
|
bool is_finish_first = false;
|
|
|
|
|
2024-07-30 11:25:45 +00:00
|
|
|
NozzleChangeResult nozzle_change_result;
|
|
|
|
|
2022-07-15 15:37:19 +00:00
|
|
|
// Sum the total length of the extrusion.
|
|
|
|
float total_extrusion_length_in_plane() {
|
|
|
|
float e_length = 0.f;
|
|
|
|
for (size_t i = 1; i < this->extrusions.size(); ++ i) {
|
|
|
|
const Extrusion &e = this->extrusions[i];
|
|
|
|
if (e.width > 0) {
|
|
|
|
Vec2f v = e.pos - (&e - 1)->pos;
|
|
|
|
e_length += v.norm();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return e_length;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct box_coordinates
|
|
|
|
{
|
|
|
|
box_coordinates(float left, float bottom, float width, float height) :
|
|
|
|
ld(left , bottom ),
|
|
|
|
lu(left , bottom + height),
|
|
|
|
rd(left + width, bottom ),
|
|
|
|
ru(left + width, bottom + height) {}
|
|
|
|
box_coordinates(const Vec2f &pos, float width, float height) : box_coordinates(pos(0), pos(1), width, height) {}
|
|
|
|
void translate(const Vec2f &shift) {
|
|
|
|
ld += shift; lu += shift;
|
|
|
|
rd += shift; ru += shift;
|
|
|
|
}
|
|
|
|
void translate(const float dx, const float dy) { translate(Vec2f(dx, dy)); }
|
|
|
|
void expand(const float offset) {
|
|
|
|
ld += Vec2f(- offset, - offset);
|
|
|
|
lu += Vec2f(- offset, offset);
|
|
|
|
rd += Vec2f( offset, - offset);
|
|
|
|
ru += Vec2f( offset, offset);
|
|
|
|
}
|
|
|
|
void expand(const float offset_x, const float offset_y) {
|
|
|
|
ld += Vec2f(- offset_x, - offset_y);
|
|
|
|
lu += Vec2f(- offset_x, offset_y);
|
|
|
|
rd += Vec2f( offset_x, - offset_y);
|
|
|
|
ru += Vec2f( offset_x, offset_y);
|
|
|
|
}
|
|
|
|
Vec2f ld; // left down
|
|
|
|
Vec2f lu; // left upper
|
|
|
|
Vec2f rd; // right lower
|
|
|
|
Vec2f ru; // right upper
|
|
|
|
};
|
|
|
|
|
|
|
|
// Construct ToolChangeResult from current state of WipeTower and WipeTowerWriter.
|
|
|
|
// WipeTowerWriter is moved from !
|
|
|
|
ToolChangeResult construct_tcr(WipeTowerWriter& writer,
|
|
|
|
bool priming,
|
|
|
|
size_t old_tool,
|
|
|
|
bool is_finish,
|
2025-01-03 04:12:54 +00:00
|
|
|
bool is_tool_change,
|
2022-07-15 15:37:19 +00:00
|
|
|
float purge_volume) const;
|
|
|
|
|
2024-12-16 11:41:45 +00:00
|
|
|
ToolChangeResult construct_block_tcr(WipeTowerWriter& writer,
|
|
|
|
bool priming,
|
|
|
|
size_t filament_id,
|
|
|
|
bool is_finish,
|
|
|
|
float purge_volume) const;
|
|
|
|
|
|
|
|
|
2022-07-15 15:37:19 +00:00
|
|
|
// x -- x coordinates of wipe tower in mm ( left bottom corner )
|
|
|
|
// y -- y coordinates of wipe tower in mm ( left bottom corner )
|
|
|
|
// width -- width of wipe tower in mm ( default 60 mm - leave as it is )
|
|
|
|
// wipe_area -- space available for one toolchange in mm
|
|
|
|
// BBS: add partplate logic
|
2025-01-20 03:31:33 +00:00
|
|
|
WipeTower(const PrintConfig& config, int plate_idx, Vec3d plate_origin, size_t initial_tool, const float wipe_tower_height);
|
2022-07-15 15:37:19 +00:00
|
|
|
|
|
|
|
|
|
|
|
// Set the extruder properties.
|
|
|
|
void set_extruder(size_t idx, const PrintConfig& config);
|
|
|
|
|
|
|
|
// Appends into internal structure m_plan containing info about the future wipe tower
|
|
|
|
// to be used before building begins. The entries must be added ordered in z.
|
|
|
|
void plan_toolchange(float z_par, float layer_height_par, unsigned int old_tool, unsigned int new_tool, float wipe_volume = 0.f, float prime_volume = 0.f);
|
|
|
|
|
|
|
|
// Iterates through prepared m_plan, generates ToolChangeResults and appends them to "result"
|
|
|
|
void generate(std::vector<std::vector<ToolChangeResult>> &result);
|
|
|
|
|
2024-12-16 11:41:45 +00:00
|
|
|
WipeTower::ToolChangeResult only_generate_out_wall(bool is_new_mode = false);
|
2025-01-02 09:20:53 +00:00
|
|
|
Polygon generate_support_wall(WipeTowerWriter &writer, const box_coordinates &wt_box, double feedrate, bool first_layer);
|
2025-01-17 08:45:50 +00:00
|
|
|
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);
|
2022-08-15 06:41:28 +00:00
|
|
|
|
2025-01-17 08:45:50 +00:00
|
|
|
Polygon generate_rib_polygon(const box_coordinates &wt_box);
|
2022-07-15 15:37:19 +00:00
|
|
|
float get_depth() const { return m_wipe_tower_depth; }
|
|
|
|
float get_brim_width() const { return m_wipe_tower_brim_width_real; }
|
2025-02-10 07:58:34 +00:00
|
|
|
BoundingBoxf get_bbx() const {
|
2025-02-25 07:51:10 +00:00
|
|
|
if (m_outer_wall.empty()) return BoundingBoxf({Vec2d(0,0)});
|
2025-02-17 03:47:41 +00:00
|
|
|
BoundingBox box = get_extents(m_outer_wall.begin()->second);
|
2025-02-10 07:58:34 +00:00
|
|
|
BoundingBoxf res = BoundingBoxf(unscale(box.min), unscale(box.max));
|
|
|
|
return res;
|
|
|
|
}
|
2025-02-17 03:47:41 +00:00
|
|
|
std::map<float, Polylines> get_outer_wall() const
|
|
|
|
{
|
2025-03-04 07:27:12 +00:00
|
|
|
return m_outer_wall;
|
2025-02-10 07:58:34 +00:00
|
|
|
}
|
2023-04-11 11:36:04 +00:00
|
|
|
float get_height() const { return m_wipe_tower_height; }
|
|
|
|
float get_layer_height() const { return m_layer_height; }
|
2025-03-04 07:27:12 +00:00
|
|
|
float get_rib_length() const { return m_rib_length; }
|
|
|
|
float get_rib_width() const { return m_rib_width; }
|
2022-07-15 15:37:19 +00:00
|
|
|
|
2022-09-15 03:18:29 +00:00
|
|
|
void set_last_layer_extruder_fill(bool extruder_fill) {
|
|
|
|
if (!m_plan.empty()) {
|
|
|
|
m_plan.back().extruder_fill = extruder_fill;
|
|
|
|
}
|
|
|
|
}
|
2022-07-15 15:37:19 +00:00
|
|
|
|
|
|
|
|
|
|
|
// Switch to a next layer.
|
|
|
|
void set_layer(
|
|
|
|
// Print height of this layer.
|
|
|
|
float print_z,
|
|
|
|
// Layer height, used to calculate extrusion the rate.
|
|
|
|
float layer_height,
|
|
|
|
// Maximum number of tool changes on this layer or the layers below.
|
|
|
|
size_t max_tool_changes,
|
|
|
|
// Is this the first layer of the print? In that case print the brim first.
|
|
|
|
bool is_first_layer,
|
|
|
|
// Is this the last layer of the waste tower?
|
|
|
|
bool is_last_layer)
|
|
|
|
{
|
|
|
|
m_z_pos = print_z;
|
|
|
|
m_layer_height = layer_height;
|
|
|
|
m_depth_traversed = 0.f;
|
|
|
|
m_current_layer_finished = false;
|
|
|
|
//m_current_shape = (! is_first_layer && m_current_shape == SHAPE_NORMAL) ? SHAPE_REVERSED : SHAPE_NORMAL;
|
|
|
|
m_current_shape = SHAPE_NORMAL;
|
|
|
|
if (is_first_layer) {
|
|
|
|
m_num_layer_changes = 0;
|
|
|
|
m_num_tool_changes = 0;
|
|
|
|
} else
|
|
|
|
++ m_num_layer_changes;
|
2024-07-30 11:25:45 +00:00
|
|
|
|
2022-07-15 15:37:19 +00:00
|
|
|
// Calculate extrusion flow from desired line width, nozzle diameter, filament diameter and layer_height:
|
|
|
|
m_extrusion_flow = extrusion_flow(layer_height);
|
|
|
|
// Advance m_layer_info iterator, making sure we got it right
|
|
|
|
while (!m_plan.empty() && m_layer_info->z < print_z - WT_EPSILON && m_layer_info+1 != m_plan.end())
|
|
|
|
++m_layer_info;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return the wipe tower position.
|
|
|
|
const Vec2f& position() const { return m_wipe_tower_pos; }
|
|
|
|
// Return the wipe tower width.
|
|
|
|
float width() const { return m_wipe_tower_width; }
|
|
|
|
// The wipe tower is finished, there should be no more tool changes or wipe tower prints.
|
|
|
|
bool finished() const { return m_max_color_changes == 0; }
|
|
|
|
|
|
|
|
// Returns gcode to prime the nozzles at the front edge of the print bed.
|
|
|
|
std::vector<ToolChangeResult> prime(
|
|
|
|
// print_z of the first layer.
|
2024-07-30 11:25:45 +00:00
|
|
|
float initial_layer_print_height,
|
2022-07-15 15:37:19 +00:00
|
|
|
// Extruder indices, in the order to be primed. The last extruder will later print the wipe tower brim, print brim and the object.
|
|
|
|
const std::vector<unsigned int> &tools,
|
|
|
|
// If true, the last priming are will be the same as the other priming areas, and the rest of the wipe will be performed inside the wipe tower.
|
|
|
|
// If false, the last priming are will be large enough to wipe the last extruder sufficiently.
|
|
|
|
bool last_wipe_inside_wipe_tower);
|
|
|
|
|
|
|
|
// Returns gcode for a toolchange and a final print head position.
|
|
|
|
// On the first layer, extrude a brim around the future wipe tower first.
|
|
|
|
// BBS
|
2022-11-07 10:50:07 +00:00
|
|
|
ToolChangeResult tool_change(size_t new_tool, bool extrude_perimeter = false, bool first_toolchange_to_nonsoluble = false);
|
2022-07-15 15:37:19 +00:00
|
|
|
|
2024-07-30 11:25:45 +00:00
|
|
|
NozzleChangeResult nozzle_change(int old_filament_id, int new_filament_id);
|
|
|
|
|
2022-07-15 15:37:19 +00:00
|
|
|
// Fill the unfilled space with a sparse infill.
|
|
|
|
// Call this method only if layer_finished() is false.
|
2022-09-15 03:18:29 +00:00
|
|
|
ToolChangeResult finish_layer(bool extruder_perimeter = true, bool extruder_fill = true);
|
2022-07-15 15:37:19 +00:00
|
|
|
|
2022-11-11 04:15:18 +00:00
|
|
|
// Calculates extrusion flow needed to produce required line width for given layer height
|
|
|
|
float extrusion_flow(float layer_height = -1.f) const // negative layer_height - return current m_extrusion_flow
|
|
|
|
{
|
|
|
|
if (layer_height < 0) return m_extrusion_flow;
|
|
|
|
return layer_height * (m_perimeter_width - layer_height * (1.f - float(M_PI) / 4.f)) / filament_area();
|
|
|
|
}
|
2025-02-14 08:15:17 +00:00
|
|
|
float nozzle_change_extrusion_flow(float layer_height = -1.f) const // negative layer_height - return current m_extrusion_flow
|
|
|
|
{
|
|
|
|
if (layer_height < 0)
|
|
|
|
return m_extrusion_flow;
|
|
|
|
return layer_height * (m_nozzle_change_perimeter_width - layer_height * (1.f - float(M_PI) / 4.f)) / filament_area();
|
|
|
|
}
|
2022-11-11 04:15:18 +00:00
|
|
|
|
|
|
|
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 { return m_extrusion_flow; }
|
|
|
|
|
2022-07-15 15:37:19 +00:00
|
|
|
// Is the current layer finished?
|
|
|
|
bool layer_finished() const {
|
|
|
|
return m_current_layer_finished;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<float> get_used_filament() const { return m_used_filament_length; }
|
|
|
|
int get_number_of_toolchanges() const { return m_num_tool_changes; }
|
|
|
|
|
2024-07-30 11:25:45 +00:00
|
|
|
void set_filament_map(const std::vector<int> &filament_map) { m_filament_map = filament_map; }
|
|
|
|
|
2024-09-04 01:38:16 +00:00
|
|
|
void set_has_tpu_filament(bool has_tpu) { m_has_tpu_filament = has_tpu; }
|
2025-03-14 02:56:33 +00:00
|
|
|
void set_need_reverse_travel() {
|
|
|
|
for (int i = 0; i < m_filpar.size(); i++) {
|
|
|
|
if(m_filpar[i].ramming_travel_time>EPSILON)
|
|
|
|
{
|
|
|
|
m_need_reverse_travel = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-09-04 01:38:16 +00:00
|
|
|
bool has_tpu_filament() const { return m_has_tpu_filament; }
|
|
|
|
|
2022-07-15 15:37:19 +00:00
|
|
|
struct FilamentParameters {
|
|
|
|
std::string material = "PLA";
|
2024-12-16 11:41:45 +00:00
|
|
|
int category;
|
2022-07-15 15:37:19 +00:00
|
|
|
bool is_soluble = false;
|
|
|
|
// BBS
|
|
|
|
bool is_support = false;
|
|
|
|
int nozzle_temperature = 0;
|
|
|
|
int nozzle_temperature_initial_layer = 0;
|
|
|
|
// BBS: remove useless config
|
|
|
|
//float loading_speed = 0.f;
|
|
|
|
//float loading_speed_start = 0.f;
|
|
|
|
//float unloading_speed = 0.f;
|
|
|
|
//float unloading_speed_start = 0.f;
|
|
|
|
//float delay = 0.f ;
|
|
|
|
//int cooling_moves = 0;
|
|
|
|
//float cooling_initial_speed = 0.f;
|
|
|
|
//float cooling_final_speed = 0.f;
|
|
|
|
float ramming_line_width_multiplicator = 1.f;
|
|
|
|
float ramming_step_multiplicator = 1.f;
|
|
|
|
float max_e_speed = std::numeric_limits<float>::max();
|
|
|
|
std::vector<float> ramming_speed;
|
|
|
|
float nozzle_diameter;
|
|
|
|
float filament_area;
|
2025-01-03 07:11:41 +00:00
|
|
|
float retract_length;
|
|
|
|
float retract_speed;
|
2025-01-17 08:45:50 +00:00
|
|
|
float wipe_dist;
|
2025-03-14 02:56:33 +00:00
|
|
|
float max_e_ramming_speed = 0.f;
|
|
|
|
float ramming_travel_time=0.f; //Travel time after ramming
|
|
|
|
std::vector<float> precool_t;//Pre-cooling time, set to 0 to ensure the ramming speed is controlled solely by ramming volumetric speed.
|
|
|
|
std::vector<float> precool_t_first_layer;
|
2022-07-15 15:37:19 +00:00
|
|
|
};
|
|
|
|
|
2024-12-16 11:41:45 +00:00
|
|
|
|
|
|
|
void set_used_filament_ids(const std::vector<int> &used_filament_ids) { m_used_filament_ids = used_filament_ids; };
|
|
|
|
void set_filament_categories(const std::vector<int> & filament_categories) { m_filament_categories = filament_categories;};
|
|
|
|
std::vector<int> m_used_filament_ids;
|
|
|
|
std::vector<int> m_filament_categories;
|
|
|
|
|
|
|
|
struct WipeTowerBlock
|
|
|
|
{
|
|
|
|
int block_id{0};
|
2025-02-11 06:31:27 +00:00
|
|
|
int filament_adhesiveness_category{0};
|
2024-12-16 11:41:45 +00:00
|
|
|
std::vector<float> layer_depths;
|
2025-01-01 04:02:53 +00:00
|
|
|
std::vector<bool> solid_infill;
|
2025-02-11 08:30:02 +00:00
|
|
|
std::vector<float> finish_depth{0}; // the start pos of finish frame for every layer
|
2024-12-16 11:41:45 +00:00
|
|
|
float depth{0};
|
|
|
|
float start_depth{0};
|
|
|
|
float cur_depth{0};
|
|
|
|
int last_filament_change_id{-1};
|
|
|
|
int last_nozzle_change_id{-1};
|
|
|
|
};
|
|
|
|
|
|
|
|
struct BlockDepthInfo
|
|
|
|
{
|
|
|
|
int category{-1};
|
|
|
|
float depth{0};
|
|
|
|
float nozzle_change_depth{0};
|
|
|
|
};
|
|
|
|
|
|
|
|
std::vector<std::vector<BlockDepthInfo>> m_all_layers_depth;
|
|
|
|
std::vector<WipeTowerBlock> m_wipe_tower_blocks;
|
|
|
|
int m_last_block_id;
|
2025-02-11 08:30:02 +00:00
|
|
|
WipeTowerBlock* m_cur_block{nullptr};
|
2024-12-16 11:41:45 +00:00
|
|
|
|
|
|
|
// help function
|
2025-03-06 08:31:00 +00:00
|
|
|
WipeTowerBlock* get_block_by_category(int filament_adhesiveness_category, bool create);
|
2025-02-11 06:31:27 +00:00
|
|
|
void add_depth_to_block(int filament_id, int filament_adhesiveness_category, float depth, bool is_nozzle_change = false);
|
2024-12-16 11:41:45 +00:00
|
|
|
int get_filament_category(int filament_id);
|
|
|
|
bool is_in_same_extruder(int filament_id_1, int filament_id_2);
|
|
|
|
void reset_block_status();
|
|
|
|
int get_wall_filament_for_all_layer();
|
|
|
|
// for generate new wipe tower
|
|
|
|
void generate_new(std::vector<std::vector<WipeTower::ToolChangeResult>> &result);
|
|
|
|
|
|
|
|
void plan_tower_new();
|
|
|
|
void generate_wipe_tower_blocks();
|
2024-12-21 11:54:32 +00:00
|
|
|
void update_all_layer_depth(float wipe_tower_depth);
|
2025-03-19 03:31:48 +00:00
|
|
|
void set_nozzle_last_layer_id();
|
2024-12-16 11:41:45 +00:00
|
|
|
|
2025-02-14 02:28:41 +00:00
|
|
|
ToolChangeResult tool_change_new(size_t new_tool, bool solid_change = false, bool solid_nozzlechange=false);
|
2025-02-12 13:00:15 +00:00
|
|
|
NozzleChangeResult nozzle_change_new(int old_filament_id, int new_filament_id, bool solid_change = false);
|
2024-12-16 11:41:45 +00:00
|
|
|
ToolChangeResult finish_layer_new(bool extrude_perimeter = true, bool extrude_fill = true, bool extrude_fill_wall = true);
|
2025-01-01 04:02:53 +00:00
|
|
|
ToolChangeResult finish_block(const WipeTowerBlock &block, int filament_id, bool extrude_fill = true);
|
2025-02-14 02:28:41 +00:00
|
|
|
ToolChangeResult finish_block_solid(const WipeTowerBlock &block, int filament_id, bool extrude_fill = true ,bool interface_solid =false);
|
2025-02-12 13:00:15 +00:00
|
|
|
void toolchange_wipe_new(WipeTowerWriter &writer, const box_coordinates &cleaning_box, float wipe_length,bool solid_toolchange=false);
|
2025-01-19 02:34:51 +00:00
|
|
|
Vec2f get_rib_offset() const { return m_rib_offset; }
|
2024-12-16 11:41:45 +00:00
|
|
|
|
2022-07-15 15:37:19 +00:00
|
|
|
private:
|
|
|
|
enum wipe_shape // A fill-in direction
|
|
|
|
{
|
|
|
|
SHAPE_NORMAL = 1,
|
|
|
|
SHAPE_REVERSED = -1
|
|
|
|
};
|
|
|
|
|
|
|
|
const float Width_To_Nozzle_Ratio = 1.25f; // desired line width (oval) in multiples of nozzle diameter - may not be actually neccessary to adjust
|
|
|
|
const float WT_EPSILON = 1e-3f;
|
|
|
|
float filament_area() const {
|
|
|
|
return m_filpar[0].filament_area; // all extruders are assumed to have the same filament diameter at this point
|
|
|
|
}
|
|
|
|
|
2022-08-15 06:41:28 +00:00
|
|
|
bool m_enable_timelapse_print = false;
|
2022-07-15 15:37:19 +00:00
|
|
|
bool m_semm = true; // Are we using a single extruder multimaterial printer?
|
|
|
|
Vec2f m_wipe_tower_pos; // Left front corner of the wipe tower in mm.
|
|
|
|
float m_wipe_tower_width; // Width of the wipe tower.
|
|
|
|
float m_wipe_tower_depth = 0.f; // Depth of the wipe tower
|
|
|
|
// BBS
|
|
|
|
float m_wipe_tower_height = 0.f;
|
|
|
|
float m_wipe_tower_brim_width = 0.f; // Width of brim (mm) from config
|
|
|
|
float m_wipe_tower_brim_width_real = 0.f; // Width of brim (mm) after generation
|
|
|
|
float m_wipe_tower_rotation_angle = 0.f; // Wipe tower rotation angle in degrees (with respect to x axis)
|
|
|
|
float m_internal_rotation = 0.f;
|
|
|
|
float m_y_shift = 0.f; // y shift passed to writer
|
|
|
|
float m_z_pos = 0.f; // Current Z position.
|
|
|
|
float m_layer_height = 0.f; // Current layer height.
|
|
|
|
size_t m_max_color_changes = 0; // Maximum number of color changes per layer.
|
|
|
|
int m_old_temperature = -1; // To keep track of what was the last temp that we set (so we don't issue the command when not neccessary)
|
|
|
|
float m_travel_speed = 0.f;
|
|
|
|
float m_first_layer_speed = 0.f;
|
|
|
|
size_t m_first_layer_idx = size_t(-1);
|
2025-03-19 03:31:48 +00:00
|
|
|
std::vector<int> m_last_layer_id;
|
2025-01-17 09:15:12 +00:00
|
|
|
std::vector<double> m_filaments_change_length;
|
2024-07-30 11:25:45 +00:00
|
|
|
size_t m_cur_layer_id;
|
|
|
|
NozzleChangeResult m_nozzle_change_result;
|
|
|
|
std::vector<int> m_filament_map;
|
2024-09-04 01:38:16 +00:00
|
|
|
bool m_has_tpu_filament{false};
|
|
|
|
bool m_is_multi_extruder{false};
|
2025-01-02 13:43:03 +00:00
|
|
|
bool m_use_gap_wall{false};
|
2025-01-17 08:45:50 +00:00
|
|
|
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};
|
2025-01-19 02:34:51 +00:00
|
|
|
Vec2f m_rib_offset{Vec2f(0.f, 0.f)};
|
2025-01-21 07:39:42 +00:00
|
|
|
bool m_tower_framework{false};
|
2025-03-14 02:56:33 +00:00
|
|
|
bool m_need_reverse_travel{false};
|
2024-07-30 11:25:45 +00:00
|
|
|
|
2022-07-15 15:37:19 +00:00
|
|
|
// G-code generator parameters.
|
|
|
|
// BBS: remove useless config
|
|
|
|
//float m_cooling_tube_retraction = 0.f;
|
|
|
|
//float m_cooling_tube_length = 0.f;
|
|
|
|
//float m_parking_pos_retraction = 0.f;
|
|
|
|
//float m_extra_loading_move = 0.f;
|
|
|
|
float m_bridging = 0.f;
|
|
|
|
bool m_no_sparse_layers = false;
|
|
|
|
// BBS: remove useless config
|
|
|
|
//bool m_set_extruder_trimpot = false;
|
|
|
|
bool m_adhesion = true;
|
|
|
|
GCodeFlavor m_gcode_flavor;
|
|
|
|
|
|
|
|
// Bed properties
|
|
|
|
enum {
|
|
|
|
RectangularBed,
|
|
|
|
CircularBed,
|
|
|
|
CustomBed
|
|
|
|
} m_bed_shape;
|
|
|
|
float m_bed_width; // width of the bed bounding box
|
|
|
|
Vec2f m_bed_bottom_left; // bottom-left corner coordinates (for rectangular beds)
|
|
|
|
|
|
|
|
float m_perimeter_width = 0.4f * Width_To_Nozzle_Ratio; // Width of an extrusion line, also a perimeter spacing for 100% infill.
|
2025-02-14 10:28:41 +00:00
|
|
|
float m_nozzle_change_perimeter_width = 0.4f * Width_To_Nozzle_Ratio;
|
2022-07-15 15:37:19 +00:00
|
|
|
float m_extrusion_flow = 0.038f; //0.029f;// Extrusion flow is derived from m_perimeter_width, layer height and filament diameter.
|
|
|
|
|
|
|
|
// Extruder specific parameters.
|
|
|
|
std::vector<FilamentParameters> m_filpar;
|
|
|
|
|
|
|
|
|
|
|
|
// State of the wipe tower generator.
|
|
|
|
unsigned int m_num_layer_changes = 0; // Layer change counter for the output statistics.
|
|
|
|
unsigned int m_num_tool_changes = 0; // Tool change change counter for the output statistics.
|
|
|
|
///unsigned int m_idx_tool_change_in_layer = 0; // Layer change counter in this layer. Counting up to m_max_color_changes.
|
|
|
|
bool m_print_brim = true;
|
|
|
|
// A fill-in direction (positive Y, negative Y) alternates with each layer.
|
|
|
|
wipe_shape m_current_shape = SHAPE_NORMAL;
|
|
|
|
size_t m_current_tool = 0;
|
|
|
|
// BBS
|
|
|
|
//const std::vector<std::vector<float>> wipe_volumes;
|
|
|
|
|
|
|
|
float m_depth_traversed = 0.f; // Current y position at the wipe tower.
|
|
|
|
bool m_current_layer_finished = false;
|
|
|
|
bool m_left_to_right = true;
|
|
|
|
float m_extra_spacing = 1.f;
|
2024-12-16 11:41:45 +00:00
|
|
|
float m_tpu_fixed_spacing = 2;
|
2025-03-14 02:56:33 +00:00
|
|
|
float m_max_speed = 5400.f; // the maximum printing speed on the prime tower.
|
2025-01-17 08:45:50 +00:00
|
|
|
std::vector<Vec2f> m_wall_skip_points;
|
2025-02-17 03:47:41 +00:00
|
|
|
std::map<float,Polylines> m_outer_wall;
|
2025-03-19 03:31:48 +00:00
|
|
|
std::vector<double> m_printable_height;
|
2022-07-15 15:37:19 +00:00
|
|
|
bool is_first_layer() const { return size_t(m_layer_info - m_plan.begin()) == m_first_layer_idx; }
|
2025-03-19 03:31:48 +00:00
|
|
|
bool is_valid_last_layer(int tool) const;
|
2022-07-15 15:37:19 +00:00
|
|
|
|
|
|
|
// Calculates length of extrusion line to extrude given volume
|
|
|
|
float volume_to_length(float volume, float line_width, float layer_height) const {
|
|
|
|
return std::max(0.f, volume / (layer_height * (line_width - layer_height * (1.f - float(M_PI) / 4.f))));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Calculates depth for all layers and propagates them downwards
|
|
|
|
void plan_tower();
|
|
|
|
|
|
|
|
// Goes through m_plan and recalculates depths and width of the WT to make it exactly square - experimental
|
|
|
|
void make_wipe_tower_square();
|
|
|
|
|
2024-07-30 11:25:45 +00:00
|
|
|
Vec2f get_next_pos(const WipeTower::box_coordinates &cleaning_box, float wipe_length);
|
|
|
|
|
2022-07-15 15:37:19 +00:00
|
|
|
// Goes through m_plan, calculates border and finish_layer extrusions and subtracts them from last wipe
|
|
|
|
void save_on_last_wipe();
|
|
|
|
|
2024-09-04 01:38:16 +00:00
|
|
|
bool is_tpu_filament(int filament_id) const;
|
2025-03-14 02:56:33 +00:00
|
|
|
bool is_need_reverse_travel(int filament) const;
|
2022-07-15 15:37:19 +00:00
|
|
|
// BBS
|
|
|
|
box_coordinates align_perimeter(const box_coordinates& perimeter_box);
|
|
|
|
|
|
|
|
|
|
|
|
// to store information about tool changes for a given layer
|
|
|
|
struct WipeTowerInfo{
|
|
|
|
struct ToolChange {
|
|
|
|
size_t old_tool;
|
|
|
|
size_t new_tool;
|
|
|
|
float required_depth;
|
|
|
|
float ramming_depth;
|
|
|
|
float first_wipe_line;
|
|
|
|
float wipe_volume;
|
|
|
|
float wipe_length;
|
2024-07-30 11:25:45 +00:00
|
|
|
float nozzle_change_depth{0};
|
2022-07-15 15:37:19 +00:00
|
|
|
// BBS
|
|
|
|
float purge_volume;
|
|
|
|
ToolChange(size_t old, size_t newtool, float depth=0.f, float ramming_depth=0.f, float fwl=0.f, float wv=0.f, float wl = 0, float pv = 0)
|
|
|
|
: old_tool{ old }, new_tool{ newtool }, required_depth{ depth }, ramming_depth{ ramming_depth }, first_wipe_line{ fwl }, wipe_volume{ wv }, wipe_length{ wl }, purge_volume{ pv } {}
|
|
|
|
};
|
|
|
|
float z; // z position of the layer
|
|
|
|
float height; // layer height
|
|
|
|
float depth; // depth of the layer based on all layers above
|
|
|
|
float extra_spacing;
|
2022-09-15 03:18:29 +00:00
|
|
|
bool extruder_fill{true};
|
2022-07-15 15:37:19 +00:00
|
|
|
float toolchanges_depth() const { float sum = 0.f; for (const auto &a : tool_changes) sum += a.required_depth; return sum; }
|
|
|
|
|
|
|
|
std::vector<ToolChange> tool_changes;
|
|
|
|
|
|
|
|
WipeTowerInfo(float z_par, float layer_height_par)
|
|
|
|
: z{z_par}, height{layer_height_par}, depth{0}, extra_spacing{1.f} {}
|
|
|
|
};
|
|
|
|
|
|
|
|
std::vector<WipeTowerInfo> m_plan; // Stores information about all layers and toolchanges for the future wipe tower (filled by plan_toolchange(...))
|
|
|
|
std::vector<WipeTowerInfo>::iterator m_layer_info = m_plan.end();
|
|
|
|
|
|
|
|
// Stores information about used filament length per extruder:
|
|
|
|
std::vector<float> m_used_filament_length;
|
|
|
|
|
|
|
|
// BBS: consider both soluable and support properties
|
|
|
|
// Return index of first toolchange that switches to non-soluble extruder
|
|
|
|
// ot -1 if there is no such toolchange.
|
|
|
|
int first_toolchange_to_nonsoluble_nonsupport(
|
|
|
|
const std::vector<WipeTowerInfo::ToolChange>& tool_changes) const;
|
|
|
|
|
|
|
|
void toolchange_Unload(
|
|
|
|
WipeTowerWriter &writer,
|
2024-07-30 11:25:45 +00:00
|
|
|
const box_coordinates &cleaning_box,
|
2022-07-15 15:37:19 +00:00
|
|
|
const std::string& current_material,
|
|
|
|
const int new_temperature);
|
|
|
|
|
|
|
|
void toolchange_Change(
|
|
|
|
WipeTowerWriter &writer,
|
|
|
|
const size_t new_tool,
|
|
|
|
const std::string& new_material);
|
2024-07-30 11:25:45 +00:00
|
|
|
|
2022-07-15 15:37:19 +00:00
|
|
|
void toolchange_Load(
|
|
|
|
WipeTowerWriter &writer,
|
|
|
|
const box_coordinates &cleaning_box);
|
2024-07-30 11:25:45 +00:00
|
|
|
|
2022-07-15 15:37:19 +00:00
|
|
|
void toolchange_Wipe(
|
|
|
|
WipeTowerWriter &writer,
|
|
|
|
const box_coordinates &cleaning_box,
|
|
|
|
float wipe_volume);
|
2025-01-02 09:20:53 +00:00
|
|
|
void get_wall_skip_points(const WipeTowerInfo &layer);
|
2025-03-14 02:56:33 +00:00
|
|
|
ToolChangeResult merge_tcr(ToolChangeResult &first, ToolChangeResult &second);
|
2022-07-15 15:37:19 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} // namespace Slic3r
|
|
|
|
|
2024-07-30 11:25:45 +00:00
|
|
|
#endif // WipeTowerPrusaMM_hpp_
|