mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-08-09 23:05:04 -06:00
Merge remote-tracking branch 'origin/master' into feature_arrange_with_libnest2d
This commit is contained in:
commit
3c32a7c3db
29 changed files with 540 additions and 105 deletions
|
@ -167,6 +167,18 @@ std::string WipeTowerIntegration::append_tcr(GCode &gcodegen, const WipeTower::T
|
|||
{
|
||||
std::string gcode;
|
||||
|
||||
// Toolchangeresult.gcode assumes the wipe tower corner is at the origin
|
||||
// We want to rotate and shift all extrusions (gcode postprocessing) and starting and ending position
|
||||
float alpha = m_wipe_tower_rotation/180.f * M_PI;
|
||||
WipeTower::xy start_pos = tcr.start_pos;
|
||||
WipeTower::xy end_pos = tcr.end_pos;
|
||||
start_pos.rotate(alpha);
|
||||
start_pos.translate(m_wipe_tower_pos);
|
||||
end_pos.rotate(alpha);
|
||||
end_pos.translate(m_wipe_tower_pos);
|
||||
std::string tcr_rotated_gcode = rotate_wipe_tower_moves(tcr.gcode, tcr.start_pos, m_wipe_tower_pos, alpha);
|
||||
|
||||
|
||||
// Disable linear advance for the wipe tower operations.
|
||||
gcode += "M900 K0\n";
|
||||
// Move over the wipe tower.
|
||||
|
@ -174,14 +186,14 @@ std::string WipeTowerIntegration::append_tcr(GCode &gcodegen, const WipeTower::T
|
|||
gcode += gcodegen.retract(true);
|
||||
gcodegen.m_avoid_crossing_perimeters.use_external_mp_once = true;
|
||||
gcode += gcodegen.travel_to(
|
||||
wipe_tower_point_to_object_point(gcodegen, tcr.start_pos),
|
||||
wipe_tower_point_to_object_point(gcodegen, start_pos),
|
||||
erMixed,
|
||||
"Travel to a Wipe Tower");
|
||||
gcode += gcodegen.unretract();
|
||||
|
||||
// Let the tool change be executed by the wipe tower class.
|
||||
// Inform the G-code writer about the changes done behind its back.
|
||||
gcode += tcr.gcode;
|
||||
gcode += tcr_rotated_gcode;
|
||||
// Let the m_writer know the current extruder_id, but ignore the generated G-code.
|
||||
if (new_extruder_id >= 0 && gcodegen.writer().need_toolchange(new_extruder_id))
|
||||
gcodegen.writer().toolchange(new_extruder_id);
|
||||
|
@ -195,18 +207,18 @@ std::string WipeTowerIntegration::append_tcr(GCode &gcodegen, const WipeTower::T
|
|||
check_add_eol(gcode);
|
||||
}
|
||||
// A phony move to the end position at the wipe tower.
|
||||
gcodegen.writer().travel_to_xy(Pointf(tcr.end_pos.x, tcr.end_pos.y));
|
||||
gcodegen.set_last_pos(wipe_tower_point_to_object_point(gcodegen, tcr.end_pos));
|
||||
gcodegen.writer().travel_to_xy(Pointf(end_pos.x, end_pos.y));
|
||||
gcodegen.set_last_pos(wipe_tower_point_to_object_point(gcodegen, end_pos));
|
||||
|
||||
// Prepare a future wipe.
|
||||
gcodegen.m_wipe.path.points.clear();
|
||||
if (new_extruder_id >= 0) {
|
||||
// Start the wipe at the current position.
|
||||
gcodegen.m_wipe.path.points.emplace_back(wipe_tower_point_to_object_point(gcodegen, tcr.end_pos));
|
||||
gcodegen.m_wipe.path.points.emplace_back(wipe_tower_point_to_object_point(gcodegen, end_pos));
|
||||
// Wipe end point: Wipe direction away from the closer tower edge to the further tower edge.
|
||||
gcodegen.m_wipe.path.points.emplace_back(wipe_tower_point_to_object_point(gcodegen,
|
||||
WipeTower::xy((std::abs(m_left - tcr.end_pos.x) < std::abs(m_right - tcr.end_pos.x)) ? m_right : m_left,
|
||||
tcr.end_pos.y)));
|
||||
WipeTower::xy((std::abs(m_left - end_pos.x) < std::abs(m_right - end_pos.x)) ? m_right : m_left,
|
||||
end_pos.y)));
|
||||
}
|
||||
|
||||
// Let the planner know we are traveling between objects.
|
||||
|
@ -214,6 +226,57 @@ std::string WipeTowerIntegration::append_tcr(GCode &gcodegen, const WipeTower::T
|
|||
return gcode;
|
||||
}
|
||||
|
||||
// This function postprocesses gcode_original, rotates and moves all G1 extrusions and returns resulting gcode
|
||||
// Starting position has to be supplied explicitely (otherwise it would fail in case first G1 command only contained one coordinate)
|
||||
std::string WipeTowerIntegration::rotate_wipe_tower_moves(const std::string& gcode_original, const WipeTower::xy& start_pos, const WipeTower::xy& translation, float angle) const
|
||||
{
|
||||
std::istringstream gcode_str(gcode_original);
|
||||
std::string gcode_out;
|
||||
std::string line;
|
||||
WipeTower::xy pos = start_pos;
|
||||
WipeTower::xy transformed_pos;
|
||||
WipeTower::xy old_pos(-1000.1f, -1000.1f);
|
||||
|
||||
while (gcode_str) {
|
||||
std::getline(gcode_str, line); // we read the gcode line by line
|
||||
if (line.find("G1 ") == 0) {
|
||||
std::ostringstream line_out;
|
||||
std::istringstream line_str(line);
|
||||
line_str >> std::noskipws; // don't skip whitespace
|
||||
char ch = 0;
|
||||
while (line_str >> ch) {
|
||||
if (ch == 'X')
|
||||
line_str >> pos.x;
|
||||
else
|
||||
if (ch == 'Y')
|
||||
line_str >> pos.y;
|
||||
else
|
||||
line_out << ch;
|
||||
}
|
||||
|
||||
transformed_pos = pos;
|
||||
transformed_pos.rotate(angle);
|
||||
transformed_pos.translate(translation);
|
||||
|
||||
if (transformed_pos != old_pos) {
|
||||
line = line_out.str();
|
||||
char buf[2048] = "G1";
|
||||
if (transformed_pos.x != old_pos.x)
|
||||
sprintf(buf + strlen(buf), " X%.3f", transformed_pos.x);
|
||||
if (transformed_pos.y != old_pos.y)
|
||||
sprintf(buf + strlen(buf), " Y%.3f", transformed_pos.y);
|
||||
|
||||
line.replace(line.find("G1 "), 3, buf);
|
||||
old_pos = transformed_pos;
|
||||
}
|
||||
}
|
||||
gcode_out += line + "\n";
|
||||
}
|
||||
return gcode_out;
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::string WipeTowerIntegration::prime(GCode &gcodegen)
|
||||
{
|
||||
assert(m_layer_idx == 0);
|
||||
|
@ -377,10 +440,9 @@ void GCode::do_export(Print *print, const char *path, GCodePreviewData *preview_
|
|||
}
|
||||
fclose(file);
|
||||
|
||||
if (print->config.gcode_flavor.value == gcfMarlin)
|
||||
if (print->config.remaining_times.value)
|
||||
{
|
||||
m_normal_time_estimator.post_process_remaining_times(path_tmp, 60.0f);
|
||||
|
||||
if (m_silent_time_estimator_enabled)
|
||||
m_silent_time_estimator.post_process_remaining_times(path_tmp, 60.0f);
|
||||
}
|
||||
|
@ -462,8 +524,13 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
|
|||
m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Y, print.config.machine_max_jerk_y.values[1]);
|
||||
m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::Z, print.config.machine_max_jerk_z.values[1]);
|
||||
m_silent_time_estimator.set_axis_max_jerk(GCodeTimeEstimator::E, print.config.machine_max_jerk_e.values[1]);
|
||||
m_silent_time_estimator.set_filament_load_times(print.config.filament_load_time.values);
|
||||
m_silent_time_estimator.set_filament_unload_times(print.config.filament_unload_time.values);
|
||||
}
|
||||
}
|
||||
// Filament load / unload times are not specific to a firmware flavor. Let anybody use it if they find it useful.
|
||||
m_normal_time_estimator.set_filament_load_times(print.config.filament_load_time.values);
|
||||
m_normal_time_estimator.set_filament_unload_times(print.config.filament_unload_time.values);
|
||||
|
||||
// resets analyzer
|
||||
m_analyzer.reset();
|
||||
|
@ -1012,9 +1079,10 @@ void GCode::print_machine_envelope(FILE *file, Print &print)
|
|||
int(print.config.machine_max_feedrate_y.values.front() + 0.5),
|
||||
int(print.config.machine_max_feedrate_z.values.front() + 0.5),
|
||||
int(print.config.machine_max_feedrate_e.values.front() + 0.5));
|
||||
fprintf(file, "M204 S%d T%d ; sets acceleration (S) and retract acceleration (T), mm/sec^2\n",
|
||||
fprintf(file, "M204 P%d R%d T%d ; sets acceleration (P, T) and retract acceleration (R), mm/sec^2\n",
|
||||
int(print.config.machine_max_acceleration_extruding.values.front() + 0.5),
|
||||
int(print.config.machine_max_acceleration_retracting.values.front() + 0.5));
|
||||
int(print.config.machine_max_acceleration_retracting.values.front() + 0.5),
|
||||
int(print.config.machine_max_acceleration_extruding.values.front() + 0.5));
|
||||
fprintf(file, "M205 X%.2lf Y%.2lf Z%.2lf E%.2lf ; sets the jerk limits, mm/sec\n",
|
||||
print.config.machine_max_jerk_x.values.front(),
|
||||
print.config.machine_max_jerk_y.values.front(),
|
||||
|
|
|
@ -83,8 +83,10 @@ public:
|
|||
const WipeTower::ToolChangeResult &priming,
|
||||
const std::vector<std::vector<WipeTower::ToolChangeResult>> &tool_changes,
|
||||
const WipeTower::ToolChangeResult &final_purge) :
|
||||
m_left(float(print_config.wipe_tower_x.value)),
|
||||
m_right(float(print_config.wipe_tower_x.value + print_config.wipe_tower_width.value)),
|
||||
m_left(/*float(print_config.wipe_tower_x.value)*/ 0.f),
|
||||
m_right(float(/*print_config.wipe_tower_x.value +*/ print_config.wipe_tower_width.value)),
|
||||
m_wipe_tower_pos(float(print_config.wipe_tower_x.value), float(print_config.wipe_tower_y.value)),
|
||||
m_wipe_tower_rotation(float(print_config.wipe_tower_rotation_angle)),
|
||||
m_priming(priming),
|
||||
m_tool_changes(tool_changes),
|
||||
m_final_purge(final_purge),
|
||||
|
@ -101,9 +103,14 @@ private:
|
|||
WipeTowerIntegration& operator=(const WipeTowerIntegration&);
|
||||
std::string append_tcr(GCode &gcodegen, const WipeTower::ToolChangeResult &tcr, int new_extruder_id) const;
|
||||
|
||||
// Postprocesses gcode: rotates and moves all G1 extrusions and returns result
|
||||
std::string rotate_wipe_tower_moves(const std::string& gcode_original, const WipeTower::xy& start_pos, const WipeTower::xy& translation, float angle) const;
|
||||
|
||||
// Left / right edges of the wipe tower, for the planning of wipe moves.
|
||||
const float m_left;
|
||||
const float m_right;
|
||||
const WipeTower::xy m_wipe_tower_pos;
|
||||
const float m_wipe_tower_rotation;
|
||||
// Reference to cached values at the Printer class.
|
||||
const WipeTower::ToolChangeResult &m_priming;
|
||||
const std::vector<std::vector<WipeTower::ToolChangeResult>> &m_tool_changes;
|
||||
|
@ -112,6 +119,7 @@ private:
|
|||
int m_layer_idx;
|
||||
int m_tool_change_idx;
|
||||
bool m_brim_done;
|
||||
bool i_have_brim = false;
|
||||
};
|
||||
|
||||
class GCode {
|
||||
|
|
|
@ -134,6 +134,11 @@ BoundingBoxf get_print_object_extrusions_extents(const PrintObject &print_object
|
|||
// The projection does not contain the priming regions.
|
||||
BoundingBoxf get_wipe_tower_extrusions_extents(const Print &print, const coordf_t max_print_z)
|
||||
{
|
||||
// Wipe tower extrusions are saved as if the tower was at the origin with no rotation
|
||||
// We need to get position and angle of the wipe tower to transform them to actual position.
|
||||
Pointf wipe_tower_pos(print.config.wipe_tower_x.value, print.config.wipe_tower_y.value);
|
||||
float wipe_tower_angle = print.config.wipe_tower_rotation_angle.value;
|
||||
|
||||
BoundingBoxf bbox;
|
||||
for (const std::vector<WipeTower::ToolChangeResult> &tool_changes : print.m_wipe_tower_tool_changes) {
|
||||
if (! tool_changes.empty() && tool_changes.front().print_z > max_print_z)
|
||||
|
@ -144,6 +149,11 @@ BoundingBoxf get_wipe_tower_extrusions_extents(const Print &print, const coordf_
|
|||
if (e.width > 0) {
|
||||
Pointf p1((&e - 1)->pos.x, (&e - 1)->pos.y);
|
||||
Pointf p2(e.pos.x, e.pos.y);
|
||||
p1.rotate(wipe_tower_angle);
|
||||
p1.translate(wipe_tower_pos);
|
||||
p2.rotate(wipe_tower_angle);
|
||||
p2.translate(wipe_tower_pos);
|
||||
|
||||
bbox.merge(p1);
|
||||
coordf_t radius = 0.5 * e.width;
|
||||
bbox.min.x = std::min(bbox.min.x, std::min(p1.x, p2.x) - radius);
|
||||
|
|
|
@ -25,18 +25,30 @@ public:
|
|||
bool operator==(const xy &rhs) const { return x == rhs.x && y == rhs.y; }
|
||||
bool operator!=(const xy &rhs) const { return x != rhs.x || y != rhs.y; }
|
||||
|
||||
// Rotate the point around given point about given angle (in degrees)
|
||||
// shifts the result so that point of rotation is in the middle of the tower
|
||||
xy rotate(const xy& origin, float width, float depth, float angle) const {
|
||||
// Rotate the point around center of the wipe tower about given angle (in degrees)
|
||||
xy rotate(float width, float depth, float angle) const {
|
||||
xy out(0,0);
|
||||
float temp_x = x - width / 2.f;
|
||||
float temp_y = y - depth / 2.f;
|
||||
angle *= M_PI/180.;
|
||||
out.x += (temp_x - origin.x) * cos(angle) - (temp_y - origin.y) * sin(angle);
|
||||
out.y += (temp_x - origin.x) * sin(angle) + (temp_y - origin.y) * cos(angle);
|
||||
return out + origin;
|
||||
out.x += temp_x * cos(angle) - temp_y * sin(angle) + width / 2.f;
|
||||
out.y += temp_x * sin(angle) + temp_y * cos(angle) + depth / 2.f;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
// Rotate the point around origin about given angle in degrees
|
||||
void rotate(float angle) {
|
||||
float temp_x = x * cos(angle) - y * sin(angle);
|
||||
y = x * sin(angle) + y * cos(angle);
|
||||
x = temp_x;
|
||||
}
|
||||
|
||||
void translate(const xy& vect) {
|
||||
x += vect.x;
|
||||
y += vect.y;
|
||||
}
|
||||
|
||||
float x;
|
||||
float y;
|
||||
};
|
||||
|
@ -104,6 +116,9 @@ public:
|
|||
// 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;
|
||||
|
||||
// Sum the total length of the extrusion.
|
||||
float total_extrusion_length_in_plane() {
|
||||
float e_length = 0.f;
|
||||
|
|
|
@ -5,7 +5,7 @@ TODO LIST
|
|||
|
||||
1. cooling moves - DONE
|
||||
2. account for perimeter and finish_layer extrusions and subtract it from last wipe - DONE
|
||||
3. priming extrusions (last wipe must clear the color)
|
||||
3. priming extrusions (last wipe must clear the color) - DONE
|
||||
4. Peter's wipe tower - layer's are not exactly square
|
||||
5. Peter's wipe tower - variable width for higher levels
|
||||
6. Peter's wipe tower - make sure it is not too sparse (apply max_bridge_distance and make last wipe longer)
|
||||
|
@ -17,7 +17,6 @@ TODO LIST
|
|||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <numeric>
|
||||
|
@ -68,8 +67,11 @@ public:
|
|||
return *this;
|
||||
}
|
||||
|
||||
Writer& set_initial_position(const WipeTower::xy &pos) {
|
||||
m_start_pos = WipeTower::xy(pos,0.f,m_y_shift).rotate(m_wipe_tower_pos, m_wipe_tower_width, m_wipe_tower_depth, m_angle_deg);
|
||||
Writer& set_initial_position(const WipeTower::xy &pos, float width = 0.f, float depth = 0.f, float internal_angle = 0.f) {
|
||||
m_wipe_tower_width = width;
|
||||
m_wipe_tower_depth = depth;
|
||||
m_internal_angle = internal_angle;
|
||||
m_start_pos = WipeTower::xy(pos,0.f,m_y_shift).rotate(m_wipe_tower_width, m_wipe_tower_depth, m_internal_angle);
|
||||
m_current_pos = pos;
|
||||
return *this;
|
||||
}
|
||||
|
@ -81,9 +83,6 @@ public:
|
|||
|
||||
Writer& set_extrusion_flow(float flow)
|
||||
{ m_extrusion_flow = flow; return *this; }
|
||||
|
||||
Writer& set_rotation(WipeTower::xy& pos, float width, float depth, float angle)
|
||||
{ m_wipe_tower_pos = pos; m_wipe_tower_width = width; m_wipe_tower_depth=depth; m_angle_deg = angle; return (*this); }
|
||||
|
||||
Writer& set_y_shift(float shift) {
|
||||
m_current_pos.y -= shift-m_y_shift;
|
||||
|
@ -110,7 +109,7 @@ public:
|
|||
float y() const { return m_current_pos.y; }
|
||||
const WipeTower::xy& pos() const { return m_current_pos; }
|
||||
const WipeTower::xy start_pos_rotated() const { return m_start_pos; }
|
||||
const WipeTower::xy pos_rotated() const { return WipeTower::xy(m_current_pos,0.f,m_y_shift).rotate(m_wipe_tower_pos, m_wipe_tower_width, m_wipe_tower_depth, m_angle_deg); }
|
||||
const WipeTower::xy pos_rotated() const { return WipeTower::xy(m_current_pos, 0.f, m_y_shift).rotate(m_wipe_tower_width, m_wipe_tower_depth, m_internal_angle); }
|
||||
float elapsed_time() const { return m_elapsed_time; }
|
||||
|
||||
// Extrude with an explicitely provided amount of extrusion.
|
||||
|
@ -125,9 +124,9 @@ public:
|
|||
double len = sqrt(dx*dx+dy*dy);
|
||||
|
||||
|
||||
// For rotated wipe tower, transform position to printer coordinates
|
||||
WipeTower::xy rotated_current_pos(WipeTower::xy(m_current_pos,0.f,m_y_shift).rotate(m_wipe_tower_pos, m_wipe_tower_width, m_wipe_tower_depth, m_angle_deg)); // this is where we are
|
||||
WipeTower::xy rot(WipeTower::xy(x,y+m_y_shift).rotate(m_wipe_tower_pos, m_wipe_tower_width, m_wipe_tower_depth, m_angle_deg)); // this is where we want to go
|
||||
// Now do the "internal rotation" with respect to the wipe tower center
|
||||
WipeTower::xy rotated_current_pos(WipeTower::xy(m_current_pos,0.f,m_y_shift).rotate(m_wipe_tower_width, m_wipe_tower_depth, m_internal_angle)); // this is where we are
|
||||
WipeTower::xy rot(WipeTower::xy(x,y+m_y_shift).rotate(m_wipe_tower_width, m_wipe_tower_depth, m_internal_angle)); // this is where we want to go
|
||||
|
||||
if (! m_preview_suppressed && e > 0.f && len > 0.) {
|
||||
// Width of a squished extrusion, corrected for the roundings of the squished extrusions.
|
||||
|
@ -147,6 +146,7 @@ public:
|
|||
if (std::abs(rot.y - rotated_current_pos.y) > EPSILON)
|
||||
m_gcode += set_format_Y(rot.y);
|
||||
|
||||
|
||||
if (e != 0.f)
|
||||
m_gcode += set_format_E(e);
|
||||
|
||||
|
@ -397,9 +397,8 @@ private:
|
|||
std::string m_gcode;
|
||||
std::vector<WipeTower::Extrusion> m_extrusions;
|
||||
float m_elapsed_time;
|
||||
float m_angle_deg = 0.f;
|
||||
float m_internal_angle = 0.f;
|
||||
float m_y_shift = 0.f;
|
||||
WipeTower::xy m_wipe_tower_pos;
|
||||
float m_wipe_tower_width = 0.f;
|
||||
float m_wipe_tower_depth = 0.f;
|
||||
float m_last_fan_speed = 0.f;
|
||||
|
@ -539,6 +538,7 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::prime(
|
|||
m_print_brim = true;
|
||||
|
||||
ToolChangeResult result;
|
||||
result.priming = true;
|
||||
result.print_z = this->m_z_pos;
|
||||
result.layer_height = this->m_layer_height;
|
||||
result.gcode = writer.gcode();
|
||||
|
@ -575,7 +575,7 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::tool_change(unsigned int tool, boo
|
|||
}
|
||||
|
||||
box_coordinates cleaning_box(
|
||||
m_wipe_tower_pos + xy(m_perimeter_width / 2.f, m_perimeter_width / 2.f),
|
||||
xy(m_perimeter_width / 2.f, m_perimeter_width / 2.f),
|
||||
m_wipe_tower_width - m_perimeter_width,
|
||||
(tool != (unsigned int)(-1) ? /*m_layer_info->depth*/wipe_area+m_depth_traversed-0.5*m_perimeter_width
|
||||
: m_wipe_tower_depth-m_perimeter_width));
|
||||
|
@ -584,7 +584,6 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::tool_change(unsigned int tool, boo
|
|||
writer.set_extrusion_flow(m_extrusion_flow)
|
||||
.set_z(m_z_pos)
|
||||
.set_initial_tool(m_current_tool)
|
||||
.set_rotation(m_wipe_tower_pos, m_wipe_tower_width, m_wipe_tower_depth, m_wipe_tower_rotation_angle)
|
||||
.set_y_shift(m_y_shift + (tool!=(unsigned int)(-1) && (m_current_shape == SHAPE_REVERSED && !m_peters_wipe_tower) ? m_layer_info->depth - m_layer_info->toolchanges_depth(): 0.f))
|
||||
.append(";--------------------\n"
|
||||
"; CP TOOLCHANGE START\n")
|
||||
|
@ -594,7 +593,7 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::tool_change(unsigned int tool, boo
|
|||
.speed_override(100);
|
||||
|
||||
xy initial_position = cleaning_box.ld + WipeTower::xy(0.f,m_depth_traversed);
|
||||
writer.set_initial_position(initial_position);
|
||||
writer.set_initial_position(initial_position, m_wipe_tower_width, m_wipe_tower_depth, m_internal_rotation);
|
||||
|
||||
// Increase the extruder driver current to allow fast ramming.
|
||||
writer.set_extruder_trimpot(750);
|
||||
|
@ -616,11 +615,11 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::tool_change(unsigned int tool, boo
|
|||
if (last_change_in_layer) {// draw perimeter line
|
||||
writer.set_y_shift(m_y_shift);
|
||||
if (m_peters_wipe_tower)
|
||||
writer.rectangle(m_wipe_tower_pos,m_layer_info->depth + 3*m_perimeter_width,m_wipe_tower_depth);
|
||||
writer.rectangle(WipeTower::xy(0.f, 0.f),m_layer_info->depth + 3*m_perimeter_width,m_wipe_tower_depth);
|
||||
else {
|
||||
writer.rectangle(m_wipe_tower_pos,m_wipe_tower_width, m_layer_info->depth + m_perimeter_width);
|
||||
writer.rectangle(WipeTower::xy(0.f, 0.f),m_wipe_tower_width, m_layer_info->depth + m_perimeter_width);
|
||||
if (layer_finished()) { // no finish_layer will be called, we must wipe the nozzle
|
||||
writer.travel(m_wipe_tower_pos.x + (writer.x()> (m_wipe_tower_pos.x + m_wipe_tower_width) / 2.f ? 0.f : m_wipe_tower_width), writer.y());
|
||||
writer.travel(writer.x()> m_wipe_tower_width / 2.f ? 0.f : m_wipe_tower_width, writer.y());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -634,6 +633,7 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::tool_change(unsigned int tool, boo
|
|||
"\n\n");
|
||||
|
||||
ToolChangeResult result;
|
||||
result.priming = false;
|
||||
result.print_z = this->m_z_pos;
|
||||
result.layer_height = this->m_layer_height;
|
||||
result.gcode = writer.gcode();
|
||||
|
@ -647,7 +647,7 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::tool_change(unsigned int tool, boo
|
|||
WipeTower::ToolChangeResult WipeTowerPrusaMM::toolchange_Brim(bool sideOnly, float y_offset)
|
||||
{
|
||||
const box_coordinates wipeTower_box(
|
||||
m_wipe_tower_pos,
|
||||
WipeTower::xy(0.f, 0.f),
|
||||
m_wipe_tower_width,
|
||||
m_wipe_tower_depth);
|
||||
|
||||
|
@ -655,12 +655,11 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::toolchange_Brim(bool sideOnly, flo
|
|||
writer.set_extrusion_flow(m_extrusion_flow * 1.1f)
|
||||
.set_z(m_z_pos) // Let the writer know the current Z position as a base for Z-hop.
|
||||
.set_initial_tool(m_current_tool)
|
||||
.set_rotation(m_wipe_tower_pos, m_wipe_tower_width, m_wipe_tower_depth, m_wipe_tower_rotation_angle)
|
||||
.append(";-------------------------------------\n"
|
||||
"; CP WIPE TOWER FIRST LAYER BRIM START\n");
|
||||
|
||||
xy initial_position = wipeTower_box.lu - xy(m_perimeter_width * 6.f, 0);
|
||||
writer.set_initial_position(initial_position);
|
||||
writer.set_initial_position(initial_position, m_wipe_tower_width, m_wipe_tower_depth, m_internal_rotation);
|
||||
|
||||
writer.extrude_explicit(wipeTower_box.ld - xy(m_perimeter_width * 6.f, 0), // Prime the extruder left of the wipe tower.
|
||||
1.5f * m_extrusion_flow * (wipeTower_box.lu.y - wipeTower_box.ld.y), 2400);
|
||||
|
@ -685,6 +684,7 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::toolchange_Brim(bool sideOnly, flo
|
|||
m_print_brim = false; // Mark the brim as extruded
|
||||
|
||||
ToolChangeResult result;
|
||||
result.priming = false;
|
||||
result.print_z = this->m_z_pos;
|
||||
result.layer_height = this->m_layer_height;
|
||||
result.gcode = writer.gcode();
|
||||
|
@ -724,7 +724,7 @@ void WipeTowerPrusaMM::toolchange_Unload(
|
|||
if (m_layer_info > m_plan.begin() && m_layer_info < m_plan.end() && (m_layer_info-1!=m_plan.begin() || !m_adhesion )) {
|
||||
|
||||
// this is y of the center of previous sparse infill border
|
||||
float sparse_beginning_y = m_wipe_tower_pos.y;
|
||||
float sparse_beginning_y = 0.f;
|
||||
if (m_current_shape == SHAPE_REVERSED)
|
||||
sparse_beginning_y += ((m_layer_info-1)->depth - (m_layer_info-1)->toolchanges_depth())
|
||||
- ((m_layer_info)->depth-(m_layer_info)->toolchanges_depth()) ;
|
||||
|
@ -742,7 +742,7 @@ void WipeTowerPrusaMM::toolchange_Unload(
|
|||
for (const auto& tch : m_layer_info->tool_changes) { // let's find this toolchange
|
||||
if (tch.old_tool == m_current_tool) {
|
||||
sum_of_depths += tch.ramming_depth;
|
||||
float ramming_end_y = m_wipe_tower_pos.y + sum_of_depths;
|
||||
float ramming_end_y = sum_of_depths;
|
||||
ramming_end_y -= (y_step/m_extra_spacing-m_perimeter_width) / 2.f; // center of final ramming line
|
||||
|
||||
// debugging:
|
||||
|
@ -950,7 +950,7 @@ void WipeTowerPrusaMM::toolchange_Wipe(
|
|||
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;
|
||||
writer.travel(writer.x(), writer.y() - dy)
|
||||
.travel(m_wipe_tower_pos.x + (m_left_to_right ? m_wipe_tower_width : 0.f), writer.y());
|
||||
.travel(m_left_to_right ? m_wipe_tower_width : 0.f, writer.y());
|
||||
}
|
||||
|
||||
writer.set_extrusion_flow(m_extrusion_flow); // Reset the extrusion flow.
|
||||
|
@ -969,7 +969,6 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::finish_layer()
|
|||
writer.set_extrusion_flow(m_extrusion_flow)
|
||||
.set_z(m_z_pos)
|
||||
.set_initial_tool(m_current_tool)
|
||||
.set_rotation(m_wipe_tower_pos, m_wipe_tower_width, m_wipe_tower_depth, m_wipe_tower_rotation_angle)
|
||||
.set_y_shift(m_y_shift - (m_current_shape == SHAPE_REVERSED && !m_peters_wipe_tower ? m_layer_info->toolchanges_depth() : 0.f))
|
||||
.append(";--------------------\n"
|
||||
"; CP EMPTY GRID START\n")
|
||||
|
@ -978,14 +977,12 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::finish_layer()
|
|||
// Slow down on the 1st layer.
|
||||
float speed_factor = m_is_first_layer ? 0.5f : 1.f;
|
||||
float current_depth = m_layer_info->depth - m_layer_info->toolchanges_depth();
|
||||
box_coordinates fill_box(m_wipe_tower_pos + xy(m_perimeter_width, m_depth_traversed + m_perimeter_width),
|
||||
box_coordinates fill_box(xy(m_perimeter_width, m_depth_traversed + m_perimeter_width),
|
||||
m_wipe_tower_width - 2 * m_perimeter_width, current_depth-m_perimeter_width);
|
||||
|
||||
if (m_left_to_right) // so there is never a diagonal travel
|
||||
writer.set_initial_position(fill_box.ru);
|
||||
else
|
||||
writer.set_initial_position(fill_box.lu);
|
||||
|
||||
writer.set_initial_position((m_left_to_right ? fill_box.ru : fill_box.lu), // so there is never a diagonal travel
|
||||
m_wipe_tower_width, m_wipe_tower_depth, m_internal_rotation);
|
||||
|
||||
box_coordinates box = fill_box;
|
||||
for (int i=0;i<2;++i) {
|
||||
|
@ -1044,6 +1041,7 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::finish_layer()
|
|||
m_depth_traversed = m_wipe_tower_depth-m_perimeter_width;
|
||||
|
||||
ToolChangeResult result;
|
||||
result.priming = false;
|
||||
result.print_z = this->m_z_pos;
|
||||
result.layer_height = this->m_layer_height;
|
||||
result.gcode = writer.gcode();
|
||||
|
@ -1165,9 +1163,9 @@ void WipeTowerPrusaMM::generate(std::vector<std::vector<WipeTower::ToolChangeRes
|
|||
{
|
||||
set_layer(layer.z,layer.height,0,layer.z == m_plan.front().z,layer.z == m_plan.back().z);
|
||||
if (m_peters_wipe_tower)
|
||||
m_wipe_tower_rotation_angle += 90.f;
|
||||
m_internal_rotation += 90.f;
|
||||
else
|
||||
m_wipe_tower_rotation_angle += 180.f;
|
||||
m_internal_rotation += 180.f;
|
||||
|
||||
if (!m_peters_wipe_tower && m_layer_info->depth < m_wipe_tower_depth - m_perimeter_width)
|
||||
m_y_shift = (m_wipe_tower_depth-m_layer_info->depth-m_perimeter_width)/2.f;
|
||||
|
@ -1188,7 +1186,7 @@ void WipeTowerPrusaMM::generate(std::vector<std::vector<WipeTower::ToolChangeRes
|
|||
last_toolchange.gcode += buf;
|
||||
}
|
||||
last_toolchange.gcode += finish_layer_toolchange.gcode;
|
||||
last_toolchange.extrusions.insert(last_toolchange.extrusions.end(),finish_layer_toolchange.extrusions.begin(),finish_layer_toolchange.extrusions.end());
|
||||
last_toolchange.extrusions.insert(last_toolchange.extrusions.end(), finish_layer_toolchange.extrusions.begin(), finish_layer_toolchange.extrusions.end());
|
||||
last_toolchange.end_pos = finish_layer_toolchange.end_pos;
|
||||
}
|
||||
else
|
||||
|
|
|
@ -102,6 +102,8 @@ public:
|
|||
// Iterates through prepared m_plan, generates ToolChangeResults and appends them to "result"
|
||||
void generate(std::vector<std::vector<WipeTower::ToolChangeResult>> &result);
|
||||
|
||||
float get_depth() const { return m_wipe_tower_depth; }
|
||||
|
||||
|
||||
|
||||
// Switch to a next layer.
|
||||
|
@ -189,6 +191,7 @@ private:
|
|||
float m_wipe_tower_width; // Width of the wipe tower.
|
||||
float m_wipe_tower_depth = 0.f; // Depth of the wipe tower
|
||||
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.
|
||||
|
|
|
@ -114,6 +114,28 @@ void GCodeReader::parse_file(const std::string &file, callback_t callback)
|
|||
this->parse_line(line, callback);
|
||||
}
|
||||
|
||||
bool GCodeReader::GCodeLine::has(char axis) const
|
||||
{
|
||||
const char *c = m_raw.c_str();
|
||||
// Skip the whitespaces.
|
||||
c = skip_whitespaces(c);
|
||||
// Skip the command.
|
||||
c = skip_word(c);
|
||||
// Up to the end of line or comment.
|
||||
while (! is_end_of_gcode_line(*c)) {
|
||||
// Skip whitespaces.
|
||||
c = skip_whitespaces(c);
|
||||
if (is_end_of_gcode_line(*c))
|
||||
break;
|
||||
// Check the name of the axis.
|
||||
if (*c == axis)
|
||||
return true;
|
||||
// Skip the rest of the word.
|
||||
c = skip_word(c);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GCodeReader::GCodeLine::has_value(char axis, float &value) const
|
||||
{
|
||||
const char *c = m_raw.c_str();
|
||||
|
|
|
@ -27,6 +27,7 @@ public:
|
|||
|
||||
bool has(Axis axis) const { return (m_mask & (1 << int(axis))) != 0; }
|
||||
float value(Axis axis) const { return m_axis[axis]; }
|
||||
bool has(char axis) const;
|
||||
bool has_value(char axis, float &value) const;
|
||||
float new_Z(const GCodeReader &reader) const { return this->has(Z) ? this->z() : reader.z(); }
|
||||
float new_E(const GCodeReader &reader) const { return this->has(E) ? this->e() : reader.e(); }
|
||||
|
|
|
@ -469,6 +469,40 @@ namespace Slic3r {
|
|||
return _state.minimum_travel_feedrate;
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::set_filament_load_times(const std::vector<double> &filament_load_times)
|
||||
{
|
||||
_state.filament_load_times.clear();
|
||||
for (double t : filament_load_times)
|
||||
_state.filament_load_times.push_back(t);
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::set_filament_unload_times(const std::vector<double> &filament_unload_times)
|
||||
{
|
||||
_state.filament_unload_times.clear();
|
||||
for (double t : filament_unload_times)
|
||||
_state.filament_unload_times.push_back(t);
|
||||
}
|
||||
|
||||
float GCodeTimeEstimator::get_filament_load_time(unsigned int id_extruder)
|
||||
{
|
||||
return
|
||||
(_state.filament_load_times.empty() || id_extruder == _state.extruder_id_unloaded) ?
|
||||
0 :
|
||||
(_state.filament_load_times.size() <= id_extruder) ?
|
||||
_state.filament_load_times.front() :
|
||||
_state.filament_load_times[id_extruder];
|
||||
}
|
||||
|
||||
float GCodeTimeEstimator::get_filament_unload_time(unsigned int id_extruder)
|
||||
{
|
||||
return
|
||||
(_state.filament_unload_times.empty() || id_extruder == _state.extruder_id_unloaded) ?
|
||||
0 :
|
||||
(_state.filament_unload_times.size() <= id_extruder) ?
|
||||
_state.filament_unload_times.front() :
|
||||
_state.filament_unload_times[id_extruder];
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::set_extrude_factor_override_percentage(float percentage)
|
||||
{
|
||||
_state.extrude_factor_override_percentage = percentage;
|
||||
|
@ -535,6 +569,23 @@ namespace Slic3r {
|
|||
_state.g1_line_id = 0;
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::set_extruder_id(unsigned int id)
|
||||
{
|
||||
_state.extruder_id = id;
|
||||
}
|
||||
|
||||
unsigned int GCodeTimeEstimator::get_extruder_id() const
|
||||
{
|
||||
return _state.extruder_id;
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::reset_extruder_id()
|
||||
{
|
||||
// Set the initial extruder ID to unknown. For the multi-material setup it means
|
||||
// that all the filaments are parked in the MMU and no filament is loaded yet.
|
||||
_state.extruder_id = _state.extruder_id_unloaded;
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::add_additional_time(float timeSec)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
|
@ -575,6 +626,9 @@ namespace Slic3r {
|
|||
set_axis_max_acceleration(axis, DEFAULT_AXIS_MAX_ACCELERATION[a]);
|
||||
set_axis_max_jerk(axis, DEFAULT_AXIS_MAX_JERK[a]);
|
||||
}
|
||||
|
||||
_state.filament_load_times.clear();
|
||||
_state.filament_unload_times.clear();
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::reset()
|
||||
|
@ -613,6 +667,7 @@ namespace Slic3r {
|
|||
|
||||
set_additional_time(0.0f);
|
||||
|
||||
reset_extruder_id();
|
||||
reset_g1_line_id();
|
||||
_g1_line_ids.clear();
|
||||
|
||||
|
@ -778,8 +833,18 @@ namespace Slic3r {
|
|||
_processM566(line);
|
||||
break;
|
||||
}
|
||||
case 702: // MK3 MMU2: Process the final filament unload.
|
||||
{
|
||||
_processM702(line);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 'T': // Select Tools
|
||||
{
|
||||
_processT(line);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1164,11 +1229,25 @@ namespace Slic3r {
|
|||
{
|
||||
PROFILE_FUNC();
|
||||
float value;
|
||||
if (line.has_value('S', value))
|
||||
if (line.has_value('S', value)) {
|
||||
// Legacy acceleration format. This format is used by the legacy Marlin, MK2 or MK3 firmware,
|
||||
// and it is also generated by Slic3r to control acceleration per extrusion type
|
||||
// (there is a separate acceleration settings in Slicer for perimeter, first layer etc).
|
||||
set_acceleration(value);
|
||||
|
||||
if (line.has_value('T', value))
|
||||
set_retract_acceleration(value);
|
||||
if (line.has_value('T', value))
|
||||
set_retract_acceleration(value);
|
||||
} else {
|
||||
// New acceleration format, compatible with the upstream Marlin.
|
||||
if (line.has_value('P', value))
|
||||
set_acceleration(value);
|
||||
if (line.has_value('R', value))
|
||||
set_retract_acceleration(value);
|
||||
if (line.has_value('T', value)) {
|
||||
// Interpret the T value as the travel acceleration in the new Marlin format.
|
||||
//FIXME Prusa3D firmware currently does not support travel acceleration value independent from the extruding acceleration value.
|
||||
// set_travel_acceleration(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_processM205(const GCodeReader::GCodeLine& line)
|
||||
|
@ -1223,6 +1302,37 @@ namespace Slic3r {
|
|||
set_axis_max_jerk(E, line.e() * MMMIN_TO_MMSEC);
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_processM702(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
if (line.has('C')) {
|
||||
// MK3 MMU2 specific M code:
|
||||
// M702 C is expected to be sent by the custom end G-code when finalizing a print.
|
||||
// The MK3 unit shall unload and park the active filament into the MMU2 unit.
|
||||
add_additional_time(get_filament_unload_time(get_extruder_id()));
|
||||
reset_extruder_id();
|
||||
_simulate_st_synchronize();
|
||||
}
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_processT(const GCodeReader::GCodeLine& line)
|
||||
{
|
||||
std::string cmd = line.cmd();
|
||||
if (cmd.length() > 1)
|
||||
{
|
||||
unsigned int id = (unsigned int)::strtol(cmd.substr(1).c_str(), nullptr, 10);
|
||||
if (get_extruder_id() != id)
|
||||
{
|
||||
// Specific to the MK3 MMU2: The initial extruder ID is set to -1 indicating
|
||||
// that the filament is parked in the MMU2 unit and there is nothing to be unloaded yet.
|
||||
add_additional_time(get_filament_unload_time(get_extruder_id()));
|
||||
set_extruder_id(id);
|
||||
add_additional_time(get_filament_load_time(get_extruder_id()));
|
||||
_simulate_st_synchronize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GCodeTimeEstimator::_simulate_st_synchronize()
|
||||
{
|
||||
PROFILE_FUNC();
|
||||
|
|
|
@ -79,7 +79,15 @@ namespace Slic3r {
|
|||
float minimum_feedrate; // mm/s
|
||||
float minimum_travel_feedrate; // mm/s
|
||||
float extrude_factor_override_percentage;
|
||||
// Additional load / unload times for a filament exchange sequence.
|
||||
std::vector<float> filament_load_times;
|
||||
std::vector<float> filament_unload_times;
|
||||
unsigned int g1_line_id;
|
||||
// extruder_id is currently used to correctly calculate filament load / unload times
|
||||
// into the total print time. This is currently only really used by the MK3 MMU2:
|
||||
// Extruder id (-1) means no filament is loaded yet, all the filaments are parked in the MK3 MMU2 unit.
|
||||
static const unsigned int extruder_id_unloaded = (unsigned int)-1;
|
||||
unsigned int extruder_id;
|
||||
};
|
||||
|
||||
public:
|
||||
|
@ -281,6 +289,11 @@ namespace Slic3r {
|
|||
void set_minimum_travel_feedrate(float feedrate_mm_sec);
|
||||
float get_minimum_travel_feedrate() const;
|
||||
|
||||
void set_filament_load_times(const std::vector<double> &filament_load_times);
|
||||
void set_filament_unload_times(const std::vector<double> &filament_unload_times);
|
||||
float get_filament_load_time(unsigned int id_extruder);
|
||||
float get_filament_unload_time(unsigned int id_extruder);
|
||||
|
||||
void set_extrude_factor_override_percentage(float percentage);
|
||||
float get_extrude_factor_override_percentage() const;
|
||||
|
||||
|
@ -300,6 +313,10 @@ namespace Slic3r {
|
|||
void increment_g1_line_id();
|
||||
void reset_g1_line_id();
|
||||
|
||||
void set_extruder_id(unsigned int id);
|
||||
unsigned int get_extruder_id() const;
|
||||
void reset_extruder_id();
|
||||
|
||||
void add_additional_time(float timeSec);
|
||||
void set_additional_time(float timeSec);
|
||||
float get_additional_time() const;
|
||||
|
@ -383,6 +400,12 @@ namespace Slic3r {
|
|||
// Set allowable instantaneous speed change
|
||||
void _processM566(const GCodeReader::GCodeLine& line);
|
||||
|
||||
// Unload the current filament into the MK3 MMU2 unit at the end of print.
|
||||
void _processM702(const GCodeReader::GCodeLine& line);
|
||||
|
||||
// Processes T line (Select Tool)
|
||||
void _processT(const GCodeReader::GCodeLine& line);
|
||||
|
||||
// Simulates firmware st_synchronize() call
|
||||
void _simulate_st_synchronize();
|
||||
|
||||
|
|
|
@ -167,7 +167,10 @@ bool Print::invalidate_state_by_config_options(const std::vector<t_config_option
|
|||
"use_relative_e_distances",
|
||||
"use_volumetric_e",
|
||||
"variable_layer_height",
|
||||
"wipe"
|
||||
"wipe",
|
||||
"wipe_tower_x",
|
||||
"wipe_tower_y",
|
||||
"wipe_tower_rotation_angle"
|
||||
};
|
||||
|
||||
std::vector<PrintStep> steps;
|
||||
|
@ -176,7 +179,12 @@ bool Print::invalidate_state_by_config_options(const std::vector<t_config_option
|
|||
|
||||
// Always invalidate the wipe tower. This is probably necessary because of the wipe_into_infill / wipe_into_objects
|
||||
// features - nearly anything can influence what should (and could) be wiped into.
|
||||
steps.emplace_back(psWipeTower);
|
||||
// Only these three parameters don't invalidate the wipe tower (they only affect the gcode export):
|
||||
for (const t_config_option_key &opt_key : opt_keys)
|
||||
if (opt_key != "wipe_tower_x" && opt_key != "wipe_tower_y" && opt_key != "wipe_tower_rotation_angle") {
|
||||
steps.emplace_back(psWipeTower);
|
||||
break;
|
||||
}
|
||||
|
||||
for (const t_config_option_key &opt_key : opt_keys) {
|
||||
if (steps_ignore.find(opt_key) != steps_ignore.end()) {
|
||||
|
@ -205,6 +213,7 @@ bool Print::invalidate_state_by_config_options(const std::vector<t_config_option
|
|||
|| opt_key == "filament_unloading_speed"
|
||||
|| opt_key == "filament_toolchange_delay"
|
||||
|| opt_key == "filament_cooling_moves"
|
||||
|| opt_key == "filament_minimal_purge_on_wipe_tower"
|
||||
|| opt_key == "filament_cooling_initial_speed"
|
||||
|| opt_key == "filament_cooling_final_speed"
|
||||
|| opt_key == "filament_ramming_parameters"
|
||||
|
@ -213,10 +222,7 @@ bool Print::invalidate_state_by_config_options(const std::vector<t_config_option
|
|||
|| opt_key == "spiral_vase"
|
||||
|| opt_key == "temperature"
|
||||
|| opt_key == "wipe_tower"
|
||||
|| opt_key == "wipe_tower_x"
|
||||
|| opt_key == "wipe_tower_y"
|
||||
|| opt_key == "wipe_tower_width"
|
||||
|| opt_key == "wipe_tower_rotation_angle"
|
||||
|| opt_key == "wipe_tower_bridging"
|
||||
|| opt_key == "wiping_volumes_matrix"
|
||||
|| opt_key == "parking_pos_retraction"
|
||||
|
@ -1052,6 +1058,8 @@ void Print::_make_wipe_tower()
|
|||
if (! this->has_wipe_tower())
|
||||
return;
|
||||
|
||||
m_wipe_tower_depth = 0.f;
|
||||
|
||||
// Get wiping matrix to get number of extruders and convert vector<double> to vector<float>:
|
||||
std::vector<float> wiping_matrix((this->config.wiping_volumes_matrix.values).begin(),(this->config.wiping_volumes_matrix.values).end());
|
||||
// Extract purging volumes for each extruder pair:
|
||||
|
@ -1145,12 +1153,19 @@ void Print::_make_wipe_tower()
|
|||
wipe_tower.plan_toolchange(layer_tools.print_z, layer_tools.wipe_tower_layer_height, current_extruder_id, current_extruder_id,false);
|
||||
for (const auto extruder_id : layer_tools.extruders) {
|
||||
if ((first_layer && extruder_id == m_tool_ordering.all_extruders().back()) || extruder_id != current_extruder_id) {
|
||||
float volume_to_wipe = wipe_volumes[current_extruder_id][extruder_id]; // total volume to wipe after this toolchange
|
||||
float volume_to_wipe = wipe_volumes[current_extruder_id][extruder_id]; // total volume to wipe after this toolchange
|
||||
// Not all of that can be used for infill purging:
|
||||
volume_to_wipe -= config.filament_minimal_purge_on_wipe_tower.get_at(extruder_id);
|
||||
|
||||
// try to assign some infills/objects for the wiping:
|
||||
volume_to_wipe = layer_tools.wiping_extrusions().mark_wiping_extrusions(*this, current_extruder_id, extruder_id, wipe_volumes[current_extruder_id][extruder_id]);
|
||||
volume_to_wipe = layer_tools.wiping_extrusions().mark_wiping_extrusions(*this, current_extruder_id, extruder_id, volume_to_wipe);
|
||||
|
||||
wipe_tower.plan_toolchange(layer_tools.print_z, layer_tools.wipe_tower_layer_height, current_extruder_id, extruder_id, first_layer && extruder_id == m_tool_ordering.all_extruders().back(), volume_to_wipe);
|
||||
// add back the minimal amount toforce on the wipe tower:
|
||||
volume_to_wipe += config.filament_minimal_purge_on_wipe_tower.get_at(extruder_id);
|
||||
|
||||
// request a toolchange at the wipe tower with at least volume_to_wipe purging amount
|
||||
wipe_tower.plan_toolchange(layer_tools.print_z, layer_tools.wipe_tower_layer_height, current_extruder_id, extruder_id,
|
||||
first_layer && extruder_id == m_tool_ordering.all_extruders().back(), volume_to_wipe);
|
||||
current_extruder_id = extruder_id;
|
||||
}
|
||||
}
|
||||
|
@ -1163,7 +1178,8 @@ void Print::_make_wipe_tower()
|
|||
// Generate the wipe tower layers.
|
||||
m_wipe_tower_tool_changes.reserve(m_tool_ordering.layer_tools().size());
|
||||
wipe_tower.generate(m_wipe_tower_tool_changes);
|
||||
|
||||
m_wipe_tower_depth = wipe_tower.get_depth();
|
||||
|
||||
// Unload the current filament over the purge tower.
|
||||
coordf_t layer_height = this->objects.front()->config.layer_height.value;
|
||||
if (m_tool_ordering.back().wipe_tower_partitions > 0) {
|
||||
|
|
|
@ -273,6 +273,7 @@ public:
|
|||
|
||||
void add_model_object(ModelObject* model_object, int idx = -1);
|
||||
bool apply_config(DynamicPrintConfig config);
|
||||
float get_wipe_tower_depth() const { return m_wipe_tower_depth; }
|
||||
bool has_infinite_skirt() const;
|
||||
bool has_skirt() const;
|
||||
// Returns an empty string if valid, otherwise returns an error message.
|
||||
|
@ -326,6 +327,9 @@ private:
|
|||
bool invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys);
|
||||
PrintRegionConfig _region_config_from_model_volume(const ModelVolume &volume);
|
||||
|
||||
// Depth of the wipe tower to pass to GLCanvas3D for exact bounding box:
|
||||
float m_wipe_tower_depth = 0.f;
|
||||
|
||||
// Has the calculation been canceled?
|
||||
tbb::atomic<bool> m_canceled;
|
||||
};
|
||||
|
|
|
@ -504,19 +504,39 @@ PrintConfigDef::PrintConfigDef()
|
|||
def = this->add("filament_cooling_initial_speed", coFloats);
|
||||
def->label = L("Speed of the first cooling move");
|
||||
def->tooltip = L("Cooling moves are gradually accelerating beginning at this speed. ");
|
||||
def->cli = "filament-cooling-initial-speed=i@";
|
||||
def->cli = "filament-cooling-initial-speed=f@";
|
||||
def->sidetext = L("mm/s");
|
||||
def->min = 0;
|
||||
def->default_value = new ConfigOptionFloats { 2.2f };
|
||||
|
||||
def = this->add("filament_minimal_purge_on_wipe_tower", coFloats);
|
||||
def->label = L("Minimal purge on wipe tower");
|
||||
def->tooltip = L("After a toolchange, certain amount of filament is used for purging. This "
|
||||
"can end up on the wipe tower, infill or sacrificial object. If there was "
|
||||
"enough infill etc. available, this could result in bad quality at the beginning "
|
||||
"of purging. This is a minimum that must be wiped on the wipe tower before "
|
||||
"Slic3r considers moving elsewhere. ");
|
||||
def->cli = "filament-minimal-purge-on-wipe-tower=f@";
|
||||
def->sidetext = L("mm³");
|
||||
def->min = 0;
|
||||
def->default_value = new ConfigOptionFloats { 5.f };
|
||||
|
||||
def = this->add("filament_cooling_final_speed", coFloats);
|
||||
def->label = L("Speed of the last cooling move");
|
||||
def->tooltip = L("Cooling moves are gradually accelerating towards this speed. ");
|
||||
def->cli = "filament-cooling-final-speed=i@";
|
||||
def->cli = "filament-cooling-final-speed=f@";
|
||||
def->sidetext = L("mm/s");
|
||||
def->min = 0;
|
||||
def->default_value = new ConfigOptionFloats { 3.4f };
|
||||
|
||||
def = this->add("filament_load_time", coFloats);
|
||||
def->label = L("Filament load time");
|
||||
def->tooltip = L("Time for the printer firmware (or the Multi Material Unit 2.0) to load a new filament during a tool change (when executing the T code). This time is added to the total print time by the G-code time estimator.");
|
||||
def->cli = "filament-load-time=i@";
|
||||
def->sidetext = L("s");
|
||||
def->min = 0;
|
||||
def->default_value = new ConfigOptionFloats { 0.0f };
|
||||
|
||||
def = this->add("filament_ramming_parameters", coStrings);
|
||||
def->label = L("Ramming parameters");
|
||||
def->tooltip = L("This string is edited by RammingDialog and contains ramming specific parameters ");
|
||||
|
@ -524,6 +544,14 @@ PrintConfigDef::PrintConfigDef()
|
|||
def->default_value = new ConfigOptionStrings { "120 100 6.6 6.8 7.2 7.6 7.9 8.2 8.7 9.4 9.9 10.0|"
|
||||
" 0.05 6.6 0.45 6.8 0.95 7.8 1.45 8.3 1.95 9.7 2.45 10 2.95 7.6 3.45 7.6 3.95 7.6 4.45 7.6 4.95 7.6" };
|
||||
|
||||
def = this->add("filament_unload_time", coFloats);
|
||||
def->label = L("Filament unload time");
|
||||
def->tooltip = L("Time for the printer firmware (or the Multi Material Unit 2.0) to unload a filament during a tool change (when executing the T code). This time is added to the total print time by the G-code time estimator.");
|
||||
def->cli = "filament-unload-time=i@";
|
||||
def->sidetext = L("s");
|
||||
def->min = 0;
|
||||
def->default_value = new ConfigOptionFloats { 0.0f };
|
||||
|
||||
def = this->add("filament_diameter", coFloats);
|
||||
def->label = L("Diameter");
|
||||
def->tooltip = L("Enter your filament diameter here. Good precision is required, so use a caliper "
|
||||
|
@ -892,8 +920,16 @@ PrintConfigDef::PrintConfigDef()
|
|||
def->min = 0;
|
||||
def->default_value = new ConfigOptionFloat(0.3);
|
||||
|
||||
def = this->add("remaining_times", coBool);
|
||||
def->label = L("Supports remaining times");
|
||||
def->tooltip = L("Emit M73 P[percent printed] R[remaining time in seconds] at 1 minute"
|
||||
" intervals into the G-code to let the firmware show accurate remaining time."
|
||||
" As of now only the Prusa i3 MK3 firmware recognizes M73."
|
||||
" Also the i3 MK3 firmware supports M73 Qxx Sxx for the silent mode.");
|
||||
def->default_value = new ConfigOptionBool(false);
|
||||
|
||||
def = this->add("silent_mode", coBool);
|
||||
def->label = L("Support silent mode");
|
||||
def->label = L("Supports silent mode");
|
||||
def->tooltip = L("Set silent mode for the G-code flavor");
|
||||
def->default_value = new ConfigOptionBool(true);
|
||||
|
||||
|
|
|
@ -528,10 +528,13 @@ public:
|
|||
ConfigOptionFloats filament_cost;
|
||||
ConfigOptionFloats filament_max_volumetric_speed;
|
||||
ConfigOptionFloats filament_loading_speed;
|
||||
ConfigOptionFloats filament_load_time;
|
||||
ConfigOptionFloats filament_unloading_speed;
|
||||
ConfigOptionFloats filament_toolchange_delay;
|
||||
ConfigOptionFloats filament_unload_time;
|
||||
ConfigOptionInts filament_cooling_moves;
|
||||
ConfigOptionFloats filament_cooling_initial_speed;
|
||||
ConfigOptionFloats filament_minimal_purge_on_wipe_tower;
|
||||
ConfigOptionFloats filament_cooling_final_speed;
|
||||
ConfigOptionStrings filament_ramming_parameters;
|
||||
ConfigOptionBool gcode_comments;
|
||||
|
@ -563,6 +566,7 @@ public:
|
|||
ConfigOptionFloat cooling_tube_retraction;
|
||||
ConfigOptionFloat cooling_tube_length;
|
||||
ConfigOptionFloat parking_pos_retraction;
|
||||
ConfigOptionBool remaining_times;
|
||||
ConfigOptionBool silent_mode;
|
||||
ConfigOptionFloat extra_loading_move;
|
||||
|
||||
|
@ -590,10 +594,13 @@ protected:
|
|||
OPT_PTR(filament_cost);
|
||||
OPT_PTR(filament_max_volumetric_speed);
|
||||
OPT_PTR(filament_loading_speed);
|
||||
OPT_PTR(filament_load_time);
|
||||
OPT_PTR(filament_unloading_speed);
|
||||
OPT_PTR(filament_unload_time);
|
||||
OPT_PTR(filament_toolchange_delay);
|
||||
OPT_PTR(filament_cooling_moves);
|
||||
OPT_PTR(filament_cooling_initial_speed);
|
||||
OPT_PTR(filament_minimal_purge_on_wipe_tower);
|
||||
OPT_PTR(filament_cooling_final_speed);
|
||||
OPT_PTR(filament_ramming_parameters);
|
||||
OPT_PTR(gcode_comments);
|
||||
|
@ -625,6 +632,7 @@ protected:
|
|||
OPT_PTR(cooling_tube_retraction);
|
||||
OPT_PTR(cooling_tube_length);
|
||||
OPT_PTR(parking_pos_retraction);
|
||||
OPT_PTR(remaining_times);
|
||||
OPT_PTR(silent_mode);
|
||||
OPT_PTR(extra_loading_move);
|
||||
}
|
||||
|
|
|
@ -75,6 +75,7 @@ bool PrintObject::delete_last_copy()
|
|||
|
||||
bool PrintObject::set_copies(const Points &points)
|
||||
{
|
||||
bool copies_num_changed = this->_copies.size() != points.size();
|
||||
this->_copies = points;
|
||||
|
||||
// order copies with a nearest neighbor search and translate them by _copies_shift
|
||||
|
@ -93,7 +94,8 @@ bool PrintObject::set_copies(const Points &points)
|
|||
|
||||
bool invalidated = this->_print->invalidate_step(psSkirt);
|
||||
invalidated |= this->_print->invalidate_step(psBrim);
|
||||
invalidated |= this->_print->invalidate_step(psWipeTower);
|
||||
if (copies_num_changed)
|
||||
invalidated |= this->_print->invalidate_step(psWipeTower);
|
||||
return invalidated;
|
||||
}
|
||||
|
||||
|
|
|
@ -644,20 +644,62 @@ std::vector<int> GLVolumeCollection::load_object(
|
|||
return volumes_idx;
|
||||
}
|
||||
|
||||
int GLVolumeCollection::load_wipe_tower_preview(
|
||||
int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool use_VBOs)
|
||||
{
|
||||
float color[4] = { 0.5f, 0.5f, 0.0f, 0.5f };
|
||||
this->volumes.emplace_back(new GLVolume(color));
|
||||
GLVolume &v = *this->volumes.back();
|
||||
|
||||
int GLVolumeCollection::load_wipe_tower_preview(
|
||||
int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool use_VBOs, bool size_unknown, float brim_width)
|
||||
{
|
||||
if (depth < 0.01f)
|
||||
return int(this->volumes.size() - 1);
|
||||
if (height == 0.0f)
|
||||
height = 0.1f;
|
||||
|
||||
auto mesh = make_cube(width, depth, height);
|
||||
mesh.translate(-width / 2.f, -depth / 2.f, 0.f);
|
||||
Point origin_of_rotation(0.f, 0.f);
|
||||
mesh.rotate(rotation_angle,&origin_of_rotation);
|
||||
TriangleMesh mesh;
|
||||
float color[4] = { 0.5f, 0.5f, 0.0f, 1.f };
|
||||
|
||||
// In case we don't know precise dimensions of the wipe tower yet, we'll draw the box with different color with one side jagged:
|
||||
if (size_unknown) {
|
||||
color[0] = 0.9f;
|
||||
color[1] = 0.6f;
|
||||
|
||||
depth = std::max(depth, 10.f); // Too narrow tower would interfere with the teeth. The estimate is not precise anyway.
|
||||
float min_width = 30.f;
|
||||
// We'll now create the box with jagged edge. y-coordinates of the pre-generated model are shifted so that the front
|
||||
// edge has y=0 and centerline of the back edge has y=depth:
|
||||
Pointf3s points;
|
||||
std::vector<Point3> facets;
|
||||
float out_points_idx[][3] = {{0, -depth, 0}, {0, 0, 0}, {38.453, 0, 0}, {61.547, 0, 0}, {100, 0, 0}, {100, -depth, 0}, {55.7735, -10, 0}, {44.2265, 10, 0},
|
||||
{38.453, 0, 1}, {0, 0, 1}, {0, -depth, 1}, {100, -depth, 1}, {100, 0, 1}, {61.547, 0, 1}, {55.7735, -10, 1}, {44.2265, 10, 1}};
|
||||
int out_facets_idx[][3] = {{0, 1, 2}, {3, 4, 5}, {6, 5, 0}, {3, 5, 6}, {6, 2, 7}, {6, 0, 2}, {8, 9, 10}, {11, 12, 13}, {10, 11, 14}, {14, 11, 13}, {15, 8, 14},
|
||||
{8, 10, 14}, {3, 12, 4}, {3, 13, 12}, {6, 13, 3}, {6, 14, 13}, {7, 14, 6}, {7, 15, 14}, {2, 15, 7}, {2, 8, 15}, {1, 8, 2}, {1, 9, 8},
|
||||
{0, 9, 1}, {0, 10, 9}, {5, 10, 0}, {5, 11, 10}, {4, 11, 5}, {4, 12, 11}};
|
||||
for (int i=0;i<16;++i)
|
||||
points.push_back(Pointf3(out_points_idx[i][0] / (100.f/min_width), out_points_idx[i][1] + depth, out_points_idx[i][2]));
|
||||
for (int i=0;i<28;++i)
|
||||
facets.push_back(Point3(out_facets_idx[i][0], out_facets_idx[i][1], out_facets_idx[i][2]));
|
||||
TriangleMesh tooth_mesh(points, facets);
|
||||
|
||||
// We have the mesh ready. It has one tooth and width of min_width. We will now append several of these together until we are close to
|
||||
// the required width of the block. Than we can scale it precisely.
|
||||
size_t n = std::max(1, int(width/min_width)); // How many shall be merged?
|
||||
for (size_t i=0;i<n;++i) {
|
||||
mesh.merge(tooth_mesh);
|
||||
tooth_mesh.translate(min_width, 0.f, 0.f);
|
||||
}
|
||||
|
||||
mesh.scale(Pointf3(width/(n*min_width), 1.f, height)); // Scaling to proper width
|
||||
}
|
||||
else
|
||||
mesh = make_cube(width, depth, height);
|
||||
|
||||
// We'll make another mesh to show the brim (fixed layer height):
|
||||
TriangleMesh brim_mesh = make_cube(width+2.f*brim_width, depth+2.f*brim_width, 0.2f);
|
||||
brim_mesh.translate(-brim_width, -brim_width, 0.f);
|
||||
mesh.merge(brim_mesh);
|
||||
|
||||
mesh.rotate(rotation_angle, &origin_of_rotation); // rotates the box according to the config rotation setting
|
||||
|
||||
this->volumes.emplace_back(new GLVolume(color));
|
||||
GLVolume &v = *this->volumes.back();
|
||||
|
||||
if (use_VBOs)
|
||||
v.indexed_vertex_array.load_mesh_full_shading(mesh);
|
||||
|
|
|
@ -401,7 +401,7 @@ public:
|
|||
bool use_VBOs);
|
||||
|
||||
int load_wipe_tower_preview(
|
||||
int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool use_VBOs);
|
||||
int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool use_VBOs, bool size_unknown, float brim_width);
|
||||
|
||||
// Render the volumes by OpenGL.
|
||||
void render_VBOs() const;
|
||||
|
|
|
@ -305,10 +305,14 @@ const Pointfs& GLCanvas3D::Bed::get_shape() const
|
|||
return m_shape;
|
||||
}
|
||||
|
||||
void GLCanvas3D::Bed::set_shape(const Pointfs& shape)
|
||||
bool GLCanvas3D::Bed::set_shape(const Pointfs& shape)
|
||||
{
|
||||
EType new_type = _detect_type();
|
||||
if (m_shape == shape && m_type == new_type)
|
||||
// No change, no need to update the UI.
|
||||
return false;
|
||||
m_shape = shape;
|
||||
m_type = _detect_type();
|
||||
m_type = new_type;
|
||||
|
||||
_calc_bounding_box();
|
||||
|
||||
|
@ -324,6 +328,8 @@ void GLCanvas3D::Bed::set_shape(const Pointfs& shape)
|
|||
_calc_gridlines(poly, bed_bbox);
|
||||
|
||||
m_polygon = offset_ex(poly.contour, (float)bed_bbox.radius() * 1.7f, jtRound, scale_(0.5))[0].contour;
|
||||
// Let the calee to update the UI.
|
||||
return true;
|
||||
}
|
||||
|
||||
const BoundingBoxf3& GLCanvas3D::Bed::get_bounding_box() const
|
||||
|
@ -1941,9 +1947,7 @@ void GLCanvas3D::set_model(Model* model)
|
|||
|
||||
void GLCanvas3D::set_bed_shape(const Pointfs& shape)
|
||||
{
|
||||
bool new_shape = (shape != m_bed.get_shape());
|
||||
if (new_shape)
|
||||
m_bed.set_shape(shape);
|
||||
bool new_shape = m_bed.set_shape(shape);
|
||||
|
||||
// Set the origin and size for painting of the coordinate system axes.
|
||||
m_axes.origin = Pointf3(0.0, 0.0, (coordf_t)GROUND_Z);
|
||||
|
@ -2314,7 +2318,12 @@ void GLCanvas3D::reload_scene(bool force)
|
|||
float w = dynamic_cast<const ConfigOptionFloat*>(m_config->option("wipe_tower_width"))->value;
|
||||
float a = dynamic_cast<const ConfigOptionFloat*>(m_config->option("wipe_tower_rotation_angle"))->value;
|
||||
|
||||
m_volumes.load_wipe_tower_preview(1000, x, y, w, 15.0f * (float)(extruders_count - 1), (float)height, a, m_use_VBOs && m_initialized);
|
||||
float depth = m_print->get_wipe_tower_depth();
|
||||
if (!m_print->state.is_done(psWipeTower))
|
||||
depth = (900.f/w) * (float)(extruders_count - 1) ;
|
||||
|
||||
m_volumes.load_wipe_tower_preview(1000, x, y, w, depth, (float)height, a, m_use_VBOs && m_initialized, !m_print->state.is_done(psWipeTower),
|
||||
m_print->config.nozzle_diameter.values[0] * 1.25f * 4.5f);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4063,6 +4072,8 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const std::vector<std::string>& str_
|
|||
{
|
||||
const Print *print;
|
||||
const std::vector<float> *tool_colors;
|
||||
WipeTower::xy wipe_tower_pos;
|
||||
float wipe_tower_angle;
|
||||
|
||||
// Number of vertices (each vertex is 6x4=24 bytes long)
|
||||
static const size_t alloc_size_max() { return 131072; } // 3.15MB
|
||||
|
@ -4095,6 +4106,9 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const std::vector<std::string>& str_
|
|||
if (m_print->m_wipe_tower_final_purge)
|
||||
ctxt.final.emplace_back(*m_print->m_wipe_tower_final_purge.get());
|
||||
|
||||
ctxt.wipe_tower_angle = ctxt.print->config.wipe_tower_rotation_angle.value/180.f * M_PI;
|
||||
ctxt.wipe_tower_pos = WipeTower::xy(ctxt.print->config.wipe_tower_x.value, ctxt.print->config.wipe_tower_y.value);
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - start";
|
||||
|
||||
//FIXME Improve the heuristics for a grain size.
|
||||
|
@ -4152,12 +4166,25 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const std::vector<std::string>& str_
|
|||
lines.reserve(n_lines);
|
||||
widths.reserve(n_lines);
|
||||
heights.assign(n_lines, extrusions.layer_height);
|
||||
WipeTower::Extrusion e_prev = extrusions.extrusions[i-1];
|
||||
|
||||
if (!extrusions.priming) { // wipe tower extrusions describe the wipe tower at the origin with no rotation
|
||||
e_prev.pos.rotate(ctxt.wipe_tower_angle);
|
||||
e_prev.pos.translate(ctxt.wipe_tower_pos);
|
||||
}
|
||||
|
||||
for (; i < j; ++i) {
|
||||
const WipeTower::Extrusion &e = extrusions.extrusions[i];
|
||||
WipeTower::Extrusion e = extrusions.extrusions[i];
|
||||
assert(e.width > 0.f);
|
||||
const WipeTower::Extrusion &e_prev = *(&e - 1);
|
||||
if (!extrusions.priming) {
|
||||
e.pos.rotate(ctxt.wipe_tower_angle);
|
||||
e.pos.translate(ctxt.wipe_tower_pos);
|
||||
}
|
||||
|
||||
lines.emplace_back(Point::new_scale(e_prev.pos.x, e_prev.pos.y), Point::new_scale(e.pos.x, e.pos.y));
|
||||
widths.emplace_back(e.width);
|
||||
|
||||
e_prev = e;
|
||||
}
|
||||
_3DScene::thick_lines_to_verts(lines, widths, heights, lines.front().a == lines.back().b, extrusions.print_z,
|
||||
*vols[ctxt.volume_idx(e.tool, 0)]);
|
||||
|
@ -4716,8 +4743,11 @@ void GLCanvas3D::_load_shells()
|
|||
const PrintConfig& config = m_print->config;
|
||||
unsigned int extruders_count = config.nozzle_diameter.size();
|
||||
if ((extruders_count > 1) && config.single_extruder_multi_material && config.wipe_tower && !config.complete_objects) {
|
||||
const float width_per_extruder = 15.0f; // a simple workaround after wipe_tower_per_color_wipe got obsolete
|
||||
m_volumes.load_wipe_tower_preview(1000, config.wipe_tower_x, config.wipe_tower_y, config.wipe_tower_width, width_per_extruder * (extruders_count - 1), max_z, config.wipe_tower_rotation_angle, m_use_VBOs && m_initialized);
|
||||
float depth = m_print->get_wipe_tower_depth();
|
||||
if (!m_print->state.is_done(psWipeTower))
|
||||
depth = (900.f/config.wipe_tower_width) * (float)(extruders_count - 1) ;
|
||||
m_volumes.load_wipe_tower_preview(1000, config.wipe_tower_x, config.wipe_tower_y, config.wipe_tower_width, depth, max_z, config.wipe_tower_rotation_angle,
|
||||
m_use_VBOs && m_initialized, !m_print->state.is_done(psWipeTower), m_print->config.nozzle_diameter.values[0] * 1.25f * 4.5f);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -162,7 +162,8 @@ public:
|
|||
bool is_custom() const;
|
||||
|
||||
const Pointfs& get_shape() const;
|
||||
void set_shape(const Pointfs& shape);
|
||||
// Return true if the bed shape changed, so the calee will update the UI.
|
||||
bool set_shape(const Pointfs& shape);
|
||||
|
||||
const BoundingBoxf3& get_bounding_box() const;
|
||||
bool contains(const Point& point) const;
|
||||
|
|
|
@ -903,6 +903,7 @@ void add_frequently_changed_parameters(wxWindow* parent, wxBoxSizer* sizer, wxFl
|
|||
std::vector<float> extruders = dlg.get_extruders();
|
||||
(config.option<ConfigOptionFloats>("wiping_volumes_matrix"))->values = std::vector<double>(matrix.begin(),matrix.end());
|
||||
(config.option<ConfigOptionFloats>("wiping_volumes_extruders"))->values = std::vector<double>(extruders.begin(),extruders.end());
|
||||
g_on_request_update_callback.call();
|
||||
}
|
||||
}));
|
||||
return sizer;
|
||||
|
@ -919,7 +920,6 @@ ConfigOptionsGroup* get_optgroup()
|
|||
return m_optgroup.get();
|
||||
}
|
||||
|
||||
|
||||
wxButton* get_wiping_dialog_button()
|
||||
{
|
||||
return g_wiping_dialog_button;
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
#include "Config.hpp"
|
||||
#include "../../libslic3r/Utils.hpp"
|
||||
|
||||
#include <wx/intl.h>
|
||||
#include <wx/string.h>
|
||||
|
@ -171,6 +172,9 @@ wxString from_u8(const std::string &str);
|
|||
|
||||
void add_frequently_changed_parameters(wxWindow* parent, wxBoxSizer* sizer, wxFlexGridSizer* preset_sizer);
|
||||
|
||||
// Callback to trigger a configuration update timer on the Plater.
|
||||
static PerlCallback g_on_request_update_callback;
|
||||
|
||||
ConfigOptionsGroup* get_optgroup();
|
||||
wxButton* get_wiping_dialog_button();
|
||||
|
||||
|
|
|
@ -313,11 +313,13 @@ const std::vector<std::string>& Preset::filament_options()
|
|||
{
|
||||
static std::vector<std::string> s_opts {
|
||||
"filament_colour", "filament_diameter", "filament_type", "filament_soluble", "filament_notes", "filament_max_volumetric_speed",
|
||||
"extrusion_multiplier", "filament_density", "filament_cost", "filament_loading_speed", "filament_unloading_speed", "filament_toolchange_delay",
|
||||
"filament_cooling_moves", "filament_cooling_initial_speed", "filament_cooling_final_speed", "filament_ramming_parameters", "temperature",
|
||||
"first_layer_temperature", "bed_temperature", "first_layer_bed_temperature", "fan_always_on", "cooling", "min_fan_speed", "max_fan_speed",
|
||||
"bridge_fan_speed", "disable_fan_first_layers", "fan_below_layer_time", "slowdown_below_layer_time", "min_print_speed",
|
||||
"start_filament_gcode", "end_filament_gcode","compatible_printers", "compatible_printers_condition", "inherits"
|
||||
"extrusion_multiplier", "filament_density", "filament_cost",
|
||||
"filament_loading_speed", "filament_load_time", "filament_unloading_speed", "filament_unload_time", "filament_toolchange_delay",
|
||||
"filament_cooling_moves", "filament_cooling_initial_speed", "filament_cooling_final_speed", "filament_ramming_parameters",
|
||||
"filament_minimal_purge_on_wipe_tower", "temperature", "first_layer_temperature", "bed_temperature", "first_layer_bed_temperature",
|
||||
"fan_always_on", "cooling", "min_fan_speed", "max_fan_speed", "bridge_fan_speed", "disable_fan_first_layers", "fan_below_layer_time",
|
||||
"slowdown_below_layer_time", "min_print_speed", "start_filament_gcode", "end_filament_gcode","compatible_printers", "compatible_printers_condition",
|
||||
"inherits"
|
||||
};
|
||||
return s_opts;
|
||||
}
|
||||
|
@ -332,7 +334,7 @@ const std::vector<std::string>& Preset::printer_options()
|
|||
"single_extruder_multi_material", "start_gcode", "end_gcode", "before_layer_gcode", "layer_gcode", "toolchange_gcode",
|
||||
"between_objects_gcode", "printer_vendor", "printer_model", "printer_variant", "printer_notes", "cooling_tube_retraction",
|
||||
"cooling_tube_length", "parking_pos_retraction", "extra_loading_move", "max_print_height", "default_print_profile", "inherits",
|
||||
"silent_mode", "machine_max_acceleration_extruding", "machine_max_acceleration_retracting",
|
||||
"remaining_times", "silent_mode", "machine_max_acceleration_extruding", "machine_max_acceleration_retracting",
|
||||
"machine_max_acceleration_x", "machine_max_acceleration_y", "machine_max_acceleration_z", "machine_max_acceleration_e",
|
||||
"machine_max_feedrate_x", "machine_max_feedrate_y", "machine_max_feedrate_z", "machine_max_feedrate_e",
|
||||
"machine_min_extruding_rate", "machine_min_travel_rate",
|
||||
|
|
|
@ -1292,10 +1292,13 @@ void TabFilament::build()
|
|||
optgroup = page->new_optgroup(_(L("Toolchange parameters with single extruder MM printers")));
|
||||
optgroup->append_single_option_line("filament_loading_speed");
|
||||
optgroup->append_single_option_line("filament_unloading_speed");
|
||||
optgroup->append_single_option_line("filament_load_time");
|
||||
optgroup->append_single_option_line("filament_unload_time");
|
||||
optgroup->append_single_option_line("filament_toolchange_delay");
|
||||
optgroup->append_single_option_line("filament_cooling_moves");
|
||||
optgroup->append_single_option_line("filament_cooling_initial_speed");
|
||||
optgroup->append_single_option_line("filament_cooling_final_speed");
|
||||
optgroup->append_single_option_line("filament_minimal_purge_on_wipe_tower");
|
||||
|
||||
line = { _(L("Ramming")), "" };
|
||||
line.widget = [this](wxWindow* parent){
|
||||
|
@ -1607,6 +1610,7 @@ void TabPrinter::build()
|
|||
optgroup = page->new_optgroup(_(L("Firmware")));
|
||||
optgroup->append_single_option_line("gcode_flavor");
|
||||
optgroup->append_single_option_line("silent_mode");
|
||||
optgroup->append_single_option_line("remaining_times");
|
||||
|
||||
optgroup->m_on_change = [this, optgroup](t_config_option_key opt_key, boost::any value){
|
||||
wxTheApp->CallAfter([this, opt_key, value](){
|
||||
|
|
|
@ -104,3 +104,10 @@ void fix_model_by_win10_sdk_gui(ModelObject *model_object_src, Print *print, Mod
|
|||
|
||||
void set_3DScene(SV *scene)
|
||||
%code%{ Slic3r::GUI::set_3DScene((_3DScene *)wxPli_sv_2_object(aTHX_ scene, "Slic3r::Model::3DScene") ); %};
|
||||
|
||||
void register_on_request_update_callback(SV* callback)
|
||||
%code%{ Slic3r::GUI::g_on_request_update_callback.register_callback(callback); %};
|
||||
|
||||
void deregister_on_request_update_callback()
|
||||
%code%{ Slic3r::GUI::g_on_request_update_callback.deregister_callback(); %};
|
||||
|
||||
|
|
|
@ -89,7 +89,7 @@
|
|||
|
||||
std::vector<int> load_object(ModelObject *object, int obj_idx, std::vector<int> instance_idxs, std::string color_by, std::string select_by, std::string drag_by, bool use_VBOs);
|
||||
|
||||
int load_wipe_tower_preview(int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool use_VBOs);
|
||||
int load_wipe_tower_preview(int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool use_VBOs, bool size_unknown, float brim_width);
|
||||
|
||||
void erase()
|
||||
%code{% THIS->clear(); %};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue