Merge remote-tracking branch 'remotes/origin/wipe_tower_improvements'
This commit is contained in:
commit
b79692c35e
@ -52,9 +52,8 @@ sub new {
|
||||
$self->{config} = Slic3r::Config::new_from_defaults_keys([qw(
|
||||
bed_shape complete_objects extruder_clearance_radius skirts skirt_distance brim_width variable_layer_height
|
||||
serial_port serial_speed octoprint_host octoprint_apikey octoprint_cafile
|
||||
nozzle_diameter single_extruder_multi_material
|
||||
wipe_tower wipe_tower_x wipe_tower_y wipe_tower_width wipe_tower_per_color_wipe extruder_colour filament_colour
|
||||
max_print_height
|
||||
nozzle_diameter single_extruder_multi_material wipe_tower wipe_tower_x wipe_tower_y wipe_tower_width
|
||||
wipe_tower_rotation_angle extruder_colour filament_colour max_print_height
|
||||
)]);
|
||||
# C++ Slic3r::Model with Perl extensions in Slic3r/Model.pm
|
||||
$self->{model} = Slic3r::Model->new;
|
||||
|
@ -210,9 +210,10 @@ sub reload_scene {
|
||||
if ($extruders_count > 1 && $self->{config}->single_extruder_multi_material && $self->{config}->wipe_tower &&
|
||||
! $self->{config}->complete_objects) {
|
||||
$self->volumes->load_wipe_tower_preview(1000,
|
||||
$self->{config}->wipe_tower_x, $self->{config}->wipe_tower_y,
|
||||
$self->{config}->wipe_tower_width, $self->{config}->wipe_tower_per_color_wipe * ($extruders_count - 1),
|
||||
$self->{model}->bounding_box->z_max, $self->UseVBOs);
|
||||
$self->{config}->wipe_tower_x, $self->{config}->wipe_tower_y, $self->{config}->wipe_tower_width,
|
||||
#$self->{config}->wipe_tower_per_color_wipe# 15 * ($extruders_count - 1), # this is just a hack when the config parameter became obsolete
|
||||
15 * ($extruders_count - 1),
|
||||
$self->{model}->bounding_box->z_max, $self->{config}->wipe_tower_rotation_angle, $self->UseVBOs);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -57,7 +57,7 @@ plan tests => 8;
|
||||
my $config = Slic3r::Config::new_from_defaults;
|
||||
$config->set('layer_height', 0.2);
|
||||
$config->set('first_layer_height', 0.2);
|
||||
$config->set('nozzle_diameter', [0.5]);
|
||||
$config->set('nozzle_diameter', [0.5,0.5,0.5,0.5]);
|
||||
$config->set('infill_every_layers', 2);
|
||||
$config->set('perimeter_extruder', 1);
|
||||
$config->set('infill_extruder', 2);
|
||||
|
@ -49,7 +49,7 @@ use Slic3r::Test;
|
||||
my $parser = Slic3r::GCode::PlaceholderParser->new;
|
||||
my $config = Slic3r::Config::new_from_defaults;
|
||||
$config->set('printer_notes', ' PRINTER_VENDOR_PRUSA3D PRINTER_MODEL_MK2 ');
|
||||
$config->set('nozzle_diameter', [0.6, 0.6, 0.6, 0.6]);
|
||||
$config->set('nozzle_diameter', [0.6,0.6,0.6,0.6]);
|
||||
$parser->apply_config($config);
|
||||
$parser->set('foo' => 0);
|
||||
$parser->set('bar' => 2);
|
||||
@ -123,6 +123,7 @@ use Slic3r::Test;
|
||||
|
||||
{
|
||||
my $config = Slic3r::Config->new;
|
||||
$config->set('nozzle_diameter', [0.6,0.6,0.6,0.6]);
|
||||
$config->set('extruder', 2);
|
||||
$config->set('first_layer_temperature', [200,205]);
|
||||
|
||||
@ -204,6 +205,7 @@ use Slic3r::Test;
|
||||
|
||||
{
|
||||
my $config = Slic3r::Config->new;
|
||||
$config->set('nozzle_diameter', [0.6,0.6,0.6,0.6,0.6]);
|
||||
$config->set('start_gcode', qq!
|
||||
;substitution:{if infill_extruder==1}if block
|
||||
{elsif infill_extruder==2}elsif block 1
|
||||
@ -228,6 +230,7 @@ use Slic3r::Test;
|
||||
|
||||
{
|
||||
my $config = Slic3r::Config->new;
|
||||
$config->set('nozzle_diameter', [0.6,0.6,0.6,0.6]);
|
||||
$config->set('start_gcode',
|
||||
';substitution:{if infill_extruder==1}{if perimeter_extruder==1}block11{else}block12{endif}' .
|
||||
'{elsif infill_extruder==2}{if perimeter_extruder==1}block21{else}block22{endif}' .
|
||||
|
4
t/fill.t
4
t/fill.t
@ -164,6 +164,7 @@ SKIP:
|
||||
|
||||
for my $pattern (qw(rectilinear honeycomb hilbertcurve concentric)) {
|
||||
my $config = Slic3r::Config::new_from_defaults;
|
||||
$config->set('nozzle_diameter', [0.4,0.4,0.4,0.4]);
|
||||
$config->set('fill_pattern', $pattern);
|
||||
$config->set('external_fill_pattern', $pattern);
|
||||
$config->set('perimeters', 1);
|
||||
@ -195,6 +196,7 @@ for my $pattern (qw(rectilinear honeycomb hilbertcurve concentric)) {
|
||||
|
||||
{
|
||||
my $config = Slic3r::Config::new_from_defaults;
|
||||
$config->set('nozzle_diameter', [0.4,0.4,0.4,0.4]);
|
||||
$config->set('infill_only_where_needed', 1);
|
||||
$config->set('bottom_solid_layers', 0);
|
||||
$config->set('infill_extruder', 2);
|
||||
@ -276,7 +278,7 @@ for my $pattern (qw(rectilinear honeycomb hilbertcurve concentric)) {
|
||||
$config->set('fill_density', 0);
|
||||
$config->set('layer_height', 0.2);
|
||||
$config->set('first_layer_height', 0.2);
|
||||
$config->set('nozzle_diameter', [0.35]);
|
||||
$config->set('nozzle_diameter', [0.35,0.35,0.35,0.35]);
|
||||
$config->set('infill_extruder', 2);
|
||||
$config->set('solid_infill_extruder', 2);
|
||||
$config->set('infill_extrusion_width', 0.52);
|
||||
|
@ -16,6 +16,7 @@ use Slic3r::Test;
|
||||
|
||||
{
|
||||
my $config = Slic3r::Config::new_from_defaults;
|
||||
$config->set('nozzle_diameter', [0.6,0.6,0.6,0.6]);
|
||||
$config->set('raft_layers', 2);
|
||||
$config->set('infill_extruder', 2);
|
||||
$config->set('solid_infill_extruder', 3);
|
||||
@ -89,6 +90,7 @@ use Slic3r::Test;
|
||||
|
||||
{
|
||||
my $config = Slic3r::Config::new_from_defaults;
|
||||
$config->set('nozzle_diameter', [0.6,0.6,0.6,0.6]);
|
||||
$config->set('support_material_extruder', 3);
|
||||
|
||||
my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
|
||||
@ -97,6 +99,7 @@ use Slic3r::Test;
|
||||
|
||||
{
|
||||
my $config = Slic3r::Config->new;
|
||||
$config->set('nozzle_diameter', [0.6,0.6,0.6,0.6]);
|
||||
$config->set('extruder', 2);
|
||||
|
||||
my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
|
||||
@ -105,6 +108,7 @@ use Slic3r::Test;
|
||||
|
||||
{
|
||||
my $config = Slic3r::Config->new;
|
||||
$config->set('nozzle_diameter', [0.6,0.6,0.6,0.6]);
|
||||
$config->set('perimeter_extruder', 2);
|
||||
$config->set('infill_extruder', 2);
|
||||
$config->set('support_material_extruder', 2);
|
||||
@ -126,6 +130,7 @@ use Slic3r::Test;
|
||||
$upper_config->set('bottom_solid_layers', 1);
|
||||
$upper_config->set('top_solid_layers', 0);
|
||||
my $config = Slic3r::Config::new_from_defaults;
|
||||
$config->set('nozzle_diameter', [0.6,0.6,0.6,0.6]);
|
||||
$config->set('fill_density', 0);
|
||||
$config->set('solid_infill_speed', 99);
|
||||
$config->set('top_solid_infill_speed', 99);
|
||||
@ -172,6 +177,7 @@ use Slic3r::Test;
|
||||
my $object = $model->objects->[0];
|
||||
|
||||
my $config = Slic3r::Config::new_from_defaults;
|
||||
$config->set('nozzle_diameter', [0.6,0.6,0.6,0.6]);
|
||||
$config->set('layer_height', 0.4);
|
||||
$config->set('first_layer_height', '100%');
|
||||
$config->set('skirts', 0);
|
||||
|
@ -95,6 +95,7 @@ use Slic3r::Test qw(_eq);
|
||||
1;
|
||||
};
|
||||
|
||||
$config->set('nozzle_diameter', [0.6,0.6,0.6,0.6]);
|
||||
$config->set('first_layer_height', $config->layer_height);
|
||||
$config->set('first_layer_speed', '100%');
|
||||
$config->set('start_gcode', ''); # to avoid dealing with the nozzle lift in start G-code
|
||||
@ -207,6 +208,7 @@ use Slic3r::Test qw(_eq);
|
||||
|
||||
{
|
||||
my $config = Slic3r::Config::new_from_defaults;
|
||||
$config->set('nozzle_diameter', [0.6,0.6,0.6,0.6]);
|
||||
$config->set('start_gcode', '');
|
||||
$config->set('retract_lift', [3, 4]);
|
||||
|
||||
|
@ -202,6 +202,10 @@ add_library(libslic3r_gui STATIC
|
||||
${LIBDIR}/slic3r/GUI/2DBed.hpp
|
||||
${LIBDIR}/slic3r/GUI/wxExtensions.cpp
|
||||
${LIBDIR}/slic3r/GUI/wxExtensions.hpp
|
||||
${LIBDIR}/slic3r/GUI/WipeTowerDialog.cpp
|
||||
${LIBDIR}/slic3r/GUI/WipeTowerDialog.hpp
|
||||
${LIBDIR}/slic3r/GUI/RammingChart.cpp
|
||||
${LIBDIR}/slic3r/GUI/RammingChart.hpp
|
||||
${LIBDIR}/slic3r/GUI/BonjourDialog.cpp
|
||||
${LIBDIR}/slic3r/GUI/BonjourDialog.hpp
|
||||
${LIBDIR}/slic3r/Config/Snapshot.cpp
|
||||
|
@ -9,74 +9,115 @@
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
static inline Polyline make_wave_vertical(
|
||||
double width, double height, double x0,
|
||||
double segmentSize, double scaleFactor,
|
||||
double z_cos, double z_sin, bool flip)
|
||||
static inline double f(double x, double z_sin, double z_cos, bool vertical, bool flip)
|
||||
{
|
||||
Polyline polyline;
|
||||
polyline.points.emplace_back(Point(coord_t(clamp(0., width, x0) * scaleFactor), 0));
|
||||
double phase_offset_sin = (z_cos < 0 ? M_PI : 0) + M_PI;
|
||||
double phase_offset_cos = (z_cos < 0 ? M_PI : 0) + M_PI + (flip ? M_PI : 0.);
|
||||
for (double y = 0.; y < height + segmentSize; y += segmentSize) {
|
||||
y = std::min(y, height);
|
||||
double a = sin(y + phase_offset_sin);
|
||||
if (vertical) {
|
||||
double phase_offset = (z_cos < 0 ? M_PI : 0) + M_PI;
|
||||
double a = sin(x + phase_offset);
|
||||
double b = - z_cos;
|
||||
double res = z_sin * cos(y + phase_offset_cos);
|
||||
double res = z_sin * cos(x + phase_offset + (flip ? M_PI : 0.));
|
||||
double r = sqrt(sqr(a) + sqr(b));
|
||||
double x = clamp(0., width, asin(a/r) + asin(res/r) + M_PI + x0);
|
||||
polyline.points.emplace_back(convert_to<Point>(Pointf(x, y) * scaleFactor));
|
||||
return asin(a/r) + asin(res/r) + M_PI;
|
||||
}
|
||||
if (flip)
|
||||
std::reverse(polyline.points.begin(), polyline.points.end());
|
||||
else {
|
||||
double phase_offset = z_sin < 0 ? M_PI : 0.;
|
||||
double a = cos(x + phase_offset);
|
||||
double b = - z_sin;
|
||||
double res = z_cos * sin(x + phase_offset + (flip ? 0 : M_PI));
|
||||
double r = sqrt(sqr(a) + sqr(b));
|
||||
return (asin(a/r) + asin(res/r) + 0.5 * M_PI);
|
||||
}
|
||||
}
|
||||
|
||||
static inline Polyline make_wave(
|
||||
const std::vector<Pointf>& one_period, double width, double height, double offset, double scaleFactor,
|
||||
double z_cos, double z_sin, bool vertical)
|
||||
{
|
||||
std::vector<Pointf> points = one_period;
|
||||
double period = points.back().x;
|
||||
points.pop_back();
|
||||
int n = points.size();
|
||||
do {
|
||||
points.emplace_back(Pointf(points[points.size()-n].x + period, points[points.size()-n].y));
|
||||
} while (points.back().x < width);
|
||||
points.back().x = width;
|
||||
|
||||
// and construct the final polyline to return:
|
||||
Polyline polyline;
|
||||
for (auto& point : points) {
|
||||
point.y += offset;
|
||||
point.y = clamp(0., height, double(point.y));
|
||||
if (vertical)
|
||||
std::swap(point.x, point.y);
|
||||
polyline.points.emplace_back(convert_to<Point>(point * scaleFactor));
|
||||
}
|
||||
|
||||
return polyline;
|
||||
}
|
||||
|
||||
static inline Polyline make_wave_horizontal(
|
||||
double width, double height, double y0,
|
||||
double segmentSize, double scaleFactor,
|
||||
double z_cos, double z_sin, bool flip)
|
||||
static std::vector<Pointf> make_one_period(double width, double scaleFactor, double z_cos, double z_sin, bool vertical, bool flip)
|
||||
{
|
||||
Polyline polyline;
|
||||
polyline.points.emplace_back(Point(0, coord_t(clamp(0., height, y0) * scaleFactor)));
|
||||
double phase_offset_sin = (z_sin < 0 ? M_PI : 0) + (flip ? 0 : M_PI);
|
||||
double phase_offset_cos = z_sin < 0 ? M_PI : 0.;
|
||||
for (double x = 0.; x < width + segmentSize; x += segmentSize) {
|
||||
x = std::min(x, width);
|
||||
double a = cos(x + phase_offset_cos);
|
||||
double b = - z_sin;
|
||||
double res = z_cos * sin(x + phase_offset_sin);
|
||||
double r = sqrt(sqr(a) + sqr(b));
|
||||
double y = clamp(0., height, asin(a/r) + asin(res/r) + 0.5 * M_PI + y0);
|
||||
polyline.points.emplace_back(convert_to<Point>(Pointf(x, y) * scaleFactor));
|
||||
std::vector<Pointf> points;
|
||||
double dx = M_PI_4; // very coarse spacing to begin with
|
||||
double limit = std::min(2*M_PI, width);
|
||||
for (double x = 0.; x < limit + EPSILON; x += dx) { // so the last point is there too
|
||||
x = std::min(x, limit);
|
||||
points.emplace_back(Pointf(x,f(x, z_sin,z_cos, vertical, flip)));
|
||||
}
|
||||
if (flip)
|
||||
std::reverse(polyline.points.begin(), polyline.points.end());
|
||||
return polyline;
|
||||
|
||||
// now we will check all internal points and in case some are too far from the line connecting its neighbours,
|
||||
// we will add one more point on each side:
|
||||
const double tolerance = .1;
|
||||
for (unsigned int i=1;i<points.size()-1;++i) {
|
||||
auto& lp = points[i-1]; // left point
|
||||
auto& tp = points[i]; // this point
|
||||
auto& rp = points[i+1]; // right point
|
||||
// calculate distance of the point to the line:
|
||||
double dist_mm = unscale(scaleFactor * std::abs( (rp.y - lp.y)*tp.x + (lp.x - rp.x)*tp.y + (rp.x*lp.y - rp.y*lp.x) ) / std::hypot((rp.y - lp.y),(lp.x - rp.x)));
|
||||
|
||||
if (dist_mm > tolerance) { // if the difference from straight line is more than this
|
||||
double x = 0.5f * (points[i-1].x + points[i].x);
|
||||
points.emplace_back(Pointf(x, f(x, z_sin, z_cos, vertical, flip)));
|
||||
x = 0.5f * (points[i+1].x + points[i].x);
|
||||
points.emplace_back(Pointf(x, f(x, z_sin, z_cos, vertical, flip)));
|
||||
std::sort(points.begin(), points.end()); // we added the points to the end, but need them all in order
|
||||
--i; // decrement i so we also check the first newly added point
|
||||
}
|
||||
}
|
||||
return points;
|
||||
}
|
||||
|
||||
static Polylines make_gyroid_waves(double gridZ, double density_adjusted, double line_spacing, double width, double height)
|
||||
{
|
||||
double scaleFactor = scale_(line_spacing) / density_adjusted;
|
||||
double segmentSize = 0.5 * density_adjusted;
|
||||
const double scaleFactor = scale_(line_spacing) / density_adjusted;
|
||||
//scale factor for 5% : 8 712 388
|
||||
// 1z = 10^-6 mm ?
|
||||
double z = gridZ / scaleFactor;
|
||||
double z_sin = sin(z);
|
||||
double z_cos = cos(z);
|
||||
Polylines result;
|
||||
if (std::abs(z_sin) <= std::abs(z_cos)) {
|
||||
// Vertical wave
|
||||
double x0 = M_PI * (int)((- 0.5 * M_PI) / M_PI - 1.);
|
||||
bool flip = ((int)(x0 / M_PI + 1.) & 1) != 0;
|
||||
for (; x0 < width - 0.5 * M_PI; x0 += M_PI, flip = ! flip)
|
||||
result.emplace_back(make_wave_vertical(width, height, x0, segmentSize, scaleFactor, z_cos, z_sin, flip));
|
||||
} else {
|
||||
// Horizontal wave
|
||||
bool flip = true;
|
||||
for (double y0 = 0.; y0 < height; y0 += M_PI, flip = !flip)
|
||||
result.emplace_back(make_wave_horizontal(width, height, y0, segmentSize, scaleFactor, z_cos, z_sin, flip));
|
||||
const double z = gridZ / scaleFactor;
|
||||
const double z_sin = sin(z);
|
||||
const double z_cos = cos(z);
|
||||
|
||||
bool vertical = (std::abs(z_sin) <= std::abs(z_cos));
|
||||
double lower_bound = 0.;
|
||||
double upper_bound = height;
|
||||
bool flip = true;
|
||||
if (vertical) {
|
||||
flip = false;
|
||||
lower_bound = -M_PI;
|
||||
upper_bound = width - M_PI_2;
|
||||
std::swap(width,height);
|
||||
}
|
||||
|
||||
std::vector<Pointf> one_period = make_one_period(width, scaleFactor, z_cos, z_sin, vertical, flip); // creates one period of the waves, so it doesn't have to be recalculated all the time
|
||||
Polylines result;
|
||||
|
||||
for (double y0 = lower_bound; y0 < upper_bound+EPSILON; y0 += 2*M_PI) // creates odd polylines
|
||||
result.emplace_back(make_wave(one_period, width, height, y0, scaleFactor, z_cos, z_sin, vertical));
|
||||
|
||||
flip = !flip; // even polylines are a bit shifted
|
||||
one_period = make_one_period(width, scaleFactor, z_cos, z_sin, vertical, flip); // updates the one period sample
|
||||
for (double y0 = lower_bound + M_PI; y0 < upper_bound+EPSILON; y0 += 2*M_PI) // creates even polylines
|
||||
result.emplace_back(make_wave(one_period, width, height, y0, scaleFactor, z_cos, z_sin, vertical));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -90,7 +131,7 @@ void FillGyroid::_fill_surface_single(
|
||||
// no rotation is supported for this infill pattern (yet)
|
||||
BoundingBox bb = expolygon.contour.bounding_box();
|
||||
// Density adjusted to have a good %of weight.
|
||||
double density_adjusted = params.density * 1.75;
|
||||
double density_adjusted = std::max(0., params.density * 2.);
|
||||
// Distance between the gyroid waves in scaled coordinates.
|
||||
coord_t distance = coord_t(scale_(this->spacing) / density_adjusted);
|
||||
|
||||
|
@ -17,12 +17,26 @@ public:
|
||||
struct xy
|
||||
{
|
||||
xy(float x = 0.f, float y = 0.f) : x(x), y(y) {}
|
||||
xy(const xy& pos,float xp,float yp) : x(pos.x+xp), y(pos.y+yp) {}
|
||||
xy operator+(const xy &rhs) const { xy out(*this); out.x += rhs.x; out.y += rhs.y; return out; }
|
||||
xy operator-(const xy &rhs) const { xy out(*this); out.x -= rhs.x; out.y -= rhs.y; return out; }
|
||||
xy& operator+=(const xy &rhs) { x += rhs.x; y += rhs.y; return *this; }
|
||||
xy& operator-=(const xy &rhs) { x -= rhs.x; y -= rhs.y; return *this; }
|
||||
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 {
|
||||
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;
|
||||
}
|
||||
|
||||
float x;
|
||||
float y;
|
||||
};
|
||||
@ -112,17 +126,15 @@ public:
|
||||
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,
|
||||
// May be used by a stand alone post processor.
|
||||
Purpose purpose = PURPOSE_MOVE_TO_TOWER_AND_EXTRUDE) = 0;
|
||||
bool last_wipe_inside_wipe_tower) = 0;
|
||||
|
||||
// Returns gcode for toolchange and the end position.
|
||||
// if new_tool == -1, just unload the current filament over the wipe tower.
|
||||
virtual ToolChangeResult tool_change(unsigned int new_tool, bool last_in_layer, Purpose purpose = PURPOSE_MOVE_TO_TOWER_AND_EXTRUDE) = 0;
|
||||
virtual ToolChangeResult tool_change(unsigned int new_tool, bool last_in_layer) = 0;
|
||||
|
||||
// Close the current wipe tower layer with a perimeter and possibly fill the unfilled space with a zig-zag.
|
||||
// Call this method only if layer_finished() is false.
|
||||
virtual ToolChangeResult finish_layer(Purpose purpose = PURPOSE_MOVE_TO_TOWER_AND_EXTRUDE) = 0;
|
||||
virtual ToolChangeResult finish_layer() = 0;
|
||||
|
||||
// Is the current layer finished? A layer is finished if either the wipe tower is finished, or
|
||||
// the wipe tower has been completely covered by the tool change extrusions,
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,13 +1,14 @@
|
||||
#ifndef WipeTowerPrusaMM_hpp_
|
||||
#define WipeTowerPrusaMM_hpp_
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
|
||||
#include "WipeTower.hpp"
|
||||
|
||||
|
||||
namespace Slic3r
|
||||
{
|
||||
|
||||
@ -15,6 +16,8 @@ namespace PrusaMultiMaterial {
|
||||
class Writer;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class WipeTowerPrusaMM : public WipeTower
|
||||
{
|
||||
public:
|
||||
@ -39,65 +42,98 @@ public:
|
||||
// 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
|
||||
WipeTowerPrusaMM(float x, float y, float width, float wipe_area, unsigned int initial_tool) :
|
||||
WipeTowerPrusaMM(float x, float y, float width, float rotation_angle, float cooling_tube_retraction,
|
||||
float cooling_tube_length, float parking_pos_retraction, float bridging, const std::vector<float>& wiping_matrix,
|
||||
unsigned int initial_tool) :
|
||||
m_wipe_tower_pos(x, y),
|
||||
m_wipe_tower_width(width),
|
||||
m_wipe_area(wipe_area),
|
||||
m_wipe_tower_rotation_angle(rotation_angle),
|
||||
m_y_shift(0.f),
|
||||
m_z_pos(0.f),
|
||||
m_current_tool(initial_tool)
|
||||
m_is_first_layer(false),
|
||||
m_cooling_tube_retraction(cooling_tube_retraction),
|
||||
m_cooling_tube_length(cooling_tube_length),
|
||||
m_parking_pos_retraction(parking_pos_retraction),
|
||||
m_bridging(bridging),
|
||||
m_current_tool(initial_tool)
|
||||
{
|
||||
for (size_t i = 0; i < 4; ++ i) {
|
||||
// Extruder specific parameters.
|
||||
m_material[i] = PLA;
|
||||
m_temperature[i] = 0;
|
||||
m_first_layer_temperature[i] = 0;
|
||||
}
|
||||
unsigned int number_of_extruders = (unsigned int)(sqrt(wiping_matrix.size())+WT_EPSILON);
|
||||
for (unsigned int i = 0; i<number_of_extruders; ++i)
|
||||
wipe_volumes.push_back(std::vector<float>(wiping_matrix.begin()+i*number_of_extruders,wiping_matrix.begin()+(i+1)*number_of_extruders));
|
||||
}
|
||||
|
||||
virtual ~WipeTowerPrusaMM() {}
|
||||
|
||||
// _retract - retract value in mm
|
||||
void set_retract(float retract) { m_retract = retract; }
|
||||
|
||||
// _zHop - z hop value in mm
|
||||
void set_zhop(float zhop) { m_zhop = zhop; }
|
||||
|
||||
// Set the extruder properties.
|
||||
void set_extruder(size_t idx, material_type material, int temp, int first_layer_temp)
|
||||
void set_extruder(size_t idx, material_type material, int temp, int first_layer_temp, float loading_speed,
|
||||
float unloading_speed, float delay, float cooling_time, std::string ramming_parameters, float nozzle_diameter)
|
||||
{
|
||||
m_material[idx] = material;
|
||||
m_temperature[idx] = temp;
|
||||
m_first_layer_temperature[idx] = first_layer_temp;
|
||||
//while (m_filpar.size() < idx+1) // makes sure the required element is in the vector
|
||||
m_filpar.push_back(FilamentParameters());
|
||||
|
||||
m_filpar[idx].material = material;
|
||||
m_filpar[idx].temperature = temp;
|
||||
m_filpar[idx].first_layer_temperature = first_layer_temp;
|
||||
m_filpar[idx].loading_speed = loading_speed;
|
||||
m_filpar[idx].unloading_speed = unloading_speed;
|
||||
m_filpar[idx].delay = delay;
|
||||
m_filpar[idx].cooling_time = cooling_time;
|
||||
m_filpar[idx].nozzle_diameter = nozzle_diameter; // to be used in future with (non-single) multiextruder MM
|
||||
|
||||
m_perimeter_width = nozzle_diameter * Width_To_Nozzle_Ratio; // all extruders are now assumed to have the same diameter
|
||||
|
||||
std::stringstream stream{ramming_parameters};
|
||||
float speed = 0.f;
|
||||
stream >> m_filpar[idx].ramming_line_width_multiplicator >> m_filpar[idx].ramming_step_multiplicator;
|
||||
m_filpar[idx].ramming_line_width_multiplicator /= 100;
|
||||
m_filpar[idx].ramming_step_multiplicator /= 100;
|
||||
while (stream >> speed)
|
||||
m_filpar[idx].ramming_speed.push_back(speed);
|
||||
}
|
||||
|
||||
|
||||
// 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, bool brim);
|
||||
|
||||
// Iterates through prepared m_plan, generates ToolChangeResults and appends them to "result"
|
||||
void generate(std::vector<std::vector<WipeTower::ToolChangeResult>> &result);
|
||||
|
||||
|
||||
|
||||
// Switch to a next layer.
|
||||
virtual void set_layer(
|
||||
// Print height of this layer.
|
||||
float print_z,
|
||||
float print_z,
|
||||
// Layer height, used to calculate extrusion the rate.
|
||||
float layer_height,
|
||||
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,
|
||||
bool is_first_layer,
|
||||
// Is this the last layer of the waste tower?
|
||||
bool is_last_layer)
|
||||
bool is_last_layer)
|
||||
{
|
||||
m_z_pos = print_z;
|
||||
m_layer_height = layer_height;
|
||||
m_max_color_changes = max_tool_changes;
|
||||
m_is_first_layer = is_first_layer;
|
||||
m_is_last_layer = is_last_layer;
|
||||
// Start counting the color changes from zero. Special case: -1 - extrude a brim first.
|
||||
m_idx_tool_change_in_layer = is_first_layer ? (unsigned int)(-1) : 0;
|
||||
m_current_wipe_start_y = 0.f;
|
||||
m_print_brim = is_first_layer;
|
||||
m_depth_traversed = 0.f;
|
||||
m_current_shape = (! is_first_layer && m_current_shape == SHAPE_NORMAL) ? SHAPE_REVERSED : SHAPE_NORMAL;
|
||||
++ m_num_layer_changes;
|
||||
// Extrusion rate for an extrusion aka perimeter width 0.35mm.
|
||||
// Clamp the extrusion height to a 0.2mm layer height, independent of the nozzle diameter.
|
||||
// m_extrusion_flow = std::min(0.2f, layer_height) * 0.145f;
|
||||
// Use a strictly
|
||||
m_extrusion_flow = layer_height * 0.145f;
|
||||
if (is_first_layer) {
|
||||
this->m_num_layer_changes = 0;
|
||||
this->m_num_tool_changes = 0;
|
||||
}
|
||||
else
|
||||
++ m_num_layer_changes;
|
||||
|
||||
// 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.
|
||||
@ -115,79 +151,114 @@ public:
|
||||
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,
|
||||
// May be used by a stand alone post processor.
|
||||
Purpose purpose = PURPOSE_MOVE_TO_TOWER_AND_EXTRUDE);
|
||||
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.
|
||||
virtual ToolChangeResult tool_change(unsigned int new_tool, bool last_in_layer, Purpose purpose);
|
||||
virtual ToolChangeResult tool_change(unsigned int new_tool, bool last_in_layer);
|
||||
|
||||
// Close the current wipe tower layer with a perimeter and possibly fill the unfilled space with a zig-zag.
|
||||
// Fill the unfilled space with a sparse infill.
|
||||
// Call this method only if layer_finished() is false.
|
||||
virtual ToolChangeResult finish_layer(Purpose purpose);
|
||||
virtual ToolChangeResult finish_layer();
|
||||
|
||||
// Is the current layer finished?
|
||||
virtual bool layer_finished() const {
|
||||
return ( (m_is_first_layer ? m_wipe_tower_depth - m_perimeter_width : m_layer_info->depth) - WT_EPSILON < m_depth_traversed);
|
||||
}
|
||||
|
||||
// Is the current layer finished? A layer is finished if either the wipe tower is finished, or
|
||||
// the wipe tower has been completely covered by the tool change extrusions,
|
||||
// or the rest of the tower has been filled by a sparse infill with the finish_layer() method.
|
||||
virtual bool layer_finished() const
|
||||
{ return m_idx_tool_change_in_layer == m_max_color_changes; }
|
||||
|
||||
private:
|
||||
WipeTowerPrusaMM();
|
||||
|
||||
// A fill-in direction (positive Y, negative Y) alternates with each layer.
|
||||
enum wipe_shape
|
||||
enum wipe_shape // A fill-in direction
|
||||
{
|
||||
SHAPE_NORMAL = 1,
|
||||
SHAPE_NORMAL = 1,
|
||||
SHAPE_REVERSED = -1
|
||||
};
|
||||
|
||||
// Left front corner of the wipe tower in mm.
|
||||
xy m_wipe_tower_pos;
|
||||
// Width of the wipe tower.
|
||||
float m_wipe_tower_width;
|
||||
// Per color Y span.
|
||||
float m_wipe_area;
|
||||
// Current Z position.
|
||||
float m_z_pos = 0.f;
|
||||
// Current layer height.
|
||||
float m_layer_height = 0.f;
|
||||
// Maximum number of color changes per layer.
|
||||
size_t m_max_color_changes = 0;
|
||||
// Is this the 1st layer of the print? If so, print the brim around the waste tower.
|
||||
bool m_is_first_layer = false;
|
||||
// Is this the last layer of this waste tower?
|
||||
bool m_is_last_layer = false;
|
||||
|
||||
const bool m_peters_wipe_tower = false; // sparse wipe tower inspired by Peter's post processor - not finished yet
|
||||
const float Filament_Area = M_PI * 1.75f * 1.75f / 4.f; // filament area in mm^2
|
||||
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;
|
||||
|
||||
|
||||
xy 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
|
||||
float m_wipe_tower_rotation_angle = 0.f; // Wipe tower rotation angle in degrees (with respect to x axis)
|
||||
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.
|
||||
bool m_is_first_layer = false;// Is this the 1st layer of the print? If so, print the brim around the waste tower.
|
||||
|
||||
// G-code generator parameters.
|
||||
float m_zhop = 0.5f;
|
||||
float m_retract = 4.f;
|
||||
// Width of an extrusion line, also a perimeter spacing for 100% infill.
|
||||
float m_perimeter_width = 0.5f;
|
||||
// Extrusion flow is derived from m_perimeter_width, layer height and filament diameter.
|
||||
float m_extrusion_flow = 0.029f;
|
||||
float m_cooling_tube_retraction = 0.f;
|
||||
float m_cooling_tube_length = 0.f;
|
||||
float m_parking_pos_retraction = 0.f;
|
||||
float m_bridging = 0.f;
|
||||
bool m_adhesion = true;
|
||||
|
||||
float m_perimeter_width = 0.4 * Width_To_Nozzle_Ratio; // Width of an extrusion line, also a perimeter spacing for 100% infill.
|
||||
float m_extrusion_flow = 0.038; //0.029f;// Extrusion flow is derived from m_perimeter_width, layer height and filament diameter.
|
||||
|
||||
|
||||
struct FilamentParameters {
|
||||
material_type material = PLA;
|
||||
int temperature = 0;
|
||||
int first_layer_temperature = 0;
|
||||
float loading_speed = 0.f;
|
||||
float unloading_speed = 0.f;
|
||||
float delay = 0.f ;
|
||||
float cooling_time = 0.f;
|
||||
float ramming_line_width_multiplicator = 0.f;
|
||||
float ramming_step_multiplicator = 0.f;
|
||||
std::vector<float> ramming_speed;
|
||||
float nozzle_diameter;
|
||||
};
|
||||
|
||||
// Extruder specific parameters.
|
||||
material_type m_material[4];
|
||||
int m_temperature[4];
|
||||
int m_first_layer_temperature[4];
|
||||
std::vector<FilamentParameters> m_filpar;
|
||||
|
||||
// State of the wiper tower generator.
|
||||
// Layer change counter for the output statistics.
|
||||
unsigned int m_num_layer_changes = 0;
|
||||
// Tool change change counter for the output statistics.
|
||||
unsigned int m_num_tool_changes = 0;
|
||||
// Layer change counter in this layer. Counting up to m_max_color_changes.
|
||||
unsigned int m_idx_tool_change_in_layer = 0;
|
||||
|
||||
// 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;
|
||||
unsigned int m_current_tool = 0;
|
||||
// Current y position at the wipe tower.
|
||||
float m_current_wipe_start_y = 0.f;
|
||||
// How much to wipe the 1st extruder over the wipe tower at the 1st layer
|
||||
// after the wipe tower brim has been extruded?
|
||||
float m_initial_extra_wipe = 0.f;
|
||||
std::vector<std::vector<float>> wipe_volumes;
|
||||
|
||||
float m_depth_traversed = 0.f; // Current y position at the wipe tower.
|
||||
bool m_left_to_right = true;
|
||||
float m_extra_spacing = 1.f;
|
||||
|
||||
|
||||
// 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-M_PI/4.f)) / Filament_Area;
|
||||
}
|
||||
|
||||
// Calculates length of extrusion line to extrude given volume
|
||||
float volume_to_length(float volume, float line_width, float layer_height) const {
|
||||
return volume / (layer_height * (line_width - layer_height * (1. - M_PI / 4.)));
|
||||
}
|
||||
|
||||
// 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();
|
||||
|
||||
// Goes through m_plan, calculates border and finish_layer extrusions and subtracts them from last wipe
|
||||
void save_on_last_wipe();
|
||||
|
||||
|
||||
struct box_coordinates
|
||||
{
|
||||
@ -216,14 +287,42 @@ private:
|
||||
}
|
||||
xy ld; // left down
|
||||
xy lu; // left upper
|
||||
xy ru; // right upper
|
||||
xy rd; // right lower
|
||||
xy ru; // right upper
|
||||
};
|
||||
|
||||
|
||||
// to store information about tool changes for a given layer
|
||||
struct WipeTowerInfo{
|
||||
struct ToolChange {
|
||||
unsigned int old_tool;
|
||||
unsigned int new_tool;
|
||||
float required_depth;
|
||||
float ramming_depth;
|
||||
float first_wipe_line;
|
||||
ToolChange(unsigned int old,unsigned int newtool,float depth=0.f,float ramming_depth=0.f,float fwl=0.f)
|
||||
: old_tool{old}, new_tool{newtool}, required_depth{depth}, ramming_depth{ramming_depth},first_wipe_line{fwl} {}
|
||||
};
|
||||
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;
|
||||
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();
|
||||
|
||||
|
||||
// Returns gcode for wipe tower brim
|
||||
// sideOnly -- set to false -- experimental, draw brim on sides of wipe tower
|
||||
// offset -- set to 0 -- experimental, offset to replace brim in front / rear of wipe tower
|
||||
ToolChangeResult toolchange_Brim(Purpose purpose, bool sideOnly = false, float y_offset = 0.f);
|
||||
ToolChangeResult toolchange_Brim(bool sideOnly = false, float y_offset = 0.f);
|
||||
|
||||
void toolchange_Unload(
|
||||
PrusaMultiMaterial::Writer &writer,
|
||||
@ -243,11 +342,12 @@ private:
|
||||
void toolchange_Wipe(
|
||||
PrusaMultiMaterial::Writer &writer,
|
||||
const box_coordinates &cleaning_box,
|
||||
bool skip_initial_y_move);
|
||||
|
||||
void toolchange_Perimeter();
|
||||
float wipe_volume);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
}; // namespace Slic3r
|
||||
|
||||
#endif /* WipeTowerPrusaMM_hpp_ */
|
||||
|
@ -183,6 +183,11 @@ bool Print::invalidate_state_by_config_options(const std::vector<t_config_option
|
||||
|| opt_key == "filament_type"
|
||||
|| opt_key == "filament_soluble"
|
||||
|| opt_key == "first_layer_temperature"
|
||||
|| opt_key == "filament_loading_speed"
|
||||
|| opt_key == "filament_unloading_speed"
|
||||
|| opt_key == "filament_toolchange_delay"
|
||||
|| opt_key == "filament_cooling_time"
|
||||
|| opt_key == "filament_ramming_parameters"
|
||||
|| opt_key == "gcode_flavor"
|
||||
|| opt_key == "single_extruder_multi_material"
|
||||
|| opt_key == "spiral_vase"
|
||||
@ -191,7 +196,12 @@ bool Print::invalidate_state_by_config_options(const std::vector<t_config_option
|
||||
|| opt_key == "wipe_tower_x"
|
||||
|| opt_key == "wipe_tower_y"
|
||||
|| opt_key == "wipe_tower_width"
|
||||
|| opt_key == "wipe_tower_per_color_wipe"
|
||||
|| opt_key == "wipe_tower_rotation_angle"
|
||||
|| opt_key == "wipe_tower_bridging"
|
||||
|| opt_key == "wiping_volumes_matrix"
|
||||
|| opt_key == "parking_pos_retraction"
|
||||
|| opt_key == "cooling_tube_retraction"
|
||||
|| opt_key == "cooling_tube_length"
|
||||
|| opt_key == "z_offset") {
|
||||
steps.emplace_back(psWipeTower);
|
||||
} else if (
|
||||
@ -571,6 +581,12 @@ std::string Print::validate() const
|
||||
return "The Spiral Vase option can only be used when printing single material objects.";
|
||||
}
|
||||
|
||||
if (this->config.single_extruder_multi_material) {
|
||||
for (size_t i=1; i<this->config.nozzle_diameter.values.size(); ++i)
|
||||
if (this->config.nozzle_diameter.values[i] != this->config.nozzle_diameter.values[i-1])
|
||||
return "All extruders must have the same diameter for single extruder multimaterial printer.";
|
||||
}
|
||||
|
||||
if (this->has_wipe_tower() && ! this->objects.empty()) {
|
||||
#if 0
|
||||
for (auto dmr : this->config.nozzle_diameter.values)
|
||||
@ -596,10 +612,21 @@ std::string Print::validate() const
|
||||
bool was_layer_height_profile_valid = object->layer_height_profile_valid;
|
||||
object->update_layer_height_profile();
|
||||
object->layer_height_profile_valid = was_layer_height_profile_valid;
|
||||
for (size_t i = 5; i < object->layer_height_profile.size(); i += 2)
|
||||
|
||||
if ( this->config.variable_layer_height ) {
|
||||
PrintObject* first_object = this->objects.front();
|
||||
int i = 0;
|
||||
while ( i < first_object->layer_height_profile.size() && i < object->layer_height_profile.size() ) {
|
||||
if (std::abs(first_object->layer_height_profile[i] - object->layer_height_profile[i]) > EPSILON )
|
||||
return "The Wipe tower is only supported if all objects have the same layer height profile";
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
/*for (size_t i = 5; i < object->layer_height_profile.size(); i += 2)
|
||||
if (object->layer_height_profile[i-1] > slicing_params.object_print_z_min + EPSILON &&
|
||||
std::abs(object->layer_height_profile[i] - object->config.layer_height) > EPSILON)
|
||||
return "The Wipe Tower is currently only supported with constant Z layer spacing. Layer editing is not allowed.";
|
||||
return "The Wipe Tower is currently only supported with constant Z layer spacing. Layer editing is not allowed.";*/
|
||||
}
|
||||
}
|
||||
|
||||
@ -614,6 +641,11 @@ std::string Print::validate() const
|
||||
nozzle_diameters.push_back(this->config.nozzle_diameter.get_at(extruder_id));
|
||||
double min_nozzle_diameter = *std::min_element(nozzle_diameters.begin(), nozzle_diameters.end());
|
||||
|
||||
unsigned int total_extruders_count = this->config.nozzle_diameter.size();
|
||||
for (const auto& extruder_idx : extruders)
|
||||
if ( extruder_idx >= total_extruders_count )
|
||||
return "One or more object were assigned an extruder that the printer does not have.";
|
||||
|
||||
for (PrintObject *object : this->objects) {
|
||||
if ((object->config.support_material_extruder == -1 || object->config.support_material_interface_extruder == -1) &&
|
||||
(object->config.raft_layers > 0 || object->config.support_material.value)) {
|
||||
@ -1026,22 +1058,33 @@ void Print::_make_wipe_tower()
|
||||
}
|
||||
}
|
||||
|
||||
// Get wiping matrix to get number of extruders and convert vector<double> to vector<float>:
|
||||
std::vector<float> wiping_volumes((this->config.wiping_volumes_matrix.values).begin(),(this->config.wiping_volumes_matrix.values).end());
|
||||
|
||||
// Initialize the wipe tower.
|
||||
WipeTowerPrusaMM wipe_tower(
|
||||
float(this->config.wipe_tower_x.value), float(this->config.wipe_tower_y.value),
|
||||
float(this->config.wipe_tower_width.value), float(this->config.wipe_tower_per_color_wipe.value),
|
||||
m_tool_ordering.first_extruder());
|
||||
float(this->config.wipe_tower_width.value),
|
||||
float(this->config.wipe_tower_rotation_angle.value), float(this->config.cooling_tube_retraction.value),
|
||||
float(this->config.cooling_tube_length.value), float(this->config.parking_pos_retraction.value),
|
||||
float(this->config.wipe_tower_bridging), wiping_volumes, m_tool_ordering.first_extruder());
|
||||
|
||||
//wipe_tower.set_retract();
|
||||
//wipe_tower.set_zhop();
|
||||
|
||||
// Set the extruder & material properties at the wipe tower object.
|
||||
for (size_t i = 0; i < 4; ++ i)
|
||||
for (size_t i = 0; i < (int)(sqrt(wiping_volumes.size())+EPSILON); ++ i)
|
||||
wipe_tower.set_extruder(
|
||||
i,
|
||||
WipeTowerPrusaMM::parse_material(this->config.filament_type.get_at(i).c_str()),
|
||||
this->config.temperature.get_at(i),
|
||||
this->config.first_layer_temperature.get_at(i));
|
||||
this->config.first_layer_temperature.get_at(i),
|
||||
this->config.filament_loading_speed.get_at(i),
|
||||
this->config.filament_unloading_speed.get_at(i),
|
||||
this->config.filament_toolchange_delay.get_at(i),
|
||||
this->config.filament_cooling_time.get_at(i),
|
||||
this->config.filament_ramming_parameters.get_at(i),
|
||||
this->config.nozzle_diameter.get_at(i));
|
||||
|
||||
// When printing the first layer's wipe tower, the first extruder is expected to be active and primed.
|
||||
// Therefore the number of wipe sections at the wipe tower will be (m_tool_ordering.front().extruders-1) at the 1st layer.
|
||||
@ -1049,12 +1092,37 @@ void Print::_make_wipe_tower()
|
||||
bool last_priming_wipe_full = m_tool_ordering.front().extruders.size() > m_tool_ordering.front().wipe_tower_partitions;
|
||||
|
||||
m_wipe_tower_priming = Slic3r::make_unique<WipeTower::ToolChangeResult>(
|
||||
wipe_tower.prime(this->skirt_first_layer_height(), m_tool_ordering.all_extruders(), ! last_priming_wipe_full, WipeTower::PURPOSE_EXTRUDE));
|
||||
wipe_tower.prime(this->skirt_first_layer_height(), m_tool_ordering.all_extruders(), ! last_priming_wipe_full));
|
||||
|
||||
|
||||
// Lets go through the wipe tower layers and determine pairs of extruder changes for each
|
||||
// to pass to wipe_tower (so that it can use it for planning the layout of the tower)
|
||||
{
|
||||
unsigned int current_extruder_id = m_tool_ordering.all_extruders().back();
|
||||
for (const auto &layer_tools : m_tool_ordering.layer_tools()) { // for all layers
|
||||
if (!layer_tools.has_wipe_tower) continue;
|
||||
bool first_layer = &layer_tools == &m_tool_ordering.front();
|
||||
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) {
|
||||
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());
|
||||
current_extruder_id = extruder_id;
|
||||
}
|
||||
}
|
||||
if (&layer_tools == &m_tool_ordering.back() || (&layer_tools + 1)->wipe_tower_partitions == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 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);
|
||||
|
||||
// Set current_extruder_id to the last extruder primed.
|
||||
unsigned int current_extruder_id = m_tool_ordering.all_extruders().back();
|
||||
/*unsigned int current_extruder_id = m_tool_ordering.all_extruders().back();
|
||||
|
||||
for (const ToolOrdering::LayerTools &layer_tools : m_tool_ordering.layer_tools()) {
|
||||
if (! layer_tools.has_wipe_tower)
|
||||
// This is a support only layer, or the wipe tower does not reach to this height.
|
||||
@ -1098,7 +1166,7 @@ void Print::_make_wipe_tower()
|
||||
m_wipe_tower_tool_changes.emplace_back(std::move(tool_changes));
|
||||
if (last_layer)
|
||||
break;
|
||||
}
|
||||
}*/
|
||||
|
||||
// Unload the current filament over the purge tower.
|
||||
coordf_t layer_height = this->objects.front()->config.layer_height.value;
|
||||
@ -1117,7 +1185,7 @@ void Print::_make_wipe_tower()
|
||||
wipe_tower.set_layer(float(m_tool_ordering.back().print_z), float(layer_height), 0, false, true);
|
||||
}
|
||||
m_wipe_tower_final_purge = Slic3r::make_unique<WipeTower::ToolChangeResult>(
|
||||
wipe_tower.tool_change((unsigned int)-1, false, WipeTower::PURPOSE_EXTRUDE));
|
||||
wipe_tower.tool_change((unsigned int)-1, false));
|
||||
}
|
||||
|
||||
std::string Print::output_filename()
|
||||
|
@ -166,6 +166,22 @@ PrintConfigDef::PrintConfigDef()
|
||||
def->cli = "cooling!";
|
||||
def->default_value = new ConfigOptionBools { true };
|
||||
|
||||
def = this->add("cooling_tube_retraction", coFloat);
|
||||
def->label = L("Cooling tube position");
|
||||
def->tooltip = L("Distance of the center-point of the cooling tube from the extruder tip ");
|
||||
def->sidetext = L("mm");
|
||||
def->cli = "cooling_tube_retraction=f";
|
||||
def->min = 0;
|
||||
def->default_value = new ConfigOptionFloat(91.5f);
|
||||
|
||||
def = this->add("cooling_tube_length", coFloat);
|
||||
def->label = L("Cooling tube length");
|
||||
def->tooltip = L("Length of the cooling tube to limit space for cooling moves inside it ");
|
||||
def->sidetext = L("mm");
|
||||
def->cli = "cooling_tube_length=f";
|
||||
def->min = 0;
|
||||
def->default_value = new ConfigOptionFloat(5.f);
|
||||
|
||||
def = this->add("default_acceleration", coFloat);
|
||||
def->label = L("Default");
|
||||
def->tooltip = L("This is the acceleration your printer will be reset to after "
|
||||
@ -439,6 +455,49 @@ PrintConfigDef::PrintConfigDef()
|
||||
def->min = 0;
|
||||
def->default_value = new ConfigOptionFloats { 0. };
|
||||
|
||||
def = this->add("filament_loading_speed", coFloats);
|
||||
def->label = L("Loading speed");
|
||||
def->tooltip = L("Speed used for loading the filament on the wipe tower. ");
|
||||
def->sidetext = L("mm/s");
|
||||
def->cli = "filament-loading-speed=f@";
|
||||
def->min = 0;
|
||||
def->default_value = new ConfigOptionFloats { 28. };
|
||||
|
||||
def = this->add("filament_unloading_speed", coFloats);
|
||||
def->label = L("Unloading speed");
|
||||
def->tooltip = L("Speed used for unloading the filament on the wipe tower (does not affect "
|
||||
" initial part of unloading just after ramming). ");
|
||||
def->sidetext = L("mm/s");
|
||||
def->cli = "filament-unloading-speed=f@";
|
||||
def->min = 0;
|
||||
def->default_value = new ConfigOptionFloats { 90. };
|
||||
|
||||
def = this->add("filament_toolchange_delay", coFloats);
|
||||
def->label = L("Delay after unloading");
|
||||
def->tooltip = L("Time to wait after the filament is unloaded. "
|
||||
"May help to get reliable toolchanges with flexible materials "
|
||||
"that may need more time to shrink to original dimensions. ");
|
||||
def->sidetext = L("s");
|
||||
def->cli = "filament-toolchange-delay=f@";
|
||||
def->min = 0;
|
||||
def->default_value = new ConfigOptionFloats { 0. };
|
||||
|
||||
def = this->add("filament_cooling_time", coFloats);
|
||||
def->label = L("Cooling time");
|
||||
def->tooltip = L("The filament is slowly moved back and forth after retraction into the cooling tube "
|
||||
"for this amount of time.");
|
||||
def->cli = "filament_cooling_time=i@";
|
||||
def->sidetext = L("s");
|
||||
def->min = 0;
|
||||
def->default_value = new ConfigOptionFloats { 14.f };
|
||||
|
||||
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 ");
|
||||
def->cli = "filament-ramming-parameters=s@";
|
||||
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_diameter", coFloats);
|
||||
def->label = L("Diameter");
|
||||
def->tooltip = L("Enter your filament diameter here. Good precision is required, so use a caliper "
|
||||
@ -977,6 +1036,15 @@ PrintConfigDef::PrintConfigDef()
|
||||
def->cli = "overhangs!";
|
||||
def->default_value = new ConfigOptionBool(true);
|
||||
|
||||
def = this->add("parking_pos_retraction", coFloat);
|
||||
def->label = L("Filament parking position");
|
||||
def->tooltip = L("Distance of the extruder tip from the position where the filament is parked "
|
||||
"when unloaded. This should match the value in printer firmware. ");
|
||||
def->sidetext = L("mm");
|
||||
def->cli = "parking_pos_retraction=f";
|
||||
def->min = 0;
|
||||
def->default_value = new ConfigOptionFloat(92.f);
|
||||
|
||||
def = this->add("perimeter_acceleration", coFloat);
|
||||
def->label = L("Perimeters");
|
||||
def->tooltip = L("This is the acceleration your printer will use for perimeters. "
|
||||
@ -1744,6 +1812,25 @@ PrintConfigDef::PrintConfigDef()
|
||||
def->cli = "wipe-tower!";
|
||||
def->default_value = new ConfigOptionBool(false);
|
||||
|
||||
def = this->add("wiping_volumes_extruders", coFloats);
|
||||
def->label = L("Purging volumes - load/unload volumes");
|
||||
def->tooltip = L("This vector saves required volumes to change from/to each tool used on the "
|
||||
"wipe tower. These values are used to simplify creation of the full purging "
|
||||
"volumes below. ");
|
||||
def->cli = "wiping-volumes-extruders=f@";
|
||||
def->default_value = new ConfigOptionFloats { 70.f, 70.f, 70.f, 70.f, 70.f, 70.f, 70.f, 70.f, 70.f, 70.f };
|
||||
|
||||
def = this->add("wiping_volumes_matrix", coFloats);
|
||||
def->label = L("Purging volumes - matrix");
|
||||
def->tooltip = L("This matrix describes volumes (in cubic milimetres) required to purge the"
|
||||
" new filament on the wipe tower for any given pair of tools. ");
|
||||
def->cli = "wiping-volumes-matrix=f@";
|
||||
def->default_value = new ConfigOptionFloats { 0.f, 140.f, 140.f, 140.f, 140.f,
|
||||
140.f, 0.f, 140.f, 140.f, 140.f,
|
||||
140.f, 140.f, 0.f, 140.f, 140.f,
|
||||
140.f, 140.f, 140.f, 0.f, 140.f,
|
||||
140.f, 140.f, 140.f, 140.f, 0.f };
|
||||
|
||||
def = this->add("wipe_tower_x", coFloat);
|
||||
def->label = L("Position X");
|
||||
def->tooltip = L("X coordinate of the left front corner of a wipe tower");
|
||||
@ -1765,14 +1852,19 @@ PrintConfigDef::PrintConfigDef()
|
||||
def->cli = "wipe-tower-width=f";
|
||||
def->default_value = new ConfigOptionFloat(60.);
|
||||
|
||||
def = this->add("wipe_tower_per_color_wipe", coFloat);
|
||||
def->label = L("Per color change depth");
|
||||
def->tooltip = L("Depth of a wipe color per color change. For N colors, there will be "
|
||||
"maximum (N-1) tool switches performed, therefore the total depth "
|
||||
"of the wipe tower will be (N-1) times this value.");
|
||||
def = this->add("wipe_tower_rotation_angle", coFloat);
|
||||
def->label = L("Wipe tower rotation angle");
|
||||
def->tooltip = L("Wipe tower rotation angle with respect to x-axis ");
|
||||
def->sidetext = L("degrees");
|
||||
def->cli = "wipe-tower-rotation-angle=f";
|
||||
def->default_value = new ConfigOptionFloat(0.);
|
||||
|
||||
def = this->add("wipe_tower_bridging", coFloat);
|
||||
def->label = L("Maximal bridging distance");
|
||||
def->tooltip = L("Maximal distance between supports on sparse infill sections. ");
|
||||
def->sidetext = L("mm");
|
||||
def->cli = "wipe-tower-per-color-wipe=f";
|
||||
def->default_value = new ConfigOptionFloat(15.);
|
||||
def->cli = "wipe-tower-bridging=f";
|
||||
def->default_value = new ConfigOptionFloat(10.);
|
||||
|
||||
def = this->add("xy_size_compensation", coFloat);
|
||||
def->label = L("XY Size Compensation");
|
||||
@ -1852,8 +1944,9 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va
|
||||
"standby_temperature", "scale", "rotate", "duplicate", "duplicate_grid",
|
||||
"start_perimeters_at_concave_points", "start_perimeters_at_non_overhang", "randomize_start",
|
||||
"seal_position", "vibration_limit", "bed_size", "octoprint_host",
|
||||
"print_center", "g0", "threads", "pressure_advance"
|
||||
"print_center", "g0", "threads", "pressure_advance", "wipe_tower_per_color_wipe"
|
||||
};
|
||||
|
||||
if (ignore.find(opt_key) != ignore.end()) {
|
||||
opt_key = "";
|
||||
return;
|
||||
|
@ -154,6 +154,13 @@ public:
|
||||
|
||||
// Validate the PrintConfig. Returns an empty string on success, otherwise an error message is returned.
|
||||
std::string validate();
|
||||
|
||||
// Verify whether the opt_key has not been obsoleted or renamed.
|
||||
// Both opt_key and value may be modified by handle_legacy().
|
||||
// If the opt_key is no more valid in this version of Slic3r, opt_key is cleared by handle_legacy().
|
||||
// handle_legacy() is called internally by set_deserialize().
|
||||
void handle_legacy(t_config_option_key &opt_key, std::string &value) const override
|
||||
{ PrintConfigDef::handle_legacy(opt_key, value); }
|
||||
};
|
||||
|
||||
template<typename CONFIG>
|
||||
@ -466,6 +473,11 @@ public:
|
||||
ConfigOptionBools filament_soluble;
|
||||
ConfigOptionFloats filament_cost;
|
||||
ConfigOptionFloats filament_max_volumetric_speed;
|
||||
ConfigOptionFloats filament_loading_speed;
|
||||
ConfigOptionFloats filament_unloading_speed;
|
||||
ConfigOptionFloats filament_toolchange_delay;
|
||||
ConfigOptionFloats filament_cooling_time;
|
||||
ConfigOptionStrings filament_ramming_parameters;
|
||||
ConfigOptionBool gcode_comments;
|
||||
ConfigOptionEnum<GCodeFlavor> gcode_flavor;
|
||||
ConfigOptionString layer_gcode;
|
||||
@ -491,6 +503,10 @@ public:
|
||||
ConfigOptionBool use_relative_e_distances;
|
||||
ConfigOptionBool use_volumetric_e;
|
||||
ConfigOptionBool variable_layer_height;
|
||||
ConfigOptionFloat cooling_tube_retraction;
|
||||
ConfigOptionFloat cooling_tube_length;
|
||||
ConfigOptionFloat parking_pos_retraction;
|
||||
|
||||
|
||||
std::string get_extrusion_axis() const
|
||||
{
|
||||
@ -515,6 +531,11 @@ protected:
|
||||
OPT_PTR(filament_soluble);
|
||||
OPT_PTR(filament_cost);
|
||||
OPT_PTR(filament_max_volumetric_speed);
|
||||
OPT_PTR(filament_loading_speed);
|
||||
OPT_PTR(filament_unloading_speed);
|
||||
OPT_PTR(filament_toolchange_delay);
|
||||
OPT_PTR(filament_cooling_time);
|
||||
OPT_PTR(filament_ramming_parameters);
|
||||
OPT_PTR(gcode_comments);
|
||||
OPT_PTR(gcode_flavor);
|
||||
OPT_PTR(layer_gcode);
|
||||
@ -540,6 +561,9 @@ protected:
|
||||
OPT_PTR(use_relative_e_distances);
|
||||
OPT_PTR(use_volumetric_e);
|
||||
OPT_PTR(variable_layer_height);
|
||||
OPT_PTR(cooling_tube_retraction);
|
||||
OPT_PTR(cooling_tube_length);
|
||||
OPT_PTR(parking_pos_retraction);
|
||||
}
|
||||
};
|
||||
|
||||
@ -610,6 +634,10 @@ public:
|
||||
ConfigOptionFloat wipe_tower_y;
|
||||
ConfigOptionFloat wipe_tower_width;
|
||||
ConfigOptionFloat wipe_tower_per_color_wipe;
|
||||
ConfigOptionFloat wipe_tower_rotation_angle;
|
||||
ConfigOptionFloat wipe_tower_bridging;
|
||||
ConfigOptionFloats wiping_volumes_matrix;
|
||||
ConfigOptionFloats wiping_volumes_extruders;
|
||||
ConfigOptionFloat z_offset;
|
||||
|
||||
protected:
|
||||
@ -675,6 +703,10 @@ protected:
|
||||
OPT_PTR(wipe_tower_y);
|
||||
OPT_PTR(wipe_tower_width);
|
||||
OPT_PTR(wipe_tower_per_color_wipe);
|
||||
OPT_PTR(wipe_tower_rotation_angle);
|
||||
OPT_PTR(wipe_tower_bridging);
|
||||
OPT_PTR(wiping_volumes_matrix);
|
||||
OPT_PTR(wiping_volumes_extruders);
|
||||
OPT_PTR(z_offset);
|
||||
}
|
||||
};
|
||||
@ -713,6 +745,7 @@ class FullPrintConfig :
|
||||
public:
|
||||
// Validate the FullPrintConfig. Returns an empty string on success, otherwise an error message is returned.
|
||||
std::string validate();
|
||||
|
||||
protected:
|
||||
// Protected constructor to be called to initialize ConfigCache::m_default.
|
||||
FullPrintConfig(int) : PrintObjectConfig(0), PrintRegionConfig(0), PrintConfig(0), HostConfig(0) {}
|
||||
|
@ -420,12 +420,17 @@ std::vector<int> GLVolumeCollection::load_object(
|
||||
|
||||
|
||||
int GLVolumeCollection::load_wipe_tower_preview(
|
||||
int obj_idx, float pos_x, float pos_y, float width, float depth, float height, bool use_VBOs)
|
||||
int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool use_VBOs)
|
||||
{
|
||||
float color[4] = { 1.0f, 1.0f, 0.0f, 0.5f };
|
||||
this->volumes.emplace_back(new GLVolume(color));
|
||||
GLVolume &v = *this->volumes.back();
|
||||
|
||||
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);
|
||||
|
||||
if (use_VBOs)
|
||||
v.indexed_vertex_array.load_mesh_full_shading(mesh);
|
||||
else
|
||||
@ -2594,8 +2599,10 @@ void _3DScene::_load_shells(const Print& print, GLVolumeCollection& volumes, boo
|
||||
coordf_t max_z = print.objects[0]->model_object()->get_model()->bounding_box().max.z;
|
||||
const PrintConfig& config = 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)
|
||||
volumes.load_wipe_tower_preview(1000, config.wipe_tower_x, config.wipe_tower_y, config.wipe_tower_width, config.wipe_tower_per_color_wipe * (extruders_count - 1), max_z, use_VBOs);
|
||||
if ((extruders_count > 1) && config.single_extruder_multi_material && config.wipe_tower && !config.complete_objects) {
|
||||
const float width_per_extruder = 15.f; // a simple workaround after wipe_tower_per_color_wipe got obsolete
|
||||
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, use_VBOs);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace Slic3r
|
||||
|
@ -271,7 +271,7 @@ public:
|
||||
const std::string &drag_by);
|
||||
|
||||
int load_wipe_tower_preview(
|
||||
int obj_idx, float pos_x, float pos_y, float width, float depth, float height, bool use_VBOs);
|
||||
int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool use_VBOs);
|
||||
|
||||
// Bounding box of this volume, in unscaled coordinates.
|
||||
BoundingBoxf3 bounding_box;
|
||||
@ -392,7 +392,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, bool use_VBOs);
|
||||
int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool use_VBOs);
|
||||
|
||||
// Render the volumes by OpenGL.
|
||||
void render_VBOs() const;
|
||||
|
@ -34,7 +34,7 @@ void BedShapeDialog::build_dialog(ConfigOptionPoints* default_pt)
|
||||
|
||||
void BedShapePanel::build_panel(ConfigOptionPoints* default_pt)
|
||||
{
|
||||
// on_change(nullptr);
|
||||
// on_change(nullptr);
|
||||
|
||||
auto box = new wxStaticBox(this, wxID_ANY, _(L("Shape")));
|
||||
auto sbsizer = new wxStaticBoxSizer(box, wxVERTICAL);
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "GUI.hpp"
|
||||
#include "WipeTowerDialog.hpp"
|
||||
|
||||
#include <assert.h>
|
||||
#include <cmath>
|
||||
@ -185,6 +186,7 @@ wxLocale* g_wxLocale;
|
||||
|
||||
std::shared_ptr<ConfigOptionsGroup> m_optgroup;
|
||||
double m_brim_width = 0.0;
|
||||
wxButton* g_wiping_dialog_button = nullptr;
|
||||
|
||||
static void init_label_colours()
|
||||
{
|
||||
@ -714,6 +716,33 @@ void add_frequently_changed_parameters(wxWindow* parent, wxBoxSizer* sizer, wxFl
|
||||
option = Option(def, "brim");
|
||||
m_optgroup->append_single_option_line(option);
|
||||
|
||||
|
||||
Line line = { _(L("")), "" };
|
||||
line.widget = [config](wxWindow* parent){
|
||||
g_wiping_dialog_button = new wxButton(parent, wxID_ANY, _(L("Purging volumes")) + "\u2026", wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
|
||||
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
sizer->Add(g_wiping_dialog_button);
|
||||
g_wiping_dialog_button->Bind(wxEVT_BUTTON, ([parent](wxCommandEvent& e)
|
||||
{
|
||||
auto &config = g_PresetBundle->project_config;
|
||||
std::vector<double> init_matrix = (config.option<ConfigOptionFloats>("wiping_volumes_matrix"))->values;
|
||||
std::vector<double> init_extruders = (config.option<ConfigOptionFloats>("wiping_volumes_extruders"))->values;
|
||||
|
||||
WipingDialog dlg(parent,std::vector<float>(init_matrix.begin(),init_matrix.end()),std::vector<float>(init_extruders.begin(),init_extruders.end()));
|
||||
|
||||
if (dlg.ShowModal() == wxID_OK) {
|
||||
std::vector<float> matrix = dlg.get_matrix();
|
||||
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());
|
||||
}
|
||||
}));
|
||||
return sizer;
|
||||
};
|
||||
m_optgroup->append_line(line);
|
||||
|
||||
|
||||
|
||||
sizer->Add(m_optgroup->sizer, 0, wxEXPAND | wxBOTTOM | wxBottom, 1);
|
||||
}
|
||||
|
||||
@ -722,6 +751,12 @@ ConfigOptionsGroup* get_optgroup()
|
||||
return m_optgroup.get();
|
||||
}
|
||||
|
||||
|
||||
wxButton* get_wiping_dialog_button()
|
||||
{
|
||||
return g_wiping_dialog_button;
|
||||
}
|
||||
|
||||
wxWindow* export_option_creator(wxWindow* parent)
|
||||
{
|
||||
wxPanel* panel = new wxPanel(parent, -1);
|
||||
@ -765,6 +800,9 @@ int get_export_option(wxFileDialog* dlg)
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
} }
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
|
@ -18,6 +18,7 @@ class wxArrayLong;
|
||||
class wxColour;
|
||||
class wxBoxSizer;
|
||||
class wxFlexGridSizer;
|
||||
class wxButton;
|
||||
class wxFileDialog;
|
||||
|
||||
namespace Slic3r {
|
||||
@ -133,6 +134,7 @@ wxString from_u8(const std::string &str);
|
||||
void add_frequently_changed_parameters(wxWindow* parent, wxBoxSizer* sizer, wxFlexGridSizer* preset_sizer);
|
||||
|
||||
ConfigOptionsGroup* get_optgroup();
|
||||
wxButton* get_wiping_dialog_button();
|
||||
|
||||
void add_export_option(wxFileDialog* dlg, const std::string& format);
|
||||
int get_export_option(wxFileDialog* dlg);
|
||||
|
@ -149,7 +149,7 @@ void OptionsGroup::append_line(const Line& line) {
|
||||
// If there's a widget, build it and add the result to the sizer.
|
||||
if (line.widget != nullptr) {
|
||||
auto wgt = line.widget(parent());
|
||||
grid_sizer->Add(wgt, 0, wxEXPAND | wxBOTTOM | wxTOP, wxOSX ? 0 : 5);
|
||||
grid_sizer->Add(wgt, 0, wxEXPAND | wxBOTTOM | wxTOP, wxOSX ? 0 : 1);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -199,8 +199,7 @@ const std::vector<std::string>& Preset::print_options()
|
||||
"perimeter_extrusion_width", "external_perimeter_extrusion_width", "infill_extrusion_width", "solid_infill_extrusion_width",
|
||||
"top_infill_extrusion_width", "support_material_extrusion_width", "infill_overlap", "bridge_flow_ratio", "clip_multipart_objects",
|
||||
"elefant_foot_compensation", "xy_size_compensation", "threads", "resolution", "wipe_tower", "wipe_tower_x", "wipe_tower_y",
|
||||
"wipe_tower_width", "wipe_tower_per_color_wipe",
|
||||
"compatible_printers", "compatible_printers_condition", "inherits"
|
||||
"wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_bridging", "compatible_printers", "compatible_printers_condition","inherits"
|
||||
};
|
||||
return s_opts;
|
||||
}
|
||||
@ -209,11 +208,11 @@ 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", "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_unloading_speed", "filament_toolchange_delay",
|
||||
"filament_cooling_time", "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"
|
||||
};
|
||||
return s_opts;
|
||||
}
|
||||
@ -226,8 +225,8 @@ const std::vector<std::string>& Preset::printer_options()
|
||||
"bed_shape", "z_offset", "gcode_flavor", "use_relative_e_distances", "serial_port", "serial_speed",
|
||||
"octoprint_host", "octoprint_apikey", "octoprint_cafile", "use_firmware_retraction", "use_volumetric_e", "variable_layer_height",
|
||||
"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", "max_print_height",
|
||||
"default_print_profile", "inherits",
|
||||
"between_objects_gcode", "printer_vendor", "printer_model", "printer_variant", "printer_notes", "cooling_tube_retraction",
|
||||
"cooling_tube_length", "parking_pos_retraction", "max_print_height", "default_print_profile", "inherits",
|
||||
};
|
||||
s_opts.insert(s_opts.end(), Preset::nozzle_options().begin(), Preset::nozzle_options().end());
|
||||
}
|
||||
|
@ -33,6 +33,11 @@
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
static std::vector<std::string> s_project_options {
|
||||
"wiping_volumes_extruders",
|
||||
"wiping_volumes_matrix"
|
||||
};
|
||||
|
||||
PresetBundle::PresetBundle() :
|
||||
prints(Preset::TYPE_PRINT, Preset::print_options()),
|
||||
filaments(Preset::TYPE_FILAMENT, Preset::filament_options()),
|
||||
@ -68,6 +73,8 @@ PresetBundle::PresetBundle() :
|
||||
this->filaments.load_bitmap_default("spool.png");
|
||||
this->printers .load_bitmap_default("printer_empty.png");
|
||||
this->load_compatible_bitmaps();
|
||||
|
||||
this->project_config.apply_only(FullPrintConfig::defaults(), s_project_options);
|
||||
}
|
||||
|
||||
PresetBundle::~PresetBundle()
|
||||
@ -293,6 +300,7 @@ DynamicPrintConfig PresetBundle::full_config() const
|
||||
out.apply(FullPrintConfig());
|
||||
out.apply(this->prints.get_edited_preset().config);
|
||||
out.apply(this->printers.get_edited_preset().config);
|
||||
out.apply(this->project_config);
|
||||
|
||||
auto *nozzle_diameter = dynamic_cast<const ConfigOptionFloats*>(out.option("nozzle_diameter"));
|
||||
size_t num_extruders = nozzle_diameter->values.size();
|
||||
@ -482,6 +490,9 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
|
||||
}
|
||||
}
|
||||
|
||||
// 4) Load the project config values (the per extruder wipe matrix etc).
|
||||
this->project_config.apply_only(config, s_project_options);
|
||||
|
||||
this->update_compatible_with_printer(false);
|
||||
}
|
||||
|
||||
@ -873,6 +884,34 @@ void PresetBundle::update_multi_material_filament_presets()
|
||||
// Append the rest of filament presets.
|
||||
// if (this->filament_presets.size() < num_extruders)
|
||||
this->filament_presets.resize(num_extruders, this->filament_presets.empty() ? this->filaments.first_visible().name : this->filament_presets.back());
|
||||
|
||||
|
||||
// Now verify if wiping_volumes_matrix has proper size (it is used to deduce number of extruders in wipe tower generator):
|
||||
std::vector<double> old_matrix = this->project_config.option<ConfigOptionFloats>("wiping_volumes_matrix")->values;
|
||||
size_t old_number_of_extruders = int(sqrt(old_matrix.size())+EPSILON);
|
||||
if (num_extruders != old_number_of_extruders) {
|
||||
// First verify if purging volumes presets for each extruder matches number of extruders
|
||||
std::vector<double>& extruders = this->project_config.option<ConfigOptionFloats>("wiping_volumes_extruders")->values;
|
||||
while (extruders.size() < 2*num_extruders) {
|
||||
extruders.push_back(extruders.size()>1 ? extruders[0] : 50.); // copy the values from the first extruder
|
||||
extruders.push_back(extruders.size()>1 ? extruders[1] : 50.);
|
||||
}
|
||||
while (extruders.size() > 2*num_extruders) {
|
||||
extruders.pop_back();
|
||||
extruders.pop_back();
|
||||
}
|
||||
|
||||
std::vector<double> new_matrix;
|
||||
for (unsigned int i=0;i<num_extruders;++i)
|
||||
for (unsigned int j=0;j<num_extruders;++j) {
|
||||
// append the value for this pair from the old matrix (if it's there):
|
||||
if (i<old_number_of_extruders && j<old_number_of_extruders)
|
||||
new_matrix.push_back(old_matrix[i*old_number_of_extruders + j]);
|
||||
else
|
||||
new_matrix.push_back( i==j ? 0. : extruders[2*i]+extruders[2*j+1]); // so it matches new extruder volumes
|
||||
}
|
||||
this->project_config.option<ConfigOptionFloats>("wiping_volumes_matrix")->values = new_matrix;
|
||||
}
|
||||
}
|
||||
|
||||
void PresetBundle::update_compatible_with_printer(bool select_other_if_incompatible)
|
||||
|
@ -44,6 +44,11 @@ public:
|
||||
// extruders.size() should be the same as printers.get_edited_preset().config.nozzle_diameter.size()
|
||||
std::vector<std::string> filament_presets;
|
||||
|
||||
// The project configuration values are kept separated from the print/filament/printer preset,
|
||||
// they are being serialized / deserialized from / to the .amf, .3mf, .config, .gcode,
|
||||
// and they are being used by slicing core.
|
||||
DynamicPrintConfig project_config;
|
||||
|
||||
// There will be an entry for each system profile loaded,
|
||||
// and the system profiles will point to the VendorProfile instances owned by PresetBundle::vendors.
|
||||
std::set<VendorProfile> vendors;
|
||||
|
284
xs/src/slic3r/GUI/RammingChart.cpp
Normal file
284
xs/src/slic3r/GUI/RammingChart.cpp
Normal file
@ -0,0 +1,284 @@
|
||||
#include <algorithm>
|
||||
#include <wx/dcbuffer.h>
|
||||
|
||||
#include "RammingChart.hpp"
|
||||
|
||||
|
||||
//! macro used to mark string used at localization,
|
||||
//! return same string
|
||||
#define L(s) s
|
||||
|
||||
|
||||
|
||||
wxDEFINE_EVENT(EVT_WIPE_TOWER_CHART_CHANGED, wxCommandEvent);
|
||||
|
||||
|
||||
void Chart::draw() {
|
||||
wxAutoBufferedPaintDC dc(this); // unbuffered DC caused flickering on win
|
||||
|
||||
dc.SetBrush(GetBackgroundColour());
|
||||
dc.SetPen(GetBackgroundColour());
|
||||
dc.DrawRectangle(GetClientRect()); // otherwise the background would end up black on windows
|
||||
|
||||
dc.SetPen(*wxBLACK_PEN);
|
||||
dc.SetBrush(*wxWHITE_BRUSH);
|
||||
dc.DrawRectangle(m_rect);
|
||||
|
||||
if (visible_area.m_width < 0.499) {
|
||||
dc.DrawText("NO RAMMING AT ALL",wxPoint(m_rect.GetLeft()+m_rect.GetWidth()/2-50,m_rect.GetBottom()-m_rect.GetHeight()/2));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (!m_line_to_draw.empty()) {
|
||||
for (unsigned int i=0;i<m_line_to_draw.size()-2;++i) {
|
||||
int color = 510*((m_rect.GetBottom()-(m_line_to_draw)[i])/double(m_rect.GetHeight()));
|
||||
dc.SetPen( wxPen( wxColor(std::min(255,color),255-std::max(color-255,0),0), 1 ) );
|
||||
dc.DrawLine(m_rect.GetLeft()+1+i,(m_line_to_draw)[i],m_rect.GetLeft()+1+i,m_rect.GetBottom());
|
||||
}
|
||||
dc.SetPen( wxPen( wxColor(0,0,0), 1 ) );
|
||||
for (unsigned int i=0;i<m_line_to_draw.size()-2;++i) {
|
||||
if (splines)
|
||||
dc.DrawLine(m_rect.GetLeft()+i,(m_line_to_draw)[i],m_rect.GetLeft()+i+1,(m_line_to_draw)[i+1]);
|
||||
else {
|
||||
dc.DrawLine(m_rect.GetLeft()+i,(m_line_to_draw)[i],m_rect.GetLeft()+i+1,(m_line_to_draw)[i]);
|
||||
dc.DrawLine(m_rect.GetLeft()+i+1,(m_line_to_draw)[i],m_rect.GetLeft()+i+1,(m_line_to_draw)[i+1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// draw draggable buttons
|
||||
dc.SetBrush(*wxBLUE_BRUSH);
|
||||
dc.SetPen( wxPen( wxColor(0,0,0), 1 ) );
|
||||
for (auto& button : m_buttons)
|
||||
//dc.DrawRectangle(math_to_screen(button.get_pos())-wxPoint(side/2.,side/2.), wxSize(side,side));
|
||||
dc.DrawCircle(math_to_screen(button.get_pos()),side/2.);
|
||||
//dc.DrawRectangle(math_to_screen(button.get_pos()-wxPoint2DDouble(0.125,0))-wxPoint(0,5),wxSize(50,10));
|
||||
|
||||
// draw x-axis:
|
||||
float last_mark = -10000;
|
||||
for (float math_x=int(visible_area.m_x*10)/10 ; math_x < (visible_area.m_x+visible_area.m_width) ; math_x+=0.1) {
|
||||
int x = math_to_screen(wxPoint2DDouble(math_x,visible_area.m_y)).x;
|
||||
int y = m_rect.GetBottom();
|
||||
if (x-last_mark < 50) continue;
|
||||
dc.DrawLine(x,y+3,x,y-3);
|
||||
dc.DrawText(wxString().Format(wxT("%.1f"), math_x),wxPoint(x-10,y+7));
|
||||
last_mark = x;
|
||||
}
|
||||
|
||||
// draw y-axis:
|
||||
last_mark=10000;
|
||||
for (int math_y=visible_area.m_y ; math_y < (visible_area.m_y+visible_area.m_height) ; math_y+=1) {
|
||||
int y = math_to_screen(wxPoint2DDouble(visible_area.m_x,math_y)).y;
|
||||
int x = m_rect.GetLeft();
|
||||
if (last_mark-y < 50) continue;
|
||||
dc.DrawLine(x-3,y,x+3,y);
|
||||
dc.DrawText(wxString()<<math_y,wxPoint(x-25,y-2/*7*/));
|
||||
last_mark = y;
|
||||
}
|
||||
|
||||
// axis labels:
|
||||
wxString label = L("Time (s)");
|
||||
int text_width = 0;
|
||||
int text_height = 0;
|
||||
dc.GetTextExtent(label,&text_width,&text_height);
|
||||
dc.DrawText(label,wxPoint(0.5*(m_rect.GetRight()+m_rect.GetLeft())-text_width/2.f, m_rect.GetBottom()+25));
|
||||
label = L("Volumetric speed (mm\u00B3/s)");
|
||||
dc.GetTextExtent(label,&text_width,&text_height);
|
||||
dc.DrawRotatedText(label,wxPoint(0,0.5*(m_rect.GetBottom()+m_rect.GetTop())+text_width/2.f),90);
|
||||
}
|
||||
|
||||
void Chart::mouse_right_button_clicked(wxMouseEvent& event) {
|
||||
if (!manual_points_manipulation)
|
||||
return;
|
||||
wxPoint point = event.GetPosition();
|
||||
int button_index = which_button_is_clicked(point);
|
||||
if (button_index != -1 && m_buttons.size()>2) {
|
||||
m_buttons.erase(m_buttons.begin()+button_index);
|
||||
recalculate_line();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Chart::mouse_clicked(wxMouseEvent& event) {
|
||||
wxPoint point = event.GetPosition();
|
||||
int button_index = which_button_is_clicked(point);
|
||||
if ( button_index != -1) {
|
||||
m_dragged = &m_buttons[button_index];
|
||||
m_previous_mouse = point;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Chart::mouse_moved(wxMouseEvent& event) {
|
||||
if (!event.Dragging() || !m_dragged) return;
|
||||
wxPoint pos = event.GetPosition();
|
||||
wxRect rect = m_rect;
|
||||
rect.Deflate(side/2.);
|
||||
if (!(rect.Contains(pos))) { // the mouse left chart area
|
||||
mouse_left_window(event);
|
||||
return;
|
||||
}
|
||||
int delta_x = pos.x - m_previous_mouse.x;
|
||||
int delta_y = pos.y - m_previous_mouse.y;
|
||||
m_dragged->move(fixed_x?0:double(delta_x)/m_rect.GetWidth() * visible_area.m_width,-double(delta_y)/m_rect.GetHeight() * visible_area.m_height);
|
||||
m_previous_mouse = pos;
|
||||
recalculate_line();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Chart::mouse_double_clicked(wxMouseEvent& event) {
|
||||
if (!manual_points_manipulation)
|
||||
return;
|
||||
wxPoint point = event.GetPosition();
|
||||
if (!m_rect.Contains(point)) // the click is outside the chart
|
||||
return;
|
||||
m_buttons.push_back(screen_to_math(point));
|
||||
std::sort(m_buttons.begin(),m_buttons.end());
|
||||
recalculate_line();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void Chart::recalculate_line() {
|
||||
std::vector<wxPoint> points;
|
||||
for (auto& but : m_buttons) {
|
||||
points.push_back(wxPoint(math_to_screen(but.get_pos())));
|
||||
if (points.size()>1 && points.back().x==points[points.size()-2].x) points.pop_back();
|
||||
if (points.size()>1 && points.back().x > m_rect.GetRight()) {
|
||||
points.pop_back();
|
||||
break;
|
||||
}
|
||||
}
|
||||
std::sort(points.begin(),points.end(),[](wxPoint& a,wxPoint& b) { return a.x < b.x; });
|
||||
|
||||
m_line_to_draw.clear();
|
||||
m_total_volume = 0.f;
|
||||
|
||||
|
||||
// Cubic spline interpolation: see https://en.wikiversity.org/wiki/Cubic_Spline_Interpolation#Methods
|
||||
const bool boundary_first_derivative = true; // true - first derivative is 0 at the leftmost and rightmost point
|
||||
// false - second ---- || -------
|
||||
const int N = points.size()-1; // last point can be accessed as N, we have N+1 total points
|
||||
std::vector<float> diag(N+1);
|
||||
std::vector<float> mu(N+1);
|
||||
std::vector<float> lambda(N+1);
|
||||
std::vector<float> h(N+1);
|
||||
std::vector<float> rhs(N+1);
|
||||
|
||||
// let's fill in inner equations
|
||||
for (int i=1;i<=N;++i) h[i] = points[i].x-points[i-1].x;
|
||||
std::fill(diag.begin(),diag.end(),2.f);
|
||||
for (int i=1;i<=N-1;++i) {
|
||||
mu[i] = h[i]/(h[i]+h[i+1]);
|
||||
lambda[i] = 1.f - mu[i];
|
||||
rhs[i] = 6 * ( float(points[i+1].y-points[i].y )/(h[i+1]*(points[i+1].x-points[i-1].x)) -
|
||||
float(points[i].y -points[i-1].y)/(h[i] *(points[i+1].x-points[i-1].x)) );
|
||||
}
|
||||
|
||||
// now fill in the first and last equations, according to boundary conditions:
|
||||
if (boundary_first_derivative) {
|
||||
const float endpoints_derivative = 0;
|
||||
lambda[0] = 1;
|
||||
mu[N] = 1;
|
||||
rhs[0] = (6.f/h[1]) * (float(points[0].y-points[1].y)/(points[0].x-points[1].x) - endpoints_derivative);
|
||||
rhs[N] = (6.f/h[N]) * (endpoints_derivative - float(points[N-1].y-points[N].y)/(points[N-1].x-points[N].x));
|
||||
}
|
||||
else {
|
||||
lambda[0] = 0;
|
||||
mu[N] = 0;
|
||||
rhs[0] = 0;
|
||||
rhs[N] = 0;
|
||||
}
|
||||
|
||||
// the trilinear system is ready to be solved:
|
||||
for (int i=1;i<=N;++i) {
|
||||
float multiple = mu[i]/diag[i-1]; // let's subtract proper multiple of above equation
|
||||
diag[i]-= multiple * lambda[i-1];
|
||||
rhs[i] -= multiple * rhs[i-1];
|
||||
}
|
||||
// now the back substitution (vector mu contains invalid values from now on):
|
||||
rhs[N] = rhs[N]/diag[N];
|
||||
for (int i=N-1;i>=0;--i)
|
||||
rhs[i] = (rhs[i]-lambda[i]*rhs[i+1])/diag[i];
|
||||
|
||||
|
||||
|
||||
|
||||
unsigned int i=1;
|
||||
float y=0.f;
|
||||
for (int x=m_rect.GetLeft(); x<=m_rect.GetRight() ; ++x) {
|
||||
if (splines) {
|
||||
if (i<points.size()-1 && points[i].x < x ) {
|
||||
++i;
|
||||
}
|
||||
if (points[0].x > x)
|
||||
y = points[0].y;
|
||||
else
|
||||
if (points[N].x < x)
|
||||
y = points[N].y;
|
||||
else
|
||||
y = (rhs[i-1]*pow(points[i].x-x,3)+rhs[i]*pow(x-points[i-1].x,3)) / (6*h[i]) +
|
||||
(points[i-1].y-rhs[i-1]*h[i]*h[i]/6.f) * (points[i].x-x)/h[i] +
|
||||
(points[i].y -rhs[i] *h[i]*h[i]/6.f) * (x-points[i-1].x)/h[i];
|
||||
m_line_to_draw.push_back(y);
|
||||
}
|
||||
else {
|
||||
float x_math = screen_to_math(wxPoint(x,0)).m_x;
|
||||
if (i+2<=points.size() && m_buttons[i+1].get_pos().m_x-0.125 < x_math)
|
||||
++i;
|
||||
m_line_to_draw.push_back(math_to_screen(wxPoint2DDouble(x_math,m_buttons[i].get_pos().m_y)).y);
|
||||
}
|
||||
|
||||
|
||||
m_line_to_draw.back() = std::max(m_line_to_draw.back(), m_rect.GetTop()-1);
|
||||
m_line_to_draw.back() = std::min(m_line_to_draw.back(), m_rect.GetBottom()-1);
|
||||
m_total_volume += (m_rect.GetBottom() - m_line_to_draw.back()) * (visible_area.m_width / m_rect.GetWidth()) * (visible_area.m_height / m_rect.GetHeight());
|
||||
}
|
||||
|
||||
wxPostEvent(this->GetParent(), wxCommandEvent(EVT_WIPE_TOWER_CHART_CHANGED));
|
||||
Refresh();
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::vector<float> Chart::get_ramming_speed(float sampling) const {
|
||||
std::vector<float> speeds_out;
|
||||
|
||||
const int number_of_samples = std::round( visible_area.m_width / sampling);
|
||||
if (number_of_samples>0) {
|
||||
const int dx = (m_line_to_draw.size()-1) / number_of_samples;
|
||||
for (int j=0;j<number_of_samples;++j) {
|
||||
float left = screen_to_math(wxPoint(0,m_line_to_draw[j*dx])).m_y;
|
||||
float right = screen_to_math(wxPoint(0,m_line_to_draw[(j+1)*dx])).m_y;
|
||||
speeds_out.push_back((left+right)/2.f);
|
||||
}
|
||||
}
|
||||
return speeds_out;
|
||||
}
|
||||
|
||||
|
||||
std::vector<std::pair<float,float>> Chart::get_buttons() const {
|
||||
std::vector<std::pair<float, float>> buttons_out;
|
||||
for (const auto& button : m_buttons)
|
||||
buttons_out.push_back(std::make_pair(button.get_pos().m_x,button.get_pos().m_y));
|
||||
return buttons_out;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
BEGIN_EVENT_TABLE(Chart, wxWindow)
|
||||
EVT_MOTION(Chart::mouse_moved)
|
||||
EVT_LEFT_DOWN(Chart::mouse_clicked)
|
||||
EVT_LEFT_UP(Chart::mouse_released)
|
||||
EVT_LEFT_DCLICK(Chart::mouse_double_clicked)
|
||||
EVT_RIGHT_DOWN(Chart::mouse_right_button_clicked)
|
||||
EVT_LEAVE_WINDOW(Chart::mouse_left_window)
|
||||
EVT_PAINT(Chart::paint_event)
|
||||
END_EVENT_TABLE()
|
115
xs/src/slic3r/GUI/RammingChart.hpp
Normal file
115
xs/src/slic3r/GUI/RammingChart.hpp
Normal file
@ -0,0 +1,115 @@
|
||||
#ifndef RAMMING_CHART_H_
|
||||
#define RAMMING_CHART_H_
|
||||
|
||||
#include <vector>
|
||||
#include <wx/wxprec.h>
|
||||
#ifndef WX_PRECOMP
|
||||
#include <wx/wx.h>
|
||||
#endif
|
||||
|
||||
wxDECLARE_EVENT(EVT_WIPE_TOWER_CHART_CHANGED, wxCommandEvent);
|
||||
|
||||
|
||||
class Chart : public wxWindow {
|
||||
|
||||
public:
|
||||
Chart(wxWindow* parent, wxRect rect,const std::vector<std::pair<float,float>>& initial_buttons,int ramming_speed_size, float sampling) :
|
||||
wxWindow(parent,wxID_ANY,rect.GetTopLeft(),rect.GetSize())
|
||||
{
|
||||
SetBackgroundStyle(wxBG_STYLE_PAINT);
|
||||
m_rect = wxRect(wxPoint(50,0),rect.GetSize()-wxSize(50,50));
|
||||
visible_area = wxRect2DDouble(0.0, 0.0, sampling*ramming_speed_size, 20.);
|
||||
m_buttons.clear();
|
||||
if (initial_buttons.size()>0)
|
||||
for (const auto& pair : initial_buttons)
|
||||
m_buttons.push_back(wxPoint2DDouble(pair.first,pair.second));
|
||||
recalculate_line();
|
||||
}
|
||||
void set_xy_range(float x,float y) {
|
||||
x = int(x/0.5) * 0.5;
|
||||
if (x>=0) visible_area.SetRight(x);
|
||||
if (y>=0) visible_area.SetBottom(y);
|
||||
recalculate_line();
|
||||
}
|
||||
float get_volume() const { return m_total_volume; }
|
||||
float get_time() const { return visible_area.m_width; }
|
||||
|
||||
std::vector<float> get_ramming_speed(float sampling) const; //returns sampled ramming speed
|
||||
std::vector<std::pair<float,float>> get_buttons() const; // returns buttons position
|
||||
|
||||
void draw();
|
||||
|
||||
void mouse_clicked(wxMouseEvent& event);
|
||||
void mouse_right_button_clicked(wxMouseEvent& event);
|
||||
void mouse_moved(wxMouseEvent& event);
|
||||
void mouse_double_clicked(wxMouseEvent& event);
|
||||
void mouse_left_window(wxMouseEvent&) { m_dragged = nullptr; }
|
||||
void mouse_released(wxMouseEvent&) { m_dragged = nullptr; }
|
||||
void paint_event(wxPaintEvent&) { draw(); }
|
||||
DECLARE_EVENT_TABLE()
|
||||
|
||||
|
||||
|
||||
private:
|
||||
static const bool fixed_x = true;
|
||||
static const bool splines = true;
|
||||
static const bool manual_points_manipulation = false;
|
||||
static const int side = 10; // side of draggable button
|
||||
|
||||
class ButtonToDrag {
|
||||
public:
|
||||
bool operator<(const ButtonToDrag& a) const { return m_pos.m_x < a.m_pos.m_x; }
|
||||
ButtonToDrag(wxPoint2DDouble pos) : m_pos{pos} {};
|
||||
wxPoint2DDouble get_pos() const { return m_pos; }
|
||||
void move(double x,double y) { m_pos.m_x+=x; m_pos.m_y+=y; }
|
||||
private:
|
||||
wxPoint2DDouble m_pos; // position in math coordinates
|
||||
};
|
||||
|
||||
|
||||
|
||||
wxPoint math_to_screen(const wxPoint2DDouble& math) const {
|
||||
wxPoint screen;
|
||||
screen.x = (math.m_x-visible_area.m_x) * (m_rect.GetWidth() / visible_area.m_width );
|
||||
screen.y = (math.m_y-visible_area.m_y) * (m_rect.GetHeight() / visible_area.m_height );
|
||||
screen.y *= -1;
|
||||
screen += m_rect.GetLeftBottom();
|
||||
return screen;
|
||||
}
|
||||
wxPoint2DDouble screen_to_math(const wxPoint& screen) const {
|
||||
wxPoint2DDouble math = screen;
|
||||
math -= m_rect.GetLeftBottom();
|
||||
math.m_y *= -1;
|
||||
math.m_x *= visible_area.m_width / m_rect.GetWidth(); // scales to [0;1]x[0,1]
|
||||
math.m_y *= visible_area.m_height / m_rect.GetHeight();
|
||||
return (math+visible_area.GetLeftTop());
|
||||
}
|
||||
|
||||
int which_button_is_clicked(const wxPoint& point) const {
|
||||
if (!m_rect.Contains(point))
|
||||
return -1;
|
||||
for (unsigned int i=0;i<m_buttons.size();++i) {
|
||||
wxRect rect(math_to_screen(m_buttons[i].get_pos())-wxPoint(side/2.,side/2.),wxSize(side,side)); // bounding rectangle of this button
|
||||
if ( rect.Contains(point) )
|
||||
return i;
|
||||
}
|
||||
return (-1);
|
||||
}
|
||||
|
||||
|
||||
void recalculate_line();
|
||||
void recalculate_volume();
|
||||
|
||||
|
||||
wxRect m_rect; // rectangle on screen the chart is mapped into (screen coordinates)
|
||||
wxPoint m_previous_mouse;
|
||||
std::vector<ButtonToDrag> m_buttons;
|
||||
std::vector<int> m_line_to_draw;
|
||||
wxRect2DDouble visible_area;
|
||||
ButtonToDrag* m_dragged = nullptr;
|
||||
float m_total_volume = 0.f;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // RAMMING_CHART_H_
|
@ -3,9 +3,11 @@
|
||||
#include "PresetBundle.hpp"
|
||||
#include "PresetHints.hpp"
|
||||
#include "../../libslic3r/Utils.hpp"
|
||||
|
||||
#include "slic3r/Utils/Http.hpp"
|
||||
#include "slic3r/Utils/OctoPrint.hpp"
|
||||
#include "BonjourDialog.hpp"
|
||||
#include "WipeTowerDialog.hpp"
|
||||
|
||||
#include <wx/app.h>
|
||||
#include <wx/button.h>
|
||||
@ -582,10 +584,27 @@ void Tab::on_value_change(std::string opt_key, boost::any value)
|
||||
get_optgroup()->set_value("brim", val);
|
||||
}
|
||||
|
||||
if (opt_key == "wipe_tower" || opt_key == "single_extruder_multi_material" || opt_key == "extruders_count" )
|
||||
update_wiping_button_visibility();
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
// Show/hide the 'purging volumes' button
|
||||
void Tab::update_wiping_button_visibility() {
|
||||
bool wipe_tower_enabled = dynamic_cast<ConfigOptionBool*>( (m_preset_bundle->prints.get_edited_preset().config ).option("wipe_tower"))->value;
|
||||
bool multiple_extruders = dynamic_cast<ConfigOptionFloats*>((m_preset_bundle->printers.get_edited_preset().config).option("nozzle_diameter"))->values.size() > 1;
|
||||
bool single_extruder_mm = dynamic_cast<ConfigOptionBool*>( (m_preset_bundle->printers.get_edited_preset().config).option("single_extruder_multi_material"))->value;
|
||||
|
||||
if (wipe_tower_enabled && multiple_extruders && single_extruder_mm)
|
||||
get_wiping_dialog_button()->Show();
|
||||
else get_wiping_dialog_button()->Hide();
|
||||
|
||||
(get_wiping_dialog_button()->GetParent())->Layout();
|
||||
}
|
||||
|
||||
|
||||
// Call a callback to update the selection of presets on the platter:
|
||||
// To update the content of the selection boxes,
|
||||
// to update the filament colors of the selection boxes,
|
||||
@ -621,6 +640,8 @@ void Tab::update_frequently_changed_parameters()
|
||||
|
||||
bool val = m_config->opt_float("brim_width") > 0.0 ? true : false;
|
||||
get_optgroup()->set_value("brim", val);
|
||||
|
||||
update_wiping_button_visibility();
|
||||
}
|
||||
|
||||
void Tab::reload_compatible_printers_widget()
|
||||
@ -770,7 +791,8 @@ void TabPrint::build()
|
||||
optgroup->append_single_option_line("wipe_tower_x");
|
||||
optgroup->append_single_option_line("wipe_tower_y");
|
||||
optgroup->append_single_option_line("wipe_tower_width");
|
||||
optgroup->append_single_option_line("wipe_tower_per_color_wipe");
|
||||
optgroup->append_single_option_line("wipe_tower_rotation_angle");
|
||||
optgroup->append_single_option_line("wipe_tower_bridging");
|
||||
|
||||
optgroup = page->new_optgroup(_(L("Advanced")));
|
||||
optgroup->append_single_option_line("interface_shells");
|
||||
@ -1015,53 +1037,40 @@ void TabPrint::update()
|
||||
}
|
||||
|
||||
bool have_perimeters = m_config->opt_int("perimeters") > 0;
|
||||
std::vector<std::string> vec_enable = { "extra_perimeters", "ensure_vertical_shell_thickness", "thin_walls", "overhangs",
|
||||
"seam_position", "external_perimeters_first", "external_perimeter_extrusion_width",
|
||||
"perimeter_speed", "small_perimeter_speed", "external_perimeter_speed" };
|
||||
for (auto el : vec_enable)
|
||||
for (auto el : {"extra_perimeters", "ensure_vertical_shell_thickness", "thin_walls", "overhangs",
|
||||
"seam_position", "external_perimeters_first", "external_perimeter_extrusion_width",
|
||||
"perimeter_speed", "small_perimeter_speed", "external_perimeter_speed" })
|
||||
get_field(el)->toggle(have_perimeters);
|
||||
|
||||
bool have_infill = m_config->option<ConfigOptionPercent>("fill_density")->value > 0;
|
||||
vec_enable.resize(0);
|
||||
vec_enable = { "fill_pattern", "infill_every_layers", "infill_only_where_needed",
|
||||
"solid_infill_every_layers", "solid_infill_below_area", "infill_extruder" };
|
||||
// infill_extruder uses the same logic as in Print::extruders()
|
||||
for (auto el : vec_enable)
|
||||
for (auto el : {"fill_pattern", "infill_every_layers", "infill_only_where_needed",
|
||||
"solid_infill_every_layers", "solid_infill_below_area", "infill_extruder" })
|
||||
get_field(el)->toggle(have_infill);
|
||||
|
||||
bool have_solid_infill = m_config->opt_int("top_solid_layers") > 0 || m_config->opt_int("bottom_solid_layers") > 0;
|
||||
vec_enable.resize(0);
|
||||
vec_enable = { "external_fill_pattern", "infill_first", "solid_infill_extruder",
|
||||
"solid_infill_extrusion_width", "solid_infill_speed" };
|
||||
// solid_infill_extruder uses the same logic as in Print::extruders()
|
||||
for (auto el : vec_enable)
|
||||
for (auto el : {"external_fill_pattern", "infill_first", "solid_infill_extruder",
|
||||
"solid_infill_extrusion_width", "solid_infill_speed" })
|
||||
get_field(el)->toggle(have_solid_infill);
|
||||
|
||||
vec_enable.resize(0);
|
||||
vec_enable = { "fill_angle", "bridge_angle", "infill_extrusion_width",
|
||||
"infill_speed", "bridge_speed" };
|
||||
for (auto el : vec_enable)
|
||||
for (auto el : {"fill_angle", "bridge_angle", "infill_extrusion_width",
|
||||
"infill_speed", "bridge_speed" })
|
||||
get_field(el)->toggle(have_infill || have_solid_infill);
|
||||
|
||||
get_field("gap_fill_speed")->toggle(have_perimeters && have_infill);
|
||||
|
||||
bool have_top_solid_infill = m_config->opt_int("top_solid_layers") > 0;
|
||||
vec_enable.resize(0);
|
||||
vec_enable = { "top_infill_extrusion_width", "top_solid_infill_speed" };
|
||||
for (auto el : vec_enable)
|
||||
for (auto el : { "top_infill_extrusion_width", "top_solid_infill_speed" })
|
||||
get_field(el)->toggle(have_top_solid_infill);
|
||||
|
||||
bool have_default_acceleration = m_config->opt_float("default_acceleration") > 0;
|
||||
vec_enable.resize(0);
|
||||
vec_enable = { "perimeter_acceleration", "infill_acceleration",
|
||||
"bridge_acceleration", "first_layer_acceleration" };
|
||||
for (auto el : vec_enable)
|
||||
for (auto el : {"perimeter_acceleration", "infill_acceleration",
|
||||
"bridge_acceleration", "first_layer_acceleration" })
|
||||
get_field(el)->toggle(have_default_acceleration);
|
||||
|
||||
bool have_skirt = m_config->opt_int("skirts") > 0 || m_config->opt_float("min_skirt_length") > 0;
|
||||
vec_enable.resize(0);
|
||||
vec_enable = { "skirt_distance", "skirt_height" };
|
||||
for (auto el : vec_enable)
|
||||
for (auto el : { "skirt_distance", "skirt_height" })
|
||||
get_field(el)->toggle(have_skirt);
|
||||
|
||||
bool have_brim = m_config->opt_float("brim_width") > 0;
|
||||
@ -1072,18 +1081,14 @@ void TabPrint::update()
|
||||
bool have_support_material = m_config->opt_bool("support_material") || have_raft;
|
||||
bool have_support_interface = m_config->opt_int("support_material_interface_layers") > 0;
|
||||
bool have_support_soluble = have_support_material && m_config->opt_float("support_material_contact_distance") == 0;
|
||||
vec_enable.resize(0);
|
||||
vec_enable = { "support_material_threshold", "support_material_pattern", "support_material_with_sheath",
|
||||
for (auto el : {"support_material_threshold", "support_material_pattern", "support_material_with_sheath",
|
||||
"support_material_spacing", "support_material_angle", "support_material_interface_layers",
|
||||
"dont_support_bridges", "support_material_extrusion_width", "support_material_contact_distance",
|
||||
"support_material_xy_spacing" };
|
||||
for (auto el : vec_enable)
|
||||
"support_material_xy_spacing" })
|
||||
get_field(el)->toggle(have_support_material);
|
||||
|
||||
vec_enable.resize(0);
|
||||
vec_enable = { "support_material_interface_spacing", "support_material_interface_extruder",
|
||||
"support_material_interface_speed", "support_material_interface_contact_loops" };
|
||||
for (auto el : vec_enable)
|
||||
for (auto el : {"support_material_interface_spacing", "support_material_interface_extruder",
|
||||
"support_material_interface_speed", "support_material_interface_contact_loops" })
|
||||
get_field(el)->toggle(have_support_material && have_support_interface);
|
||||
get_field("support_material_synchronize_layers")->toggle(have_support_soluble);
|
||||
|
||||
@ -1092,18 +1097,14 @@ void TabPrint::update()
|
||||
get_field("support_material_speed")->toggle(have_support_material || have_brim || have_skirt);
|
||||
|
||||
bool have_sequential_printing = m_config->opt_bool("complete_objects");
|
||||
vec_enable.resize(0);
|
||||
vec_enable = { "extruder_clearance_radius", "extruder_clearance_height" };
|
||||
for (auto el : vec_enable)
|
||||
for (auto el : { "extruder_clearance_radius", "extruder_clearance_height" })
|
||||
get_field(el)->toggle(have_sequential_printing);
|
||||
|
||||
bool have_ooze_prevention = m_config->opt_bool("ooze_prevention");
|
||||
get_field("standby_temperature_delta")->toggle(have_ooze_prevention);
|
||||
|
||||
bool have_wipe_tower = m_config->opt_bool("wipe_tower");
|
||||
vec_enable.resize(0);
|
||||
vec_enable = { "wipe_tower_x", "wipe_tower_y", "wipe_tower_width", "wipe_tower_per_color_wipe" };
|
||||
for (auto el : vec_enable)
|
||||
for (auto el : { "wipe_tower_x", "wipe_tower_y", "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_bridging"})
|
||||
get_field(el)->toggle(have_wipe_tower);
|
||||
|
||||
m_recommended_thin_wall_thickness_description_line->SetText(
|
||||
@ -1183,7 +1184,29 @@ void TabFilament::build()
|
||||
};
|
||||
optgroup->append_line(line);
|
||||
|
||||
page = add_options_page(_(L("Custom G-code")), "cog.png");
|
||||
optgroup = page->new_optgroup(_(L("Toolchange behaviour")));
|
||||
optgroup->append_single_option_line("filament_loading_speed");
|
||||
optgroup->append_single_option_line("filament_unloading_speed");
|
||||
optgroup->append_single_option_line("filament_toolchange_delay");
|
||||
optgroup->append_single_option_line("filament_cooling_time");
|
||||
line = { _(L("Ramming")), "" };
|
||||
line.widget = [this](wxWindow* parent){
|
||||
auto ramming_dialog_btn = new wxButton(parent, wxID_ANY, _(L("Ramming settings"))+"\u2026", wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
|
||||
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
sizer->Add(ramming_dialog_btn);
|
||||
|
||||
ramming_dialog_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent& e)
|
||||
{
|
||||
RammingDialog dlg(this,(m_config->option<ConfigOptionStrings>("filament_ramming_parameters"))->get_at(0));
|
||||
if (dlg.ShowModal() == wxID_OK)
|
||||
(m_config->option<ConfigOptionStrings>("filament_ramming_parameters"))->get_at(0) = dlg.get_parameters();
|
||||
}));
|
||||
return sizer;
|
||||
};
|
||||
optgroup->append_line(line);
|
||||
|
||||
|
||||
page = add_options_page(_(L("Custom G-code")), "cog.png");
|
||||
optgroup = page->new_optgroup(_(L("Start G-code")), 0);
|
||||
Option option = optgroup->get_option("start_filament_gcode");
|
||||
option.opt.full_width = true;
|
||||
@ -1240,13 +1263,10 @@ void TabFilament::update()
|
||||
bool cooling = m_config->opt_bool("cooling", 0);
|
||||
bool fan_always_on = cooling || m_config->opt_bool("fan_always_on", 0);
|
||||
|
||||
std::vector<std::string> vec_enable = { "max_fan_speed", "fan_below_layer_time", "slowdown_below_layer_time", "min_print_speed" };
|
||||
for (auto el : vec_enable)
|
||||
for (auto el : { "max_fan_speed", "fan_below_layer_time", "slowdown_below_layer_time", "min_print_speed" })
|
||||
get_field(el)->toggle(cooling);
|
||||
|
||||
vec_enable.resize(0);
|
||||
vec_enable = { "min_fan_speed", "disable_fan_first_layers" };
|
||||
for (auto el : vec_enable)
|
||||
for (auto el : { "min_fan_speed", "disable_fan_first_layers" })
|
||||
get_field(el)->toggle(fan_always_on);
|
||||
}
|
||||
|
||||
@ -1325,9 +1345,11 @@ void TabPrinter::build()
|
||||
optgroup->m_on_change = [this, optgroup](t_config_option_key opt_key, boost::any value){
|
||||
size_t extruders_count = boost::any_cast<int>(optgroup->get_value("extruders_count"));
|
||||
wxTheApp->CallAfter([this, opt_key, value, extruders_count](){
|
||||
if (opt_key.compare("extruders_count")==0) {
|
||||
if (opt_key.compare("extruders_count")==0 || opt_key.compare("single_extruder_multi_material")==0) {
|
||||
extruders_count_changed(extruders_count);
|
||||
update_dirty();
|
||||
if (opt_key.compare("single_extruder_multi_material")==0) // the single_extruder_multimaterial was added to force pages
|
||||
on_value_change(opt_key, value); // rebuild - let's make sure the on_value_change is not skipped
|
||||
}
|
||||
else {
|
||||
update_dirty();
|
||||
@ -1336,6 +1358,7 @@ void TabPrinter::build()
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
if (!m_no_controller)
|
||||
{
|
||||
optgroup = page->new_optgroup(_(L("USB/Serial connection")));
|
||||
@ -1606,6 +1629,25 @@ void TabPrinter::build_extruder_pages(){
|
||||
for (auto page_extruder : m_extruder_pages)
|
||||
m_pages.push_back(page_extruder);
|
||||
m_pages.push_back(page_note);
|
||||
|
||||
{
|
||||
// if we have a single extruder MM setup, add a page with configuration options:
|
||||
for (int i=0;i<m_pages.size();++i) // first make sure it's not there already
|
||||
if (m_pages[i]->title().find(_(L("Single extruder MM setup"))) != std::string::npos) {
|
||||
m_pages.erase(m_pages.begin()+i);
|
||||
break;
|
||||
}
|
||||
if ( m_extruder_pages.size()>1 && m_config->opt_bool("single_extruder_multi_material")) {
|
||||
// create a page, but pretend it's an extruder page, so we can add it to m_pages ourselves
|
||||
auto page = add_options_page(_(L("Single extruder MM setup")), "printer_empty.png",true);
|
||||
auto optgroup = page->new_optgroup(_(L("Single extruder multimaterial parameters")));
|
||||
optgroup->append_single_option_line("cooling_tube_retraction");
|
||||
optgroup->append_single_option_line("cooling_tube_length");
|
||||
optgroup->append_single_option_line("parking_pos_retraction");
|
||||
m_pages.insert(m_pages.begin()+1,page);
|
||||
}
|
||||
}
|
||||
|
||||
rebuild_page_tree();
|
||||
}
|
||||
|
||||
|
@ -194,6 +194,7 @@ public:
|
||||
protected:
|
||||
void on_presets_changed();
|
||||
void update_frequently_changed_parameters();
|
||||
void update_wiping_button_visibility();
|
||||
};
|
||||
|
||||
//Slic3r::GUI::Tab::Print;
|
||||
|
343
xs/src/slic3r/GUI/WipeTowerDialog.cpp
Normal file
343
xs/src/slic3r/GUI/WipeTowerDialog.cpp
Normal file
@ -0,0 +1,343 @@
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include "WipeTowerDialog.hpp"
|
||||
|
||||
#include <wx/sizer.h>
|
||||
|
||||
//! macro used to mark string used at localization,
|
||||
//! return same string
|
||||
#define L(s) s
|
||||
|
||||
|
||||
|
||||
RammingDialog::RammingDialog(wxWindow* parent,const std::string& parameters)
|
||||
: wxDialog(parent, wxID_ANY, _(L("Ramming customization")), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE/* | wxRESIZE_BORDER*/)
|
||||
{
|
||||
m_panel_ramming = new RammingPanel(this,parameters);
|
||||
|
||||
// Not found another way of getting the background colours of RammingDialog, RammingPanel and Chart correct than setting
|
||||
// them all explicitely. Reading the parent colour yielded colour that didn't really match it, no wxSYS_COLOUR_... matched
|
||||
// colour used for the dialog. Same issue (and "solution") here : https://forums.wxwidgets.org/viewtopic.php?f=1&t=39608
|
||||
// Whoever can fix this, feel free to do so.
|
||||
this-> SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_FRAMEBK));
|
||||
m_panel_ramming->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_FRAMEBK));
|
||||
m_panel_ramming->Show(true);
|
||||
this->Show();
|
||||
|
||||
auto main_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
main_sizer->Add(m_panel_ramming, 1, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, 5);
|
||||
main_sizer->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxALIGN_CENTER_HORIZONTAL | wxTOP | wxBOTTOM, 10);
|
||||
SetSizer(main_sizer);
|
||||
main_sizer->SetSizeHints(this);
|
||||
|
||||
this->Bind(wxEVT_CLOSE_WINDOW, [this](wxCloseEvent& e) { EndModal(wxCANCEL); });
|
||||
|
||||
this->Bind(wxEVT_BUTTON,[this](wxCommandEvent&) {
|
||||
m_output_data = m_panel_ramming->get_parameters();
|
||||
EndModal(wxID_OK);
|
||||
},wxID_OK);
|
||||
this->Show();
|
||||
wxMessageDialog(this,_(L("Ramming denotes the rapid extrusion just before a tool change in a single-extruder MM printer. Its purpose is to "
|
||||
"properly shape the end of the unloaded filament so it does not prevent insertion of the new filament and can itself "
|
||||
"be reinserted later. This phase is important and different materials can require different extrusion speeds to get "
|
||||
"the good shape. For this reason, the extrusion rates during ramming are adjustable.\n\nThis is an expert-level "
|
||||
"setting, incorrect adjustment will likely lead to jams, extruder wheel grinding into filament etc.")),_(L("Warning")),wxOK|wxICON_EXCLAMATION).ShowModal();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
RammingPanel::RammingPanel(wxWindow* parent, const std::string& parameters)
|
||||
: wxPanel(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize/*,wxPoint(50,50), wxSize(800,350),wxBORDER_RAISED*/)
|
||||
{
|
||||
auto sizer_chart = new wxBoxSizer(wxVERTICAL);
|
||||
auto sizer_param = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
std::stringstream stream{ parameters };
|
||||
stream >> m_ramming_line_width_multiplicator >> m_ramming_step_multiplicator;
|
||||
int ramming_speed_size = 0;
|
||||
float dummy = 0.f;
|
||||
while (stream >> dummy)
|
||||
++ramming_speed_size;
|
||||
stream.clear();
|
||||
stream.get();
|
||||
|
||||
std::vector<std::pair<float, float>> buttons;
|
||||
float x = 0.f;
|
||||
float y = 0.f;
|
||||
while (stream >> x >> y)
|
||||
buttons.push_back(std::make_pair(x, y));
|
||||
|
||||
m_chart = new Chart(this, wxRect(10, 10, 480, 360), buttons, ramming_speed_size, 0.25f);
|
||||
m_chart->SetBackgroundColour(parent->GetBackgroundColour()); // see comment in RammingDialog constructor
|
||||
sizer_chart->Add(m_chart, 0, wxALL, 5);
|
||||
|
||||
m_widget_time = new wxSpinCtrlDouble(this,wxID_ANY,wxEmptyString,wxDefaultPosition,wxSize(75, -1),wxSP_ARROW_KEYS,0.,5.0,3.,0.5);
|
||||
m_widget_volume = new wxSpinCtrl(this,wxID_ANY,wxEmptyString,wxDefaultPosition,wxSize(75, -1),wxSP_ARROW_KEYS,0,10000,0);
|
||||
m_widget_ramming_line_width_multiplicator = new wxSpinCtrl(this,wxID_ANY,wxEmptyString,wxDefaultPosition,wxSize(75, -1),wxSP_ARROW_KEYS,10,200,100);
|
||||
m_widget_ramming_step_multiplicator = new wxSpinCtrl(this,wxID_ANY,wxEmptyString,wxDefaultPosition,wxSize(75, -1),wxSP_ARROW_KEYS,10,200,100);
|
||||
|
||||
auto gsizer_param = new wxFlexGridSizer(2, 5, 15);
|
||||
gsizer_param->Add(new wxStaticText(this, wxID_ANY, wxString(_(L("Total ramming time (s):")))), 0, wxALIGN_CENTER_VERTICAL);
|
||||
gsizer_param->Add(m_widget_time);
|
||||
gsizer_param->Add(new wxStaticText(this, wxID_ANY, wxString(_(L("Total rammed volume (mm"))+"\u00B3):")), 0, wxALIGN_CENTER_VERTICAL);
|
||||
gsizer_param->Add(m_widget_volume);
|
||||
gsizer_param->AddSpacer(20);
|
||||
gsizer_param->AddSpacer(20);
|
||||
gsizer_param->Add(new wxStaticText(this, wxID_ANY, wxString(_(L("Ramming line width (%):")))), 0, wxALIGN_CENTER_VERTICAL);
|
||||
gsizer_param->Add(m_widget_ramming_line_width_multiplicator);
|
||||
gsizer_param->Add(new wxStaticText(this, wxID_ANY, wxString(_(L("Ramming line spacing (%):")))), 0, wxALIGN_CENTER_VERTICAL);
|
||||
gsizer_param->Add(m_widget_ramming_step_multiplicator);
|
||||
|
||||
sizer_param->Add(gsizer_param, 0, wxTOP, 100);
|
||||
|
||||
m_widget_time->SetValue(m_chart->get_time());
|
||||
m_widget_time->SetDigits(2);
|
||||
m_widget_volume->SetValue(m_chart->get_volume());
|
||||
m_widget_volume->Disable();
|
||||
m_widget_ramming_line_width_multiplicator->SetValue(m_ramming_line_width_multiplicator);
|
||||
m_widget_ramming_step_multiplicator->SetValue(m_ramming_step_multiplicator);
|
||||
|
||||
m_widget_ramming_step_multiplicator->Bind(wxEVT_TEXT,[this](wxCommandEvent&) { line_parameters_changed(); });
|
||||
m_widget_ramming_line_width_multiplicator->Bind(wxEVT_TEXT,[this](wxCommandEvent&) { line_parameters_changed(); });
|
||||
|
||||
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
sizer->Add(sizer_chart, 0, wxALL, 5);
|
||||
sizer->Add(sizer_param, 0, wxALL, 10);
|
||||
|
||||
sizer->SetSizeHints(this);
|
||||
SetSizer(sizer);
|
||||
|
||||
m_widget_time->Bind(wxEVT_TEXT,[this](wxCommandEvent&) {m_chart->set_xy_range(m_widget_time->GetValue(),-1);});
|
||||
m_widget_time->Bind(wxEVT_CHAR,[](wxKeyEvent&){}); // do nothing - prevents the user to change the value
|
||||
m_widget_volume->Bind(wxEVT_CHAR,[](wxKeyEvent&){}); // do nothing - prevents the user to change the value
|
||||
Bind(EVT_WIPE_TOWER_CHART_CHANGED,[this](wxCommandEvent&) {m_widget_volume->SetValue(m_chart->get_volume()); m_widget_time->SetValue(m_chart->get_time());} );
|
||||
Refresh(this);
|
||||
}
|
||||
|
||||
void RammingPanel::line_parameters_changed() {
|
||||
m_ramming_line_width_multiplicator = m_widget_ramming_line_width_multiplicator->GetValue();
|
||||
m_ramming_step_multiplicator = m_widget_ramming_step_multiplicator->GetValue();
|
||||
}
|
||||
|
||||
std::string RammingPanel::get_parameters()
|
||||
{
|
||||
std::vector<float> speeds = m_chart->get_ramming_speed(0.25f);
|
||||
std::vector<std::pair<float,float>> buttons = m_chart->get_buttons();
|
||||
std::stringstream stream;
|
||||
stream << m_ramming_line_width_multiplicator << " " << m_ramming_step_multiplicator;
|
||||
for (const float& speed_value : speeds)
|
||||
stream << " " << speed_value;
|
||||
stream << "|";
|
||||
for (const auto& button : buttons)
|
||||
stream << " " << button.first << " " << button.second;
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
|
||||
#define ITEM_WIDTH 60
|
||||
// Parent dialog for purging volume adjustments - it fathers WipingPanel widget (that contains all controls) and a button to toggle simple/advanced mode:
|
||||
WipingDialog::WipingDialog(wxWindow* parent,const std::vector<float>& matrix, const std::vector<float>& extruders)
|
||||
: wxDialog(parent, wxID_ANY, _(L("Wipe tower - Purging volume adjustment")), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE/* | wxRESIZE_BORDER*/)
|
||||
{
|
||||
auto widget_button = new wxButton(this,wxID_ANY,"-",wxPoint(0,0),wxDefaultSize);
|
||||
m_panel_wiping = new WipingPanel(this,matrix,extruders, widget_button);
|
||||
|
||||
auto main_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
// set min sizer width according to extruders count
|
||||
const auto sizer_width = (int)((sqrt(matrix.size()) + 2.8)*ITEM_WIDTH);
|
||||
main_sizer->SetMinSize(wxSize(sizer_width, -1));
|
||||
|
||||
main_sizer->Add(m_panel_wiping, 0, wxEXPAND | wxALL, 5);
|
||||
main_sizer->Add(widget_button, 0, wxALIGN_CENTER_HORIZONTAL | wxCENTER | wxBOTTOM, 5);
|
||||
main_sizer->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxALIGN_CENTER_HORIZONTAL | wxBOTTOM, 10);
|
||||
SetSizer(main_sizer);
|
||||
main_sizer->SetSizeHints(this);
|
||||
|
||||
this->Bind(wxEVT_CLOSE_WINDOW, [this](wxCloseEvent& e) { EndModal(wxCANCEL); });
|
||||
|
||||
this->Bind(wxEVT_BUTTON,[this](wxCommandEvent&) { // if OK button is clicked..
|
||||
m_output_matrix = m_panel_wiping->read_matrix_values(); // ..query wiping panel and save returned values
|
||||
m_output_extruders = m_panel_wiping->read_extruders_values(); // so they can be recovered later by calling get_...()
|
||||
EndModal(wxID_OK);
|
||||
},wxID_OK);
|
||||
|
||||
this->Show();
|
||||
}
|
||||
|
||||
// This function allows to "play" with sizers parameters (like align or border)
|
||||
void WipingPanel::format_sizer(wxSizer* sizer, wxPanel* page, wxGridSizer* grid_sizer, const wxString& info, const wxString& table_title, int table_lshift/*=0*/)
|
||||
{
|
||||
sizer->Add(new wxStaticText(page, wxID_ANY, info,wxDefaultPosition,wxSize(0,50)), 0, wxEXPAND | wxLEFT, 15);
|
||||
auto table_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
sizer->Add(table_sizer, 0, wxALIGN_CENTER | wxCENTER, table_lshift);
|
||||
table_sizer->Add(new wxStaticText(page, wxID_ANY, table_title), 0, wxALIGN_CENTER | wxTOP, 50);
|
||||
table_sizer->Add(grid_sizer, 0, wxALIGN_CENTER | wxTOP, 10);
|
||||
}
|
||||
|
||||
// This panel contains all control widgets for both simple and advanced mode (these reside in separate sizers)
|
||||
WipingPanel::WipingPanel(wxWindow* parent, const std::vector<float>& matrix, const std::vector<float>& extruders, wxButton* widget_button)
|
||||
: wxPanel(parent,wxID_ANY, wxDefaultPosition, wxDefaultSize/*,wxBORDER_RAISED*/)
|
||||
{
|
||||
m_widget_button = widget_button; // pointer to the button in parent dialog
|
||||
m_widget_button->Bind(wxEVT_BUTTON,[this](wxCommandEvent&){ toggle_advanced(true); });
|
||||
|
||||
m_number_of_extruders = (int)(sqrt(matrix.size())+0.001);
|
||||
|
||||
// Create two switched panels with their own sizers
|
||||
m_sizer_simple = new wxBoxSizer(wxVERTICAL);
|
||||
m_sizer_advanced = new wxBoxSizer(wxVERTICAL);
|
||||
m_page_simple = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
|
||||
m_page_advanced = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
|
||||
m_page_simple->SetSizer(m_sizer_simple);
|
||||
m_page_advanced->SetSizer(m_sizer_advanced);
|
||||
|
||||
auto gridsizer_simple = new wxGridSizer(3, 5, 10);
|
||||
m_gridsizer_advanced = new wxGridSizer(m_number_of_extruders+1, 5, 1);
|
||||
|
||||
// First create controls for advanced mode and assign them to m_page_advanced:
|
||||
for (unsigned int i = 0; i < m_number_of_extruders; ++i) {
|
||||
edit_boxes.push_back(std::vector<wxTextCtrl*>(0));
|
||||
|
||||
for (unsigned int j = 0; j < m_number_of_extruders; ++j) {
|
||||
edit_boxes.back().push_back(new wxTextCtrl(m_page_advanced, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(ITEM_WIDTH, -1)));
|
||||
if (i == j)
|
||||
edit_boxes[i][j]->Disable();
|
||||
else
|
||||
edit_boxes[i][j]->SetValue(wxString("") << int(matrix[m_number_of_extruders*j + i]));
|
||||
}
|
||||
}
|
||||
m_gridsizer_advanced->Add(new wxStaticText(m_page_advanced, wxID_ANY, wxString("")));
|
||||
for (unsigned int i = 0; i < m_number_of_extruders; ++i)
|
||||
m_gridsizer_advanced->Add(new wxStaticText(m_page_advanced, wxID_ANY, wxString("") << i + 1), 0, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL);
|
||||
for (unsigned int i = 0; i < m_number_of_extruders; ++i) {
|
||||
m_gridsizer_advanced->Add(new wxStaticText(m_page_advanced, wxID_ANY, wxString("") << i + 1), 0, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL);
|
||||
for (unsigned int j = 0; j < m_number_of_extruders; ++j)
|
||||
m_gridsizer_advanced->Add(edit_boxes[j][i], 0);
|
||||
}
|
||||
|
||||
// collect and format sizer
|
||||
format_sizer(m_sizer_advanced, m_page_advanced, m_gridsizer_advanced,
|
||||
_(L("Here you can adjust required purging volume (mm\u00B3) for any given pair of tools.")),
|
||||
_(L("Extruder changed to")));
|
||||
|
||||
// Hide preview page before new page creating
|
||||
// It allows to do that from a beginning of the main panel
|
||||
m_page_advanced->Hide();
|
||||
|
||||
// Now the same for simple mode:
|
||||
gridsizer_simple->Add(new wxStaticText(m_page_simple, wxID_ANY, wxString("")), 0, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL);
|
||||
gridsizer_simple->Add(new wxStaticText(m_page_simple, wxID_ANY, wxString(_(L("unloaded")))), 0, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL);
|
||||
gridsizer_simple->Add(new wxStaticText(m_page_simple,wxID_ANY,wxString(_(L("loaded")))), 0, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL);
|
||||
|
||||
for (unsigned int i=0;i<m_number_of_extruders;++i) {
|
||||
m_old.push_back(new wxSpinCtrl(m_page_simple,wxID_ANY,wxEmptyString,wxDefaultPosition, wxSize(80, -1),wxSP_ARROW_KEYS|wxALIGN_RIGHT,0,300,extruders[2*i]));
|
||||
m_new.push_back(new wxSpinCtrl(m_page_simple,wxID_ANY,wxEmptyString,wxDefaultPosition, wxSize(80, -1),wxSP_ARROW_KEYS|wxALIGN_RIGHT,0,300,extruders[2*i+1]));
|
||||
gridsizer_simple->Add(new wxStaticText(m_page_simple, wxID_ANY, wxString(_(L("Tool #"))) << i + 1 << ": "), 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
|
||||
gridsizer_simple->Add(m_old.back(),0);
|
||||
gridsizer_simple->Add(m_new.back(),0);
|
||||
}
|
||||
|
||||
// collect and format sizer
|
||||
format_sizer(m_sizer_simple, m_page_simple, gridsizer_simple,
|
||||
_(L("Total purging volume is calculated by summing two values below, depending on which tools are loaded/unloaded.")),
|
||||
_(L("Volume to purge (mm\u00B3) when the filament is being")), 50);
|
||||
|
||||
m_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
m_sizer->Add(m_page_simple, 0, wxEXPAND | wxALL, 25);
|
||||
m_sizer->Add(m_page_advanced, 0, wxEXPAND | wxALL, 25);
|
||||
|
||||
m_sizer->SetSizeHints(this);
|
||||
SetSizer(m_sizer);
|
||||
|
||||
toggle_advanced(); // to show/hide what is appropriate
|
||||
|
||||
m_page_advanced->Bind(wxEVT_PAINT,[this](wxPaintEvent&) {
|
||||
wxPaintDC dc(m_page_advanced);
|
||||
int y_pos = 0.5 * (edit_boxes[0][0]->GetPosition().y + edit_boxes[0][edit_boxes.size()-1]->GetPosition().y + edit_boxes[0][edit_boxes.size()-1]->GetSize().y);
|
||||
wxString label = _(L("From"));
|
||||
int text_width = 0;
|
||||
int text_height = 0;
|
||||
dc.GetTextExtent(label,&text_width,&text_height);
|
||||
int xpos = m_gridsizer_advanced->GetPosition().x;
|
||||
dc.DrawRotatedText(label,xpos-text_height,y_pos + text_width/2.f,90);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Reads values from the (advanced) wiping matrix:
|
||||
std::vector<float> WipingPanel::read_matrix_values() {
|
||||
if (!m_advanced)
|
||||
fill_in_matrix();
|
||||
std::vector<float> output;
|
||||
for (unsigned int i=0;i<m_number_of_extruders;++i) {
|
||||
for (unsigned int j=0;j<m_number_of_extruders;++j) {
|
||||
double val = 0.;
|
||||
edit_boxes[j][i]->GetValue().ToDouble(&val);
|
||||
output.push_back((float)val);
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
// Reads values from simple mode to save them for next time:
|
||||
std::vector<float> WipingPanel::read_extruders_values() {
|
||||
std::vector<float> output;
|
||||
for (unsigned int i=0;i<m_number_of_extruders;++i) {
|
||||
output.push_back(m_old[i]->GetValue());
|
||||
output.push_back(m_new[i]->GetValue());
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
// This updates the "advanced" matrix based on values from "simple" mode
|
||||
void WipingPanel::fill_in_matrix() {
|
||||
for (unsigned i=0;i<m_number_of_extruders;++i) {
|
||||
for (unsigned j=0;j<m_number_of_extruders;++j) {
|
||||
if (i==j) continue;
|
||||
edit_boxes[j][i]->SetValue(wxString("")<< (m_old[i]->GetValue() + m_new[j]->GetValue()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Function to check if simple and advanced settings are matching
|
||||
bool WipingPanel::advanced_matches_simple() {
|
||||
for (unsigned i=0;i<m_number_of_extruders;++i) {
|
||||
for (unsigned j=0;j<m_number_of_extruders;++j) {
|
||||
if (i==j) continue;
|
||||
if (edit_boxes[j][i]->GetValue() != (wxString("")<< (m_old[i]->GetValue() + m_new[j]->GetValue())))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Switches the dialog from simple to advanced mode and vice versa
|
||||
void WipingPanel::toggle_advanced(bool user_action) {
|
||||
if (m_advanced && !advanced_matches_simple() && user_action) {
|
||||
if (wxMessageDialog(this,wxString(_(L("Switching to simple settings will discard changes done in the advanced mode!\n\nDo you want to proceed?"))),
|
||||
wxString(_(L("Warning"))),wxYES_NO|wxICON_EXCLAMATION).ShowModal() != wxID_YES)
|
||||
return;
|
||||
}
|
||||
if (user_action)
|
||||
m_advanced = !m_advanced; // user demands a change -> toggle
|
||||
else
|
||||
m_advanced = !advanced_matches_simple(); // if called from constructor, show what is appropriate
|
||||
|
||||
(m_advanced ? m_page_advanced : m_page_simple)->Show();
|
||||
(!m_advanced ? m_page_advanced : m_page_simple)->Hide();
|
||||
|
||||
m_widget_button->SetLabel(m_advanced ? _(L("Show simplified settings")) : _(L("Show advanced settings")));
|
||||
if (m_advanced)
|
||||
if (user_action) fill_in_matrix(); // otherwise keep values loaded from config
|
||||
|
||||
m_sizer->Layout();
|
||||
Refresh();
|
||||
}
|
90
xs/src/slic3r/GUI/WipeTowerDialog.hpp
Normal file
90
xs/src/slic3r/GUI/WipeTowerDialog.hpp
Normal file
@ -0,0 +1,90 @@
|
||||
#ifndef _WIPE_TOWER_DIALOG_H_
|
||||
#define _WIPE_TOWER_DIALOG_H_
|
||||
|
||||
#include <wx/spinctrl.h>
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/textctrl.h>
|
||||
#include <wx/checkbox.h>
|
||||
#include <wx/msgdlg.h>
|
||||
|
||||
#include "RammingChart.hpp"
|
||||
|
||||
|
||||
class RammingPanel : public wxPanel {
|
||||
public:
|
||||
RammingPanel(wxWindow* parent);
|
||||
RammingPanel(wxWindow* parent,const std::string& data);
|
||||
std::string get_parameters();
|
||||
|
||||
private:
|
||||
Chart* m_chart = nullptr;
|
||||
wxSpinCtrl* m_widget_volume = nullptr;
|
||||
wxSpinCtrl* m_widget_ramming_line_width_multiplicator = nullptr;
|
||||
wxSpinCtrl* m_widget_ramming_step_multiplicator = nullptr;
|
||||
wxSpinCtrlDouble* m_widget_time = nullptr;
|
||||
int m_ramming_step_multiplicator;
|
||||
int m_ramming_line_width_multiplicator;
|
||||
|
||||
void line_parameters_changed();
|
||||
};
|
||||
|
||||
|
||||
class RammingDialog : public wxDialog {
|
||||
public:
|
||||
RammingDialog(wxWindow* parent,const std::string& parameters);
|
||||
std::string get_parameters() { return m_output_data; }
|
||||
private:
|
||||
RammingPanel* m_panel_ramming = nullptr;
|
||||
std::string m_output_data;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class WipingPanel : public wxPanel {
|
||||
public:
|
||||
WipingPanel(wxWindow* parent, const std::vector<float>& matrix, const std::vector<float>& extruders, wxButton* widget_button);
|
||||
std::vector<float> read_matrix_values();
|
||||
std::vector<float> read_extruders_values();
|
||||
void toggle_advanced(bool user_action = false);
|
||||
void format_sizer(wxSizer* sizer, wxPanel* page, wxGridSizer* grid_sizer, const wxString& info, const wxString& table_title, int table_lshift=0);
|
||||
|
||||
private:
|
||||
void fill_in_matrix();
|
||||
bool advanced_matches_simple();
|
||||
|
||||
std::vector<wxSpinCtrl*> m_old;
|
||||
std::vector<wxSpinCtrl*> m_new;
|
||||
std::vector<std::vector<wxTextCtrl*>> edit_boxes;
|
||||
unsigned int m_number_of_extruders = 0;
|
||||
bool m_advanced = false;
|
||||
wxPanel* m_page_simple = nullptr;
|
||||
wxPanel* m_page_advanced = nullptr;
|
||||
wxBoxSizer* m_sizer = nullptr;
|
||||
wxBoxSizer* m_sizer_simple = nullptr;
|
||||
wxBoxSizer* m_sizer_advanced = nullptr;
|
||||
wxGridSizer* m_gridsizer_advanced = nullptr;
|
||||
wxButton* m_widget_button = nullptr;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class WipingDialog : public wxDialog {
|
||||
public:
|
||||
WipingDialog(wxWindow* parent,const std::vector<float>& matrix, const std::vector<float>& extruders);
|
||||
std::vector<float> get_matrix() const { return m_output_matrix; }
|
||||
std::vector<float> get_extruders() const { return m_output_extruders; }
|
||||
|
||||
|
||||
private:
|
||||
WipingPanel* m_panel_wiping = nullptr;
|
||||
std::vector<float> m_output_matrix;
|
||||
std::vector<float> m_output_extruders;
|
||||
};
|
||||
|
||||
#endif // _WIPE_TOWER_DIALOG_H_
|
@ -84,7 +84,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, 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);
|
||||
|
||||
void erase()
|
||||
%code{% THIS->clear(); %};
|
||||
|
@ -169,6 +169,8 @@ PresetCollection::arrayref()
|
||||
Ref<PresetCollection> print() %code%{ RETVAL = &THIS->prints; %};
|
||||
Ref<PresetCollection> filament() %code%{ RETVAL = &THIS->filaments; %};
|
||||
Ref<PresetCollection> printer() %code%{ RETVAL = &THIS->printers; %};
|
||||
Ref<DynamicPrintConfig> project_config() %code%{ RETVAL = &THIS->project_config; %};
|
||||
|
||||
bool has_defauls_only();
|
||||
|
||||
std::vector<std::string> filament_presets() %code%{ RETVAL = THIS->filament_presets; %};
|
||||
|
Loading…
Reference in New Issue
Block a user