mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-12 09:17:52 -06:00
Ported the cooling changes from @alexrj: Don't slow down the external
perimeters if not necessary, don't take the bridging time into account when slowing down the print. Removed Extruder & GCodeWriter Perl bindings. Improved Extruder for constness. Refactored GCode::m_elapsed_time to struct ElapsedTime.
This commit is contained in:
parent
c1146e298b
commit
0454cc95f9
17 changed files with 156 additions and 220 deletions
|
@ -144,7 +144,6 @@ sub thread_cleanup {
|
|||
*Slic3r::Config::Static::DESTROY = sub {};
|
||||
*Slic3r::ExPolygon::DESTROY = sub {};
|
||||
*Slic3r::ExPolygon::Collection::DESTROY = sub {};
|
||||
*Slic3r::Extruder::DESTROY = sub {};
|
||||
*Slic3r::ExtrusionLoop::DESTROY = sub {};
|
||||
*Slic3r::ExtrusionMultiPath::DESTROY = sub {};
|
||||
*Slic3r::ExtrusionPath::DESTROY = sub {};
|
||||
|
@ -154,7 +153,6 @@ sub thread_cleanup {
|
|||
*Slic3r::GCode::DESTROY = sub {};
|
||||
*Slic3r::GCode::PlaceholderParser::DESTROY = sub {};
|
||||
*Slic3r::GCode::Sender::DESTROY = sub {};
|
||||
*Slic3r::GCode::Writer::DESTROY = sub {};
|
||||
*Slic3r::Geometry::BoundingBox::DESTROY = sub {};
|
||||
*Slic3r::Geometry::BoundingBoxf::DESTROY = sub {};
|
||||
*Slic3r::Geometry::BoundingBoxf3::DESTROY = sub {};
|
||||
|
|
18
t/cooling.t
18
t/cooling.t
|
@ -2,14 +2,14 @@ use Test::More;
|
|||
use strict;
|
||||
use warnings;
|
||||
|
||||
plan tests => 12;
|
||||
plan tests => 13;
|
||||
|
||||
BEGIN {
|
||||
use FindBin;
|
||||
use lib "$FindBin::Bin/../lib";
|
||||
}
|
||||
|
||||
use List::Util qw(first);
|
||||
use List::Util qw(none all);
|
||||
use Slic3r;
|
||||
use Slic3r::Test;
|
||||
|
||||
|
@ -139,21 +139,33 @@ $config->set('disable_fan_first_layers', [ 0 ]);
|
|||
$config->set('slowdown_below_layer_time', [ 10 ]);
|
||||
$config->set('min_print_speed', [ 0 ]);
|
||||
$config->set('start_gcode', '');
|
||||
$config->set('first_layer_speed', '100%');
|
||||
$config->set('external_perimeter_speed', 99);
|
||||
|
||||
my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
|
||||
my @layer_times = (0); # in seconds
|
||||
my %layer_external = (); # z => 1
|
||||
Slic3r::GCode::Reader->new->parse(my $gcode = Slic3r::Test::gcode($print), sub {
|
||||
my ($self, $cmd, $args, $info) = @_;
|
||||
|
||||
if ($cmd eq 'G1') {
|
||||
if ($info->{dist_Z}) {
|
||||
push @layer_times, 0;
|
||||
$layer_external{ $args->{Z} } = 0;
|
||||
}
|
||||
$layer_times[-1] += abs($info->{dist_XY} || $info->{dist_E} || $info->{dist_Z} || 0) / ($args->{F} // $self->F) * 60;
|
||||
if ($args->{F} && $args->{F} == $config->external_perimeter_speed*60) {
|
||||
$layer_external{ $self->Z }++;
|
||||
}
|
||||
}
|
||||
});
|
||||
my $all_below = !defined first { $_ > 0 && $_ < $config->slowdown_below_layer_time->[0] } @layer_times;
|
||||
@layer_times = grep $_, @layer_times;
|
||||
my $all_below = none { $_ < $config->slowdown_below_layer_time->[0] } @layer_times;
|
||||
ok $all_below, 'slowdown_below_layer_time is honored';
|
||||
|
||||
# check that all layers have at least one unaltered external perimeter speed
|
||||
my $external = all { $_ > 0 } values %layer_external;
|
||||
ok $external, 'slowdown_below_layer_time does not alter external perimeters';
|
||||
}
|
||||
|
||||
__END__
|
||||
|
|
|
@ -524,7 +524,6 @@ xsp/Clipper.xsp
|
|||
xsp/Config.xsp
|
||||
xsp/ExPolygon.xsp
|
||||
xsp/ExPolygonCollection.xsp
|
||||
xsp/Extruder.xsp
|
||||
xsp/ExtrusionEntityCollection.xsp
|
||||
xsp/ExtrusionLoop.xsp
|
||||
xsp/ExtrusionMultiPath.xsp
|
||||
|
@ -534,7 +533,6 @@ xsp/Filler.xsp
|
|||
xsp/Flow.xsp
|
||||
xsp/GCode.xsp
|
||||
xsp/GCodeSender.xsp
|
||||
xsp/GCodeWriter.xsp
|
||||
xsp/Geometry.xsp
|
||||
xsp/GUI.xsp
|
||||
xsp/GUI_3DScene.xsp
|
||||
|
|
|
@ -269,7 +269,6 @@ for my $class (qw(
|
|||
Slic3r::Config::Static
|
||||
Slic3r::ExPolygon
|
||||
Slic3r::ExPolygon::Collection
|
||||
Slic3r::Extruder
|
||||
Slic3r::ExtrusionLoop
|
||||
Slic3r::ExtrusionMultiPath
|
||||
Slic3r::ExtrusionPath
|
||||
|
@ -279,7 +278,6 @@ for my $class (qw(
|
|||
Slic3r::Flow
|
||||
Slic3r::GCode
|
||||
Slic3r::GCode::PlaceholderParser
|
||||
Slic3r::GCode::Writer
|
||||
Slic3r::Geometry::BoundingBox
|
||||
Slic3r::Geometry::BoundingBoxf
|
||||
Slic3r::Geometry::BoundingBoxf3
|
||||
|
|
|
@ -3,16 +3,16 @@
|
|||
namespace Slic3r {
|
||||
|
||||
Extruder::Extruder(unsigned int id, GCodeConfig *config)
|
||||
: id(id),
|
||||
: m_id(id),
|
||||
m_config(config)
|
||||
{
|
||||
reset();
|
||||
|
||||
// cache values that are going to be called often
|
||||
if (m_config->use_volumetric_e) {
|
||||
this->e_per_mm3 = this->extrusion_multiplier();
|
||||
m_e_per_mm3 = this->extrusion_multiplier();
|
||||
} else {
|
||||
this->e_per_mm3 = this->extrusion_multiplier()
|
||||
m_e_per_mm3 = this->extrusion_multiplier()
|
||||
* (4 / ((this->filament_diameter() * this->filament_diameter()) * PI));
|
||||
}
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ double Extruder::unretract()
|
|||
|
||||
double Extruder::e_per_mm(double mm3_per_mm) const
|
||||
{
|
||||
return mm3_per_mm * this->e_per_mm3;
|
||||
return mm3_per_mm * m_e_per_mm3;
|
||||
}
|
||||
|
||||
double Extruder::extruded_volume() const
|
||||
|
@ -91,64 +91,64 @@ double Extruder::used_filament() const
|
|||
|
||||
double Extruder::filament_diameter() const
|
||||
{
|
||||
return m_config->filament_diameter.get_at(this->id);
|
||||
return m_config->filament_diameter.get_at(m_id);
|
||||
}
|
||||
|
||||
double Extruder::filament_density() const
|
||||
{
|
||||
return m_config->filament_density.get_at(this->id);
|
||||
return m_config->filament_density.get_at(m_id);
|
||||
}
|
||||
|
||||
double Extruder::filament_cost() const
|
||||
{
|
||||
return m_config->filament_cost.get_at(this->id);
|
||||
return m_config->filament_cost.get_at(m_id);
|
||||
}
|
||||
|
||||
double Extruder::extrusion_multiplier() const
|
||||
{
|
||||
return m_config->extrusion_multiplier.get_at(this->id);
|
||||
return m_config->extrusion_multiplier.get_at(m_id);
|
||||
}
|
||||
|
||||
// Return a "retract_before_wipe" percentage as a factor clamped to <0, 1>
|
||||
double Extruder::retract_before_wipe() const
|
||||
{
|
||||
return std::min(1., std::max(0., m_config->retract_before_wipe.get_at(this->id) * 0.01));
|
||||
return std::min(1., std::max(0., m_config->retract_before_wipe.get_at(m_id) * 0.01));
|
||||
}
|
||||
|
||||
double Extruder::retract_length() const
|
||||
{
|
||||
return m_config->retract_length.get_at(this->id);
|
||||
return m_config->retract_length.get_at(m_id);
|
||||
}
|
||||
|
||||
double Extruder::retract_lift() const
|
||||
{
|
||||
return m_config->retract_lift.get_at(this->id);
|
||||
return m_config->retract_lift.get_at(m_id);
|
||||
}
|
||||
|
||||
int Extruder::retract_speed() const
|
||||
{
|
||||
return m_config->retract_speed.get_at(this->id);
|
||||
return m_config->retract_speed.get_at(m_id);
|
||||
}
|
||||
|
||||
int Extruder::deretract_speed() const
|
||||
{
|
||||
int speed = m_config->deretract_speed.get_at(this->id);
|
||||
int speed = m_config->deretract_speed.get_at(m_id);
|
||||
return (speed > 0) ? speed : this->retract_speed();
|
||||
}
|
||||
|
||||
double Extruder::retract_restart_extra() const
|
||||
{
|
||||
return m_config->retract_restart_extra.get_at(this->id);
|
||||
return m_config->retract_restart_extra.get_at(m_id);
|
||||
}
|
||||
|
||||
double Extruder::retract_length_toolchange() const
|
||||
{
|
||||
return m_config->retract_length_toolchange.get_at(this->id);
|
||||
return m_config->retract_length_toolchange.get_at(m_id);
|
||||
}
|
||||
|
||||
double Extruder::retract_restart_extra_toolchange() const
|
||||
{
|
||||
return m_config->retract_restart_extra_toolchange.get_at(this->id);
|
||||
return m_config->retract_restart_extra_toolchange.get_at(m_id);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -10,12 +10,10 @@ namespace Slic3r {
|
|||
class Extruder
|
||||
{
|
||||
public:
|
||||
unsigned int id;
|
||||
double E;
|
||||
double absolute_E;
|
||||
double retracted;
|
||||
double restart_extra;
|
||||
double e_per_mm3;
|
||||
|
||||
Extruder(unsigned int id, GCodeConfig *config);
|
||||
virtual ~Extruder() {}
|
||||
|
@ -27,10 +25,13 @@ public:
|
|||
this->restart_extra = 0;
|
||||
}
|
||||
|
||||
unsigned int id() const { return m_id; }
|
||||
|
||||
double extrude(double dE);
|
||||
double retract(double length, double restart_extra);
|
||||
double unretract();
|
||||
double e_per_mm(double mm3_per_mm) const;
|
||||
double e_per_mm3() const { return m_e_per_mm3; }
|
||||
double extruded_volume() const;
|
||||
double used_filament() const;
|
||||
|
||||
|
@ -47,20 +48,23 @@ public:
|
|||
double retract_length_toolchange() const;
|
||||
double retract_restart_extra_toolchange() const;
|
||||
|
||||
// Constructor for a key object, to be used by the stdlib search functions.
|
||||
static Extruder key(unsigned int id) { return Extruder(id); }
|
||||
|
||||
private:
|
||||
// Private constructor to create a key for a search in std::set.
|
||||
Extruder(unsigned int id) : id(id) {}
|
||||
Extruder(unsigned int id) : m_id(id) {}
|
||||
|
||||
GCodeConfig *m_config;
|
||||
unsigned int m_id;
|
||||
double m_e_per_mm3;
|
||||
};
|
||||
|
||||
// Sort Extruder objects by the extruder id by default.
|
||||
inline bool operator==(const Extruder &e1, const Extruder &e2) { return e1.id == e2.id; }
|
||||
inline bool operator!=(const Extruder &e1, const Extruder &e2) { return e1.id != e2.id; }
|
||||
inline bool operator< (const Extruder &e1, const Extruder &e2) { return e1.id < e2.id; }
|
||||
inline bool operator> (const Extruder &e1, const Extruder &e2) { return e1.id > e2.id; }
|
||||
inline bool operator==(const Extruder &e1, const Extruder &e2) { return e1.id() == e2.id(); }
|
||||
inline bool operator!=(const Extruder &e1, const Extruder &e2) { return e1.id() != e2.id(); }
|
||||
inline bool operator< (const Extruder &e1, const Extruder &e2) { return e1.id() < e2.id(); }
|
||||
inline bool operator> (const Extruder &e1, const Extruder &e2) { return e1.id() > e2.id(); }
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -83,8 +83,8 @@ int
|
|||
OozePrevention::_get_temp(GCode &gcodegen)
|
||||
{
|
||||
return (gcodegen.layer() != NULL && gcodegen.layer()->id() == 0)
|
||||
? gcodegen.config().first_layer_temperature.get_at(gcodegen.writer().extruder()->id)
|
||||
: gcodegen.config().temperature.get_at(gcodegen.writer().extruder()->id);
|
||||
? gcodegen.config().first_layer_temperature.get_at(gcodegen.writer().extruder()->id())
|
||||
: gcodegen.config().temperature.get_at(gcodegen.writer().extruder()->id());
|
||||
}
|
||||
|
||||
std::string
|
||||
|
@ -172,7 +172,7 @@ std::string WipeTowerIntegration::append_tcr(GCode &gcodegen, const WipeTower::T
|
|||
// Accumulate the elapsed time for the correct calculation of layer cooling.
|
||||
//FIXME currently disabled as Slic3r PE needs to be updated to differentiate the moves it could slow down
|
||||
// from the moves it could not.
|
||||
// gcodegen.m_elapsed_time += tcr.elapsed_time;
|
||||
gcodegen.m_elapsed_time.other += tcr.elapsed_time;
|
||||
// Let the m_writer know the current extruder_id, but ignore the generated G-code.
|
||||
if (new_extruder_id >= 0 && gcodegen.writer().need_toolchange(new_extruder_id))
|
||||
gcodegen.writer().toolchange(new_extruder_id);
|
||||
|
@ -220,7 +220,7 @@ std::string WipeTowerIntegration::finalize(GCode &gcodegen)
|
|||
return gcode;
|
||||
}
|
||||
|
||||
#define EXTRUDER_CONFIG(OPT) m_config.OPT.get_at(m_writer.extruder()->id)
|
||||
#define EXTRUDER_CONFIG(OPT) m_config.OPT.get_at(m_writer.extruder()->id())
|
||||
|
||||
inline void write(FILE *file, const std::string &what)
|
||||
{
|
||||
|
@ -648,12 +648,12 @@ bool GCode::do_export(FILE *file, Print &print)
|
|||
print.total_extruded_volume = 0.;
|
||||
print.total_weight = 0.;
|
||||
print.total_cost = 0.;
|
||||
for (const Extruder &extruder : m_writer.extruders) {
|
||||
for (const Extruder &extruder : m_writer.extruders()) {
|
||||
double used_filament = extruder.used_filament();
|
||||
double extruded_volume = extruder.extruded_volume();
|
||||
double filament_weight = extruded_volume * extruder.filament_density() * 0.001;
|
||||
double filament_cost = filament_weight * extruder.filament_cost() * 0.001;
|
||||
print.filament_stats.insert(std::pair<size_t,float>(extruder.id, used_filament));
|
||||
print.filament_stats.insert(std::pair<size_t,float>(extruder.id(), used_filament));
|
||||
fprintf(file, "; filament used = %.1lfmm (%.1lfcm3)\n", used_filament, extruded_volume * 0.001);
|
||||
if (filament_weight > 0.) {
|
||||
print.total_weight = print.total_weight + filament_weight;
|
||||
|
@ -815,13 +815,13 @@ void GCode::process_layer(
|
|||
if (! first_layer && ! m_second_layer_things_done) {
|
||||
// Transition from 1st to 2nd layer. Adjust nozzle temperatures as prescribed by the nozzle dependent
|
||||
// first_layer_temperature vs. temperature settings.
|
||||
for (const Extruder &extruder : m_writer.extruders) {
|
||||
if (print.config.single_extruder_multi_material.value && extruder.id != m_writer.extruder()->id)
|
||||
for (const Extruder &extruder : m_writer.extruders()) {
|
||||
if (print.config.single_extruder_multi_material.value && extruder.id() != m_writer.extruder()->id())
|
||||
// In single extruder multi material mode, set the temperature for the current extruder only.
|
||||
continue;
|
||||
int temperature = print.config.temperature.get_at(extruder.id);
|
||||
if (temperature > 0 && temperature != print.config.first_layer_temperature.get_at(extruder.id))
|
||||
gcode += m_writer.set_temperature(temperature, false, extruder.id);
|
||||
int temperature = print.config.temperature.get_at(extruder.id());
|
||||
if (temperature > 0 && temperature != print.config.first_layer_temperature.get_at(extruder.id()))
|
||||
gcode += m_writer.set_temperature(temperature, false, extruder.id());
|
||||
}
|
||||
gcode += m_writer.set_bed_temperature(print.config.bed_temperature.get_at(first_extruder_id));
|
||||
// Mark the temperature transition from 1st to 2nd layer to be finished.
|
||||
|
@ -1792,7 +1792,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
|||
}
|
||||
|
||||
// calculate extrusion length per distance unit
|
||||
double e_per_mm = m_writer.extruder()->e_per_mm3 * path.mm3_per_mm;
|
||||
double e_per_mm = m_writer.extruder()->e_per_mm3() * path.mm3_per_mm;
|
||||
if (m_writer.extrusion_axis().empty()) e_per_mm = 0;
|
||||
|
||||
// set speed
|
||||
|
@ -1846,8 +1846,11 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
|||
}
|
||||
if (is_bridge(path.role()) && m_enable_cooling_markers)
|
||||
gcode += ";_BRIDGE_FAN_START\n";
|
||||
gcode += m_writer.set_speed(F, "", m_enable_cooling_markers ? ";_EXTRUDE_SET_SPEED" : "");
|
||||
double path_length = 0;
|
||||
std::string comment = ";_EXTRUDE_SET_SPEED";
|
||||
if (path.role() == erExternalPerimeter)
|
||||
comment += ";_EXTERNAL_PERIMETER";
|
||||
gcode += m_writer.set_speed(F, "", m_enable_cooling_markers ? comment : "");
|
||||
double path_length = 0.;
|
||||
{
|
||||
std::string comment = m_config.gcode_comments ? description : "";
|
||||
for (const Line &line : path.polyline.lines()) {
|
||||
|
@ -1864,8 +1867,14 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
|||
|
||||
this->set_last_pos(path.last_point());
|
||||
|
||||
if (m_config.cooling.values.front())
|
||||
m_elapsed_time += path_length / F * 60.f;
|
||||
if (m_config.cooling.values.front()) {
|
||||
float t = path_length / F * 60.f;
|
||||
m_elapsed_time.total += t;
|
||||
if (is_bridge(path.role()))
|
||||
m_elapsed_time.bridges += t;
|
||||
if (path.role() == erExternalPerimeter)
|
||||
m_elapsed_time.external_perimeters += t;
|
||||
}
|
||||
|
||||
return gcode;
|
||||
}
|
||||
|
@ -1912,13 +1921,8 @@ std::string GCode::travel_to(const Point &point, ExtrusionRole role, std::string
|
|||
for (Lines::const_iterator line = lines.begin(); line != lines.end(); ++line)
|
||||
gcode += m_writer.travel_to_xy(this->point_to_gcode(line->b), comment);
|
||||
|
||||
/* While this makes the estimate more accurate, CoolingBuffer calculates the slowdown
|
||||
factor on the whole elapsed time but only alters non-travel moves, thus the resulting
|
||||
time is still shorter than the configured threshold. We could create a new
|
||||
elapsed_travel_time but we would still need to account for bridges, retractions, wipe etc.
|
||||
if (m_config.cooling.values.front())
|
||||
m_elapsed_time += unscale(travel.length()) / m_config.get_abs_value("travel_speed");
|
||||
*/
|
||||
m_elapsed_time.travel += unscale(travel.length()) / m_config.get_abs_value("travel_speed");
|
||||
|
||||
return gcode;
|
||||
}
|
||||
|
@ -2000,7 +2004,7 @@ std::string GCode::set_extruder(unsigned int extruder_id)
|
|||
// append custom toolchange G-code
|
||||
if (m_writer.extruder() != nullptr && !m_config.toolchange_gcode.value.empty()) {
|
||||
PlaceholderParser pp = m_placeholder_parser;
|
||||
pp.set("previous_extruder", m_writer.extruder()->id);
|
||||
pp.set("previous_extruder", m_writer.extruder()->id());
|
||||
pp.set("next_extruder", extruder_id);
|
||||
gcode += pp.process(m_config.toolchange_gcode.value) + '\n';
|
||||
}
|
||||
|
|
|
@ -107,6 +107,27 @@ private:
|
|||
bool m_brim_done;
|
||||
};
|
||||
|
||||
struct ElapsedTime
|
||||
{
|
||||
ElapsedTime() { this->reset(); }
|
||||
void reset() { total = bridges = external_perimeters = travel = other = 0.f; }
|
||||
|
||||
ElapsedTime& operator+=(const ElapsedTime &rhs) {
|
||||
this->total += rhs.total;
|
||||
this->bridges += rhs.bridges;
|
||||
this->external_perimeters += rhs.external_perimeters;
|
||||
this->travel += rhs.travel;
|
||||
this->other += rhs.other;
|
||||
return *this;
|
||||
}
|
||||
|
||||
float total;
|
||||
float bridges;
|
||||
float external_perimeters;
|
||||
float travel;
|
||||
float other;
|
||||
};
|
||||
|
||||
class GCode {
|
||||
public:
|
||||
GCode() :
|
||||
|
@ -117,7 +138,6 @@ public:
|
|||
m_layer_count(0),
|
||||
m_layer_index(-1),
|
||||
m_layer(nullptr),
|
||||
m_elapsed_time(0.0),
|
||||
m_volumetric_speed(0),
|
||||
m_last_pos_defined(false),
|
||||
m_last_extrusion_role(erNone),
|
||||
|
@ -140,13 +160,13 @@ public:
|
|||
const Layer* layer() const { return m_layer; }
|
||||
GCodeWriter& writer() { return m_writer; }
|
||||
bool enable_cooling_markers() const { return m_enable_cooling_markers; }
|
||||
float get_reset_elapsed_time() { float t = m_elapsed_time; m_elapsed_time = 0.f; return t; }
|
||||
ElapsedTime get_reset_elapsed_time() { ElapsedTime et = this->m_elapsed_time; this->m_elapsed_time.reset(); return et; }
|
||||
|
||||
// For Perl bindings, to be used exclusively by unit tests.
|
||||
unsigned int layer_count() const { return m_layer_count; }
|
||||
void set_layer_count(unsigned int value) { m_layer_count = value; }
|
||||
float elapsed_time() const { return m_elapsed_time; }
|
||||
void set_elapsed_time(float value) { m_elapsed_time = value; }
|
||||
float elapsed_time() const { return m_elapsed_time.total; }
|
||||
void set_elapsed_time(float value) { m_elapsed_time.total = value; }
|
||||
void apply_print_config(const PrintConfig &print_config);
|
||||
|
||||
protected:
|
||||
|
@ -247,7 +267,7 @@ protected:
|
|||
// This value is not quite precise. First it only accouts for extrusion moves and travel moves,
|
||||
// it does not account for wipe, retract / unretract moves.
|
||||
// second it does not account for the velocity profiles of the printer.
|
||||
float m_elapsed_time; // seconds
|
||||
ElapsedTime m_elapsed_time;
|
||||
double m_volumetric_speed;
|
||||
// Support for the extrusion role markers. Which marker is active?
|
||||
ExtrusionRole m_last_extrusion_role;
|
||||
|
|
|
@ -6,6 +6,17 @@
|
|||
|
||||
namespace Slic3r {
|
||||
|
||||
CoolingBuffer::CoolingBuffer(GCode &gcodegen) :
|
||||
m_gcodegen(gcodegen), m_layer_id(0),
|
||||
m_elapsed_time(new ElapsedTime)
|
||||
{
|
||||
}
|
||||
|
||||
CoolingBuffer::~CoolingBuffer()
|
||||
{
|
||||
delete m_elapsed_time;
|
||||
}
|
||||
|
||||
std::string CoolingBuffer::append(const std::string &gcode, size_t object_id, size_t layer_id, bool is_support)
|
||||
{
|
||||
std::string out;
|
||||
|
@ -21,7 +32,7 @@ std::string CoolingBuffer::append(const std::string &gcode, size_t object_id, si
|
|||
m_gcode += gcode;
|
||||
// This is a very rough estimate of the print time,
|
||||
// not taking into account the acceleration curves generated by the printer firmware.
|
||||
m_elapsed_time += m_gcodegen.get_reset_elapsed_time();
|
||||
*m_elapsed_time += m_gcodegen.get_reset_elapsed_time();
|
||||
return out;
|
||||
}
|
||||
|
||||
|
@ -46,37 +57,49 @@ void apply_speed_factor(std::string &line, float speed_factor, float min_print_s
|
|||
{
|
||||
std::ostringstream oss;
|
||||
oss << speed;
|
||||
line.replace(pos+1, (last_pos-pos), oss.str());
|
||||
line.replace(pos+1, last_pos-pos, oss.str());
|
||||
}
|
||||
}
|
||||
|
||||
std::string CoolingBuffer::flush()
|
||||
{
|
||||
const FullPrintConfig &config = m_gcodegen.config();
|
||||
|
||||
std::string gcode = m_gcode;
|
||||
float elapsed = m_elapsed_time;
|
||||
|
||||
std::string gcode = std::move(m_gcode);
|
||||
m_gcode.clear();
|
||||
m_elapsed_time = 0.;
|
||||
|
||||
int fan_speed = config.fan_always_on.values.front() ? config.min_fan_speed.values.front() : 0;
|
||||
|
||||
float speed_factor = 1.0;
|
||||
|
||||
bool slowdown_external = true;
|
||||
|
||||
if (config.cooling.values.front()) {
|
||||
#ifdef SLIC3R_DEBUG
|
||||
printf("Layer %zu estimated printing time: %f seconds\n", m_layer_id, elapsed);
|
||||
#endif
|
||||
if (elapsed < (float)config.slowdown_below_layer_time.values.front()) {
|
||||
printf("Layer %zu estimated printing time: %f seconds\n", m_layer_id, m_elapsed_time->total);
|
||||
#endif
|
||||
if (m_elapsed_time->total < (float)config.slowdown_below_layer_time.values.front()) {
|
||||
// Layer time very short. Enable the fan to a full throttle and slow down the print
|
||||
// (stretch the layer print time to slowdown_below_layer_time).
|
||||
fan_speed = config.max_fan_speed.values.front();
|
||||
speed_factor = elapsed / (float)config.slowdown_below_layer_time.values.front();
|
||||
} else if (elapsed < (float)config.fan_below_layer_time.values.front()) {
|
||||
|
||||
// We are not altering speed of bridges.
|
||||
float time_to_stretch = m_elapsed_time->total - m_elapsed_time->bridges;
|
||||
float target_time = (float)config.slowdown_below_layer_time.values.front() - m_elapsed_time->bridges;
|
||||
|
||||
// If we spend most of our time on external perimeters include them in the slowdown,
|
||||
// otherwise only alter other extrusions.
|
||||
if (m_elapsed_time->external_perimeters < 0.5f * time_to_stretch) {
|
||||
time_to_stretch -= m_elapsed_time->external_perimeters;
|
||||
target_time -= m_elapsed_time->external_perimeters;
|
||||
slowdown_external = false;
|
||||
}
|
||||
|
||||
speed_factor = time_to_stretch / target_time;
|
||||
} else if (m_elapsed_time->total < (float)config.fan_below_layer_time.values.front()) {
|
||||
// Layer time quite short. Enable the fan proportionally according to the current layer time.
|
||||
fan_speed = config.max_fan_speed.values.front()
|
||||
- (config.max_fan_speed.values.front() - config.min_fan_speed.values.front())
|
||||
* (elapsed - (float)config.slowdown_below_layer_time.values.front())
|
||||
* (m_elapsed_time->total - (float)config.slowdown_below_layer_time.values.front())
|
||||
/ (config.fan_below_layer_time.values.front() - config.slowdown_below_layer_time.values.front());
|
||||
}
|
||||
|
||||
|
@ -97,11 +120,12 @@ std::string CoolingBuffer::flush()
|
|||
if (boost::starts_with(line, "G1")
|
||||
&& boost::contains(line, ";_EXTRUDE_SET_SPEED")
|
||||
&& !boost::contains(line, ";_WIPE")
|
||||
&& !bridge_fan_start) {
|
||||
&& !bridge_fan_start
|
||||
&& (slowdown_external || !boost::contains(line, ";_EXTERNAL_PERIMETER"))) {
|
||||
apply_speed_factor(line, speed_factor, min_print_speed);
|
||||
boost::replace_first(line, ";_EXTRUDE_SET_SPEED", "");
|
||||
}
|
||||
bridge_fan_start = boost::contains(line, ";_BRIDGE_FAN_START");
|
||||
bridge_fan_start = boost::starts_with(line, ";_BRIDGE_FAN_START");
|
||||
new_gcode += line + '\n';
|
||||
}
|
||||
gcode = new_gcode;
|
||||
|
@ -122,8 +146,10 @@ std::string CoolingBuffer::flush()
|
|||
}
|
||||
boost::replace_all(gcode, ";_WIPE", "");
|
||||
boost::replace_all(gcode, ";_EXTRUDE_SET_SPEED", "");
|
||||
boost::replace_all(gcode, ";_EXTERNAL_PERIMETER", "");
|
||||
|
||||
m_object_ids_visited.clear();
|
||||
m_elapsed_time->reset();
|
||||
return gcode;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
namespace Slic3r {
|
||||
|
||||
struct ElapsedTime;
|
||||
class GCode;
|
||||
class Layer;
|
||||
|
||||
|
@ -18,7 +19,8 @@ and the print is modified to stretch over a minimum layer time.
|
|||
|
||||
class CoolingBuffer {
|
||||
public:
|
||||
CoolingBuffer(GCode &gcodegen) : m_gcodegen(gcodegen), m_elapsed_time(0.), m_layer_id(0) {}
|
||||
CoolingBuffer(GCode &gcodegen);
|
||||
~CoolingBuffer();
|
||||
std::string append(const std::string &gcode, size_t object_id, size_t layer_id, bool is_support);
|
||||
std::string flush();
|
||||
GCode* gcodegen() { return &m_gcodegen; };
|
||||
|
@ -28,7 +30,7 @@ private:
|
|||
|
||||
GCode& m_gcodegen;
|
||||
std::string m_gcode;
|
||||
float m_elapsed_time;
|
||||
ElapsedTime *m_elapsed_time;
|
||||
size_t m_layer_id;
|
||||
std::set<size_t> m_object_ids_visited;
|
||||
};
|
||||
|
|
|
@ -22,8 +22,10 @@ void GCodeWriter::apply_print_config(const PrintConfig &print_config)
|
|||
|
||||
void GCodeWriter::set_extruders(const std::vector<unsigned int> &extruder_ids)
|
||||
{
|
||||
m_extruders.clear();
|
||||
m_extruders.reserve(extruder_ids.size());
|
||||
for (unsigned int extruder_id : extruder_ids)
|
||||
this->extruders.insert(Extruder(extruder_id, &this->config));
|
||||
m_extruders.emplace_back(Extruder(extruder_id, &this->config));
|
||||
|
||||
/* we enable support for multiple extruder if any extruder greater than 0 is used
|
||||
(even if prints only uses that one) since we need to output Tx commands
|
||||
|
@ -229,8 +231,10 @@ std::string GCodeWriter::update_progress(unsigned int num, unsigned int tot, boo
|
|||
std::string GCodeWriter::toolchange(unsigned int extruder_id)
|
||||
{
|
||||
// set the new extruder
|
||||
m_extruder = const_cast<Extruder*>(&*this->extruders.find(Extruder::key(extruder_id)));
|
||||
|
||||
auto it_extruder = std::lower_bound(m_extruders.begin(), m_extruders.end(), Extruder::key(extruder_id));
|
||||
assert(it_extruder != m_extruders.end());
|
||||
m_extruder = const_cast<Extruder*>(&*it_extruder);
|
||||
|
||||
// return the toolchange command
|
||||
// if we are running a single-extruder setup, just set the extruder and return nothing
|
||||
std::ostringstream gcode;
|
||||
|
@ -469,10 +473,10 @@ std::string GCodeWriter::lift()
|
|||
// check whether the above/below conditions are met
|
||||
double target_lift = 0;
|
||||
{
|
||||
double above = this->config.retract_lift_above.get_at(m_extruder->id);
|
||||
double below = this->config.retract_lift_below.get_at(m_extruder->id);
|
||||
double above = this->config.retract_lift_above.get_at(m_extruder->id());
|
||||
double below = this->config.retract_lift_below.get_at(m_extruder->id());
|
||||
if (m_pos.z >= above && (below == 0 || m_pos.z <= below))
|
||||
target_lift = this->config.retract_lift.get_at(m_extruder->id);
|
||||
target_lift = this->config.retract_lift.get_at(m_extruder->id());
|
||||
}
|
||||
if (m_lifted == 0 && target_lift > 0) {
|
||||
m_lifted = target_lift;
|
||||
|
|
|
@ -12,7 +12,6 @@ namespace Slic3r {
|
|||
class GCodeWriter {
|
||||
public:
|
||||
GCodeConfig config;
|
||||
std::set<Extruder> extruders;
|
||||
bool multiple_extruders;
|
||||
|
||||
GCodeWriter() :
|
||||
|
@ -26,12 +25,14 @@ public:
|
|||
const Extruder* extruder() const { return m_extruder; }
|
||||
std::string extrusion_axis() const { return m_extrusion_axis; }
|
||||
void apply_print_config(const PrintConfig &print_config);
|
||||
// Extruders are expected to be sorted in an increasing order.
|
||||
void set_extruders(const std::vector<unsigned int> &extruder_ids);
|
||||
const std::vector<Extruder>& extruders() const { return m_extruders; }
|
||||
std::vector<unsigned int> extruder_ids() const {
|
||||
std::vector<unsigned int> out;
|
||||
out.reserve(extruders.size());
|
||||
for (const auto e : extruders)
|
||||
out.push_back(e.id);
|
||||
out.reserve(m_extruders.size());
|
||||
for (const Extruder &e : m_extruders)
|
||||
out.push_back(e.id());
|
||||
return out;
|
||||
}
|
||||
std::string preamble();
|
||||
|
@ -44,7 +45,7 @@ public:
|
|||
std::string update_progress(unsigned int num, unsigned int tot, bool allow_100 = false) const;
|
||||
// return false if this extruder was already selected
|
||||
bool need_toolchange(unsigned int extruder_id) const
|
||||
{ return m_extruder == nullptr || m_extruder->id != extruder_id; }
|
||||
{ return m_extruder == nullptr || m_extruder->id() != extruder_id; }
|
||||
std::string set_extruder(unsigned int extruder_id)
|
||||
{ return this->need_toolchange(extruder_id) ? this->toolchange(extruder_id) : ""; }
|
||||
std::string toolchange(unsigned int extruder_id);
|
||||
|
@ -63,6 +64,7 @@ public:
|
|||
Pointf3 get_position() const { return m_pos; }
|
||||
|
||||
private:
|
||||
std::vector<Extruder> m_extruders;
|
||||
std::string m_extrusion_axis;
|
||||
bool m_single_extruder_multi_material;
|
||||
Extruder* m_extruder;
|
||||
|
|
|
@ -5,7 +5,6 @@ namespace Slic3r {
|
|||
|
||||
REGISTER_CLASS(ExPolygon, "ExPolygon");
|
||||
REGISTER_CLASS(ExPolygonCollection, "ExPolygon::Collection");
|
||||
REGISTER_CLASS(Extruder, "Extruder");
|
||||
REGISTER_CLASS(ExtrusionMultiPath, "ExtrusionMultiPath");
|
||||
REGISTER_CLASS(ExtrusionPath, "ExtrusionPath");
|
||||
REGISTER_CLASS(ExtrusionLoop, "ExtrusionLoop");
|
||||
|
@ -17,7 +16,6 @@ REGISTER_CLASS(Flow, "Flow");
|
|||
REGISTER_CLASS(CoolingBuffer, "GCode::CoolingBuffer");
|
||||
REGISTER_CLASS(GCode, "GCode");
|
||||
REGISTER_CLASS(GCodeSender, "GCode::Sender");
|
||||
REGISTER_CLASS(GCodeWriter, "GCode::Writer");
|
||||
REGISTER_CLASS(Layer, "Layer");
|
||||
REGISTER_CLASS(SupportLayer, "Layer::Support");
|
||||
REGISTER_CLASS(LayerRegion, "Layer::Region");
|
||||
|
|
|
@ -1,52 +0,0 @@
|
|||
%module{Slic3r::XS};
|
||||
|
||||
%{
|
||||
#include <xsinit.h>
|
||||
#include "libslic3r/Extruder.hpp"
|
||||
%}
|
||||
|
||||
%name{Slic3r::Extruder} class Extruder {
|
||||
Extruder(unsigned int id, StaticPrintConfig* config)
|
||||
%code%{ RETVAL = new Extruder (id, dynamic_cast<GCodeConfig*>(config)); %};
|
||||
~Extruder();
|
||||
void reset();
|
||||
double extrude(double dE);
|
||||
double retract(double length, double restart_extra);
|
||||
double unretract();
|
||||
double e_per_mm(double mm3_per_mm);
|
||||
double extruded_volume();
|
||||
double used_filament();
|
||||
|
||||
unsigned int id()
|
||||
%code%{ RETVAL = THIS->id; %};
|
||||
|
||||
double E()
|
||||
%code%{ RETVAL = THIS->E; %};
|
||||
double set_E(double val)
|
||||
%code%{ RETVAL = THIS->E = val; %};
|
||||
double absolute_E()
|
||||
%code%{ RETVAL = THIS->absolute_E; %};
|
||||
double set_absolute_E(double val)
|
||||
%code%{ RETVAL = THIS->absolute_E = val; %};
|
||||
double retracted()
|
||||
%code%{ RETVAL = THIS->retracted; %};
|
||||
double set_retracted(double val)
|
||||
%code%{ RETVAL = THIS->retracted = val; %};
|
||||
double restart_extra()
|
||||
%code%{ RETVAL = THIS->restart_extra; %};
|
||||
double set_restart_extra(double val)
|
||||
%code%{ RETVAL = THIS->restart_extra = val; %};
|
||||
double e_per_mm3()
|
||||
%code%{ RETVAL = THIS->e_per_mm3; %};
|
||||
|
||||
double filament_diameter();
|
||||
double filament_density();
|
||||
double filament_cost();
|
||||
double extrusion_multiplier();
|
||||
double retract_length();
|
||||
double retract_lift();
|
||||
int retract_speed();
|
||||
double retract_restart_extra();
|
||||
double retract_length_toolchange();
|
||||
double retract_restart_extra_toolchange();
|
||||
};
|
|
@ -1,64 +0,0 @@
|
|||
%module{Slic3r::XS};
|
||||
|
||||
%{
|
||||
#include <xsinit.h>
|
||||
#include "libslic3r/GCodeWriter.hpp"
|
||||
%}
|
||||
|
||||
%name{Slic3r::GCode::Writer} class GCodeWriter {
|
||||
GCodeWriter();
|
||||
~GCodeWriter();
|
||||
|
||||
Ref<StaticPrintConfig> config()
|
||||
%code%{ RETVAL = &THIS->config; %};
|
||||
bool multiple_extruders()
|
||||
%code{% RETVAL = THIS->multiple_extruders; %};
|
||||
Ref<Extruder> extruder();
|
||||
std::string extrusion_axis();
|
||||
void apply_print_config(PrintConfig* print_config)
|
||||
%code{% THIS->apply_print_config(*print_config); %};
|
||||
void set_extruders(std::vector<unsigned int> extruder_ids);
|
||||
std::string preamble();
|
||||
std::string postamble();
|
||||
std::string set_temperature(unsigned int temperature, bool wait = false, int tool = -1);
|
||||
std::string set_bed_temperature(unsigned int temperature, bool wait = false);
|
||||
std::string set_fan(unsigned int speed, bool dont_save = false);
|
||||
std::string set_acceleration(unsigned int acceleration);
|
||||
std::string reset_e(bool force = false);
|
||||
std::string update_progress(unsigned int num, unsigned int tot, bool allow_100 = false);
|
||||
bool need_toolchange(unsigned int extruder_id);
|
||||
std::string set_extruder(unsigned int extruder_id);
|
||||
std::string toolchange(unsigned int extruder_id);
|
||||
std::string set_speed(double F, std::string comment = std::string());
|
||||
std::string travel_to_xy(Pointf* point, std::string comment = std::string())
|
||||
%code{% RETVAL = THIS->travel_to_xy(*point, comment); %};
|
||||
std::string travel_to_xyz(Pointf3* point, std::string comment = std::string())
|
||||
%code{% RETVAL = THIS->travel_to_xyz(*point, comment); %};
|
||||
std::string travel_to_z(double z, std::string comment = std::string());
|
||||
bool will_move_z(double z);
|
||||
std::string extrude_to_xy(Pointf* point, double dE, std::string comment = std::string())
|
||||
%code{% RETVAL = THIS->extrude_to_xy(*point, dE, comment); %};
|
||||
std::string extrude_to_xyz(Pointf3* point, double dE, std::string comment = std::string())
|
||||
%code{% RETVAL = THIS->extrude_to_xyz(*point, dE, comment); %};
|
||||
std::string retract();
|
||||
std::string retract_for_toolchange();
|
||||
std::string unretract();
|
||||
std::string lift();
|
||||
std::string unlift();
|
||||
Clone<Pointf3> get_position() const;
|
||||
%{
|
||||
|
||||
SV*
|
||||
GCodeWriter::extruders()
|
||||
CODE:
|
||||
AV* av = newAV();
|
||||
av_fill(av, THIS->extruders.size()-1);
|
||||
int i = 0;
|
||||
for (const Extruder &extruder : THIS->extruders)
|
||||
av_store(av, i++, perl_to_SV_ref(const_cast<Extruder&>(extruder)));
|
||||
RETVAL = newRV_noinc((SV*)av);
|
||||
OUTPUT:
|
||||
RETVAL
|
||||
|
||||
%}
|
||||
};
|
|
@ -138,10 +138,6 @@ Clone<Surface> O_OBJECT_SLIC3R_T
|
|||
SurfaceCollection* O_OBJECT_SLIC3R
|
||||
Ref<SurfaceCollection> O_OBJECT_SLIC3R_T
|
||||
|
||||
Extruder* O_OBJECT_SLIC3R
|
||||
Ref<Extruder> O_OBJECT_SLIC3R_T
|
||||
Clone<Extruder> O_OBJECT_SLIC3R_T
|
||||
|
||||
Model* O_OBJECT_SLIC3R
|
||||
Ref<Model> O_OBJECT_SLIC3R_T
|
||||
Clone<Model> O_OBJECT_SLIC3R_T
|
||||
|
@ -201,10 +197,6 @@ GCodeSender* O_OBJECT_SLIC3R
|
|||
Ref<GCodeSender> O_OBJECT_SLIC3R_T
|
||||
Clone<GCodeSender> O_OBJECT_SLIC3R_T
|
||||
|
||||
GCodeWriter* O_OBJECT_SLIC3R
|
||||
Ref<GCodeWriter> O_OBJECT_SLIC3R_T
|
||||
Clone<GCodeWriter> O_OBJECT_SLIC3R_T
|
||||
|
||||
BridgeDetector* O_OBJECT_SLIC3R
|
||||
Ref<BridgeDetector> O_OBJECT_SLIC3R_T
|
||||
Clone<BridgeDetector> O_OBJECT_SLIC3R_T
|
||||
|
|
|
@ -99,9 +99,6 @@
|
|||
%typemap{MotionPlanner*};
|
||||
%typemap{Ref<MotionPlanner>}{simple};
|
||||
%typemap{Clone<MotionPlanner>}{simple};
|
||||
%typemap{GCodeWriter*};
|
||||
%typemap{Ref<GCodeWriter>}{simple};
|
||||
%typemap{Clone<GCodeWriter>}{simple};
|
||||
%typemap{GCodeSender*};
|
||||
%typemap{Ref<GCodeSender>}{simple};
|
||||
%typemap{Clone<GCodeSender>}{simple};
|
||||
|
@ -169,9 +166,6 @@
|
|||
%typemap{Polygons*};
|
||||
%typemap{TriangleMesh*};
|
||||
%typemap{TriangleMeshPtrs};
|
||||
%typemap{Extruder*};
|
||||
%typemap{Ref<Extruder>}{simple};
|
||||
%typemap{Clone<Extruder>}{simple};
|
||||
%typemap{Model*};
|
||||
%typemap{Ref<Model>}{simple};
|
||||
%typemap{Clone<Model>}{simple};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue