Ported Flow to XS
This commit is contained in:
parent
87342d324c
commit
036badf932
16 changed files with 360 additions and 201 deletions
|
@ -1,165 +1,12 @@
|
||||||
package Slic3r::Flow;
|
package Slic3r::Flow;
|
||||||
use Moo;
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
require Exporter;
|
use parent qw(Exporter);
|
||||||
our @ISA = qw(Exporter);
|
|
||||||
our @EXPORT_OK = qw(FLOW_ROLE_PERIMETER FLOW_ROLE_INFILL FLOW_ROLE_SOLID_INFILL FLOW_ROLE_TOP_SOLID_INFILL
|
our @EXPORT_OK = qw(FLOW_ROLE_PERIMETER FLOW_ROLE_INFILL FLOW_ROLE_SOLID_INFILL
|
||||||
FLOW_ROLE_SUPPORT_MATERIAL FLOW_ROLE_SUPPORT_MATERIAL_INTERFACE);
|
FLOW_ROLE_TOP_SOLID_INFILL FLOW_ROLE_SUPPORT_MATERIAL
|
||||||
|
FLOW_ROLE_SUPPORT_MATERIAL_INTERFACE);
|
||||||
our %EXPORT_TAGS = (roles => \@EXPORT_OK);
|
our %EXPORT_TAGS = (roles => \@EXPORT_OK);
|
||||||
|
|
||||||
use Slic3r::Geometry qw(PI);
|
|
||||||
|
|
||||||
has 'width' => (is => 'ro', required => 1);
|
|
||||||
has 'spacing' => (is => 'ro', required => 1);
|
|
||||||
has 'nozzle_diameter' => (is => 'ro', required => 1);
|
|
||||||
has 'bridge' => (is => 'ro', default => sub {0});
|
|
||||||
has 'scaled_width' => (is => 'lazy');
|
|
||||||
has 'scaled_spacing' => (is => 'lazy');
|
|
||||||
|
|
||||||
use constant FLOW_ROLE_PERIMETER => 1;
|
|
||||||
use constant FLOW_ROLE_INFILL => 2;
|
|
||||||
use constant FLOW_ROLE_SOLID_INFILL => 3;
|
|
||||||
use constant FLOW_ROLE_TOP_SOLID_INFILL => 4;
|
|
||||||
use constant FLOW_ROLE_SUPPORT_MATERIAL => 5;
|
|
||||||
use constant FLOW_ROLE_SUPPORT_MATERIAL_INTERFACE => 6;
|
|
||||||
|
|
||||||
use constant BRIDGE_EXTRA_SPACING => 0.05;
|
|
||||||
use constant OVERLAP_FACTOR => 1;
|
|
||||||
|
|
||||||
sub new_from_width {
|
|
||||||
my ($class, %args) = @_;
|
|
||||||
|
|
||||||
if ($args{width} eq '0') {
|
|
||||||
$args{width} = _width(@args{qw(role nozzle_diameter layer_height bridge_flow_ratio)});
|
|
||||||
} elsif ($args{width} =~ /^(\d+(?:\.\d+)?)%$/) {
|
|
||||||
$args{width} = $args{layer_height} * $1 / 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $class->new(
|
|
||||||
width => $args{width},
|
|
||||||
spacing => _spacing(@args{qw(width nozzle_diameter layer_height bridge_flow_ratio)}),
|
|
||||||
nozzle_diameter => $args{nozzle_diameter},
|
|
||||||
bridge => ($args{bridge_flow_ratio} > 0) ? 1 : 0,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
sub new_from_spacing {
|
|
||||||
my ($class, %args) = @_;
|
|
||||||
|
|
||||||
return $class->new(
|
|
||||||
width => _width_from_spacing(@args{qw(spacing nozzle_diameter layer_height bridge)}),
|
|
||||||
spacing => $args{spacing},
|
|
||||||
nozzle_diameter => $args{nozzle_diameter},
|
|
||||||
bridge => $args{bridge},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
sub clone {
|
|
||||||
my $self = shift;
|
|
||||||
|
|
||||||
return (ref $self)->new(
|
|
||||||
width => $self->width,
|
|
||||||
spacing => $self->spacing,
|
|
||||||
nozzle_diameter => $self->nozzle_diameter,
|
|
||||||
bridge => $self->bridge,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
sub mm3_per_mm {
|
|
||||||
my ($self, $h) = @_;
|
|
||||||
|
|
||||||
my $w = $self->width;
|
|
||||||
my $s = $self->spacing;
|
|
||||||
|
|
||||||
if ($self->bridge) {
|
|
||||||
return ($w**2) * PI/4;
|
|
||||||
} elsif ($w >= ($self->nozzle_diameter + $h)) {
|
|
||||||
# rectangle with semicircles at the ends
|
|
||||||
return $w * $h + ($h**2) / 4 * (PI - 4);
|
|
||||||
} else {
|
|
||||||
# rectangle with shrunk semicircles at the ends
|
|
||||||
return $self->nozzle_diameter * $h * (1 - PI/4) + $h * $w * PI/4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub _width {
|
|
||||||
my ($role, $nozzle_diameter, $layer_height, $bridge_flow_ratio) = @_;
|
|
||||||
|
|
||||||
if ($bridge_flow_ratio > 0) {
|
|
||||||
return sqrt($bridge_flow_ratio * ($nozzle_diameter**2));
|
|
||||||
}
|
|
||||||
|
|
||||||
# here we calculate a sane default by matching the flow speed (at the nozzle) and the feed rate
|
|
||||||
my $volume = ($nozzle_diameter**2) * PI/4;
|
|
||||||
my $shape_threshold = $nozzle_diameter * $layer_height + ($layer_height**2) * PI/4;
|
|
||||||
my $width;
|
|
||||||
if ($volume >= $shape_threshold) {
|
|
||||||
# rectangle with semicircles at the ends
|
|
||||||
$width = (($nozzle_diameter**2) * PI + ($layer_height**2) * (4 - PI)) / (4 * $layer_height);
|
|
||||||
} else {
|
|
||||||
# rectangle with squished semicircles at the ends
|
|
||||||
$width = $nozzle_diameter * ($nozzle_diameter/$layer_height - 4/PI + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
my $min = $nozzle_diameter * 1.05;
|
|
||||||
my $max;
|
|
||||||
if ($role == FLOW_ROLE_PERIMETER || $role == FLOW_ROLE_SUPPORT_MATERIAL) {
|
|
||||||
$min = $max = $nozzle_diameter;
|
|
||||||
} elsif ($role != FLOW_ROLE_INFILL) {
|
|
||||||
# do not limit width for sparse infill so that we use full native flow for it
|
|
||||||
$max = $nozzle_diameter * 1.7;
|
|
||||||
}
|
|
||||||
$width = $max if defined($max) && $width > $max;
|
|
||||||
$width = $min if $width < $min;
|
|
||||||
|
|
||||||
return $width;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub _width_from_spacing {
|
|
||||||
my ($s, $nozzle_diameter, $h, $bridge) = @_;
|
|
||||||
|
|
||||||
if ($bridge) {
|
|
||||||
return $s - BRIDGE_EXTRA_SPACING;
|
|
||||||
}
|
|
||||||
|
|
||||||
my $w_threshold = $h + $nozzle_diameter;
|
|
||||||
my $s_threshold = $w_threshold - OVERLAP_FACTOR * ($w_threshold - ($w_threshold - $h * (1 - PI/4)));
|
|
||||||
|
|
||||||
if ($s >= $s_threshold) {
|
|
||||||
# rectangle with semicircles at the ends
|
|
||||||
return $s + OVERLAP_FACTOR * $h * (1 - PI/4);
|
|
||||||
} else {
|
|
||||||
# rectangle with shrunk semicircles at the ends
|
|
||||||
return ($s + $nozzle_diameter * OVERLAP_FACTOR * (PI/4 - 1)) / (1 + OVERLAP_FACTOR * (PI/4 - 1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub _spacing {
|
|
||||||
my ($width, $nozzle_diameter, $layer_height, $bridge_flow_ratio) = @_;
|
|
||||||
|
|
||||||
if ($bridge_flow_ratio > 0) {
|
|
||||||
return $width + BRIDGE_EXTRA_SPACING;
|
|
||||||
}
|
|
||||||
use XXX; ZZZ "here" if !defined $nozzle_diameter;
|
|
||||||
my $min_flow_spacing;
|
|
||||||
if ($width >= ($nozzle_diameter + $layer_height)) {
|
|
||||||
# rectangle with semicircles at the ends
|
|
||||||
$min_flow_spacing = $width - $layer_height * (1 - PI/4);
|
|
||||||
} else {
|
|
||||||
# rectangle with shrunk semicircles at the ends
|
|
||||||
$min_flow_spacing = $nozzle_diameter * (1 - PI/4) + $width * PI/4;
|
|
||||||
}
|
|
||||||
return $width - OVERLAP_FACTOR * ($width - $min_flow_spacing);
|
|
||||||
}
|
|
||||||
|
|
||||||
sub _build_scaled_width {
|
|
||||||
my $self = shift;
|
|
||||||
return Slic3r::Geometry::scale($self->width);
|
|
||||||
}
|
|
||||||
|
|
||||||
sub _build_scaled_spacing {
|
|
||||||
my $self = shift;
|
|
||||||
return Slic3r::Geometry::scale($self->spacing);
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
|
@ -246,7 +246,7 @@ sub extrude_loop {
|
||||||
foreach my $path (@{$extrusion_path->intersect_expolygons($self->_layer_overhangs)}) {
|
foreach my $path (@{$extrusion_path->intersect_expolygons($self->_layer_overhangs)}) {
|
||||||
$path = $path->clone;
|
$path = $path->clone;
|
||||||
$path->role(EXTR_ROLE_OVERHANG_PERIMETER);
|
$path->role(EXTR_ROLE_OVERHANG_PERIMETER);
|
||||||
$path->mm3_per_mm($self->region->flow(FLOW_ROLE_PERIMETER, undef, 1)->mm3_per_mm(undef));
|
$path->mm3_per_mm($self->region->flow(FLOW_ROLE_PERIMETER, -1, 1)->mm3_per_mm(-1));
|
||||||
push @paths, $path;
|
push @paths, $path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,8 @@ src/ExtrusionEntity.cpp
|
||||||
src/ExtrusionEntity.hpp
|
src/ExtrusionEntity.hpp
|
||||||
src/ExtrusionEntityCollection.cpp
|
src/ExtrusionEntityCollection.cpp
|
||||||
src/ExtrusionEntityCollection.hpp
|
src/ExtrusionEntityCollection.hpp
|
||||||
|
src/Flow.cpp
|
||||||
|
src/Flow.hpp
|
||||||
src/Geometry.cpp
|
src/Geometry.cpp
|
||||||
src/Geometry.hpp
|
src/Geometry.hpp
|
||||||
src/Line.cpp
|
src/Line.cpp
|
||||||
|
@ -65,6 +67,7 @@ t/12_extrusionpathcollection.t
|
||||||
t/13_polylinecollection.t
|
t/13_polylinecollection.t
|
||||||
t/14_geometry.t
|
t/14_geometry.t
|
||||||
t/15_config.t
|
t/15_config.t
|
||||||
|
t/16_flow.t
|
||||||
xsp/Clipper.xsp
|
xsp/Clipper.xsp
|
||||||
xsp/Config.xsp
|
xsp/Config.xsp
|
||||||
xsp/ExPolygon.xsp
|
xsp/ExPolygon.xsp
|
||||||
|
@ -72,6 +75,7 @@ xsp/ExPolygonCollection.xsp
|
||||||
xsp/ExtrusionEntityCollection.xsp
|
xsp/ExtrusionEntityCollection.xsp
|
||||||
xsp/ExtrusionLoop.xsp
|
xsp/ExtrusionLoop.xsp
|
||||||
xsp/ExtrusionPath.xsp
|
xsp/ExtrusionPath.xsp
|
||||||
|
xsp/Flow.xsp
|
||||||
xsp/Geometry.xsp
|
xsp/Geometry.xsp
|
||||||
xsp/Line.xsp
|
xsp/Line.xsp
|
||||||
xsp/my.map
|
xsp/my.map
|
||||||
|
|
|
@ -146,6 +146,34 @@ our @ISA = 'Slic3r::ExtrusionPath';
|
||||||
|
|
||||||
sub DESTROY {}
|
sub DESTROY {}
|
||||||
|
|
||||||
|
package Slic3r::Flow;
|
||||||
|
|
||||||
|
sub new {
|
||||||
|
my ($class, %args) = @_;
|
||||||
|
|
||||||
|
my $self = $class->_new(
|
||||||
|
@args{qw(width spacing nozzle_diameter)},
|
||||||
|
);
|
||||||
|
$self->set_bridge($args{bridge} // 0);
|
||||||
|
return $self;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub new_from_width {
|
||||||
|
my ($class, %args) = @_;
|
||||||
|
|
||||||
|
return $class->_new_from_width(
|
||||||
|
@args{qw(role width nozzle_diameter layer_height bridge_flow_ratio)},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub new_from_spacing {
|
||||||
|
my ($class, %args) = @_;
|
||||||
|
|
||||||
|
return $class->_new_from_spacing(
|
||||||
|
@args{qw(spacing nozzle_diameter layer_height bridge)},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
package Slic3r::Surface;
|
package Slic3r::Surface;
|
||||||
|
|
||||||
sub new {
|
sub new {
|
||||||
|
|
|
@ -50,22 +50,18 @@ ConfigBase::set_deserialize(const t_config_option_key opt_key, std::string str)
|
||||||
|
|
||||||
double
|
double
|
||||||
ConfigBase::get_abs_value(const t_config_option_key opt_key) {
|
ConfigBase::get_abs_value(const t_config_option_key opt_key) {
|
||||||
// get option definition
|
ConfigOption* opt = this->option(opt_key, false);
|
||||||
assert(this->def->count(opt_key) != 0);
|
if (ConfigOptionFloatOrPercent* optv = dynamic_cast<ConfigOptionFloatOrPercent*>(opt)) {
|
||||||
ConfigOptionDef* def = &(*this->def)[opt_key];
|
// get option definition
|
||||||
assert(def->type == coFloatOrPercent);
|
assert(this->def->count(opt_key) != 0);
|
||||||
|
ConfigOptionDef* def = &(*this->def)[opt_key];
|
||||||
// get stored option value
|
|
||||||
ConfigOptionFloatOrPercent* opt = dynamic_cast<ConfigOptionFloatOrPercent*>(this->option(opt_key));
|
// compute absolute value over the absolute value of the base option
|
||||||
assert(opt != NULL);
|
return optv->get_abs_value(this->get_abs_value(def->ratio_over));
|
||||||
|
} else if (ConfigOptionFloat* optv = dynamic_cast<ConfigOptionFloat*>(opt)) {
|
||||||
// compute absolute value
|
return optv->value;
|
||||||
if (opt->percent) {
|
|
||||||
ConfigOptionFloat* optbase = dynamic_cast<ConfigOptionFloat*>(this->option(def->ratio_over));
|
|
||||||
if (optbase == NULL) throw "ratio_over option not found";
|
|
||||||
return optbase->value * opt->value / 100;
|
|
||||||
} else {
|
} else {
|
||||||
return opt->value;
|
throw "Not a valid option type for get_abs_value()";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,11 +72,7 @@ ConfigBase::get_abs_value(const t_config_option_key opt_key, double ratio_over)
|
||||||
assert(opt != NULL);
|
assert(opt != NULL);
|
||||||
|
|
||||||
// compute absolute value
|
// compute absolute value
|
||||||
if (opt->percent) {
|
return opt->get_abs_value(ratio_over);
|
||||||
return ratio_over * opt->value / 100;
|
|
||||||
} else {
|
|
||||||
return opt->value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SLIC3RXS
|
#ifdef SLIC3RXS
|
||||||
|
|
|
@ -21,7 +21,7 @@ typedef std::vector<std::string> t_config_option_keys;
|
||||||
class ConfigOption {
|
class ConfigOption {
|
||||||
public:
|
public:
|
||||||
virtual ~ConfigOption() {};
|
virtual ~ConfigOption() {};
|
||||||
virtual std::string serialize() = 0;
|
virtual std::string serialize() const = 0;
|
||||||
virtual void deserialize(std::string str) = 0;
|
virtual void deserialize(std::string str) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ class ConfigOptionFloat : public ConfigOption
|
||||||
|
|
||||||
operator double() const { return this->value; };
|
operator double() const { return this->value; };
|
||||||
|
|
||||||
std::string serialize() {
|
std::string serialize() const {
|
||||||
std::ostringstream ss;
|
std::ostringstream ss;
|
||||||
ss << this->value;
|
ss << this->value;
|
||||||
return ss.str();
|
return ss.str();
|
||||||
|
@ -64,7 +64,7 @@ class ConfigOptionFloats : public ConfigOption, public ConfigOptionVector<double
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
std::string serialize() {
|
std::string serialize() const {
|
||||||
std::ostringstream ss;
|
std::ostringstream ss;
|
||||||
for (std::vector<double>::const_iterator it = this->values.begin(); it != this->values.end(); ++it) {
|
for (std::vector<double>::const_iterator it = this->values.begin(); it != this->values.end(); ++it) {
|
||||||
if (it - this->values.begin() != 0) ss << ",";
|
if (it - this->values.begin() != 0) ss << ",";
|
||||||
|
@ -91,7 +91,7 @@ class ConfigOptionInt : public ConfigOption
|
||||||
|
|
||||||
operator int() const { return this->value; };
|
operator int() const { return this->value; };
|
||||||
|
|
||||||
std::string serialize() {
|
std::string serialize() const {
|
||||||
std::ostringstream ss;
|
std::ostringstream ss;
|
||||||
ss << this->value;
|
ss << this->value;
|
||||||
return ss.str();
|
return ss.str();
|
||||||
|
@ -106,7 +106,7 @@ class ConfigOptionInts : public ConfigOption, public ConfigOptionVector<int>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
std::string serialize() {
|
std::string serialize() const {
|
||||||
std::ostringstream ss;
|
std::ostringstream ss;
|
||||||
for (std::vector<int>::const_iterator it = this->values.begin(); it != this->values.end(); ++it) {
|
for (std::vector<int>::const_iterator it = this->values.begin(); it != this->values.end(); ++it) {
|
||||||
if (it - this->values.begin() != 0) ss << ",";
|
if (it - this->values.begin() != 0) ss << ",";
|
||||||
|
@ -133,7 +133,7 @@ class ConfigOptionString : public ConfigOption
|
||||||
|
|
||||||
operator std::string() const { return this->value; };
|
operator std::string() const { return this->value; };
|
||||||
|
|
||||||
std::string serialize() {
|
std::string serialize() const {
|
||||||
std::string str = this->value;
|
std::string str = this->value;
|
||||||
|
|
||||||
// s/\R/\\n/g
|
// s/\R/\\n/g
|
||||||
|
@ -163,7 +163,7 @@ class ConfigOptionStrings : public ConfigOption, public ConfigOptionVector<std::
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
std::string serialize() {
|
std::string serialize() const {
|
||||||
std::ostringstream ss;
|
std::ostringstream ss;
|
||||||
for (std::vector<std::string>::const_iterator it = this->values.begin(); it != this->values.end(); ++it) {
|
for (std::vector<std::string>::const_iterator it = this->values.begin(); it != this->values.end(); ++it) {
|
||||||
if (it - this->values.begin() != 0) ss << ";";
|
if (it - this->values.begin() != 0) ss << ";";
|
||||||
|
@ -189,7 +189,15 @@ class ConfigOptionFloatOrPercent : public ConfigOption
|
||||||
bool percent;
|
bool percent;
|
||||||
ConfigOptionFloatOrPercent() : value(0), percent(false) {};
|
ConfigOptionFloatOrPercent() : value(0), percent(false) {};
|
||||||
|
|
||||||
std::string serialize() {
|
double get_abs_value(double ratio_over) const {
|
||||||
|
if (this->percent) {
|
||||||
|
return ratio_over * this->value / 100;
|
||||||
|
} else {
|
||||||
|
return this->value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string serialize() const {
|
||||||
std::ostringstream ss;
|
std::ostringstream ss;
|
||||||
ss << this->value;
|
ss << this->value;
|
||||||
std::string s(ss.str());
|
std::string s(ss.str());
|
||||||
|
@ -216,7 +224,7 @@ class ConfigOptionPoint : public ConfigOption
|
||||||
|
|
||||||
operator Pointf() const { return this->point; };
|
operator Pointf() const { return this->point; };
|
||||||
|
|
||||||
std::string serialize() {
|
std::string serialize() const {
|
||||||
std::ostringstream ss;
|
std::ostringstream ss;
|
||||||
ss << this->point.x;
|
ss << this->point.x;
|
||||||
ss << ",";
|
ss << ",";
|
||||||
|
@ -233,7 +241,7 @@ class ConfigOptionPoints : public ConfigOption, public ConfigOptionVector<Pointf
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
std::string serialize() {
|
std::string serialize() const {
|
||||||
std::ostringstream ss;
|
std::ostringstream ss;
|
||||||
for (Pointfs::const_iterator it = this->values.begin(); it != this->values.end(); ++it) {
|
for (Pointfs::const_iterator it = this->values.begin(); it != this->values.end(); ++it) {
|
||||||
if (it - this->values.begin() != 0) ss << ",";
|
if (it - this->values.begin() != 0) ss << ",";
|
||||||
|
@ -264,7 +272,7 @@ class ConfigOptionBool : public ConfigOption
|
||||||
|
|
||||||
operator bool() const { return this->value; };
|
operator bool() const { return this->value; };
|
||||||
|
|
||||||
std::string serialize() {
|
std::string serialize() const {
|
||||||
return std::string(this->value ? "1" : "0");
|
return std::string(this->value ? "1" : "0");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -277,7 +285,7 @@ class ConfigOptionBools : public ConfigOption, public ConfigOptionVector<bool>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
std::string serialize() {
|
std::string serialize() const {
|
||||||
std::ostringstream ss;
|
std::ostringstream ss;
|
||||||
for (std::vector<bool>::const_iterator it = this->values.begin(); it != this->values.end(); ++it) {
|
for (std::vector<bool>::const_iterator it = this->values.begin(); it != this->values.end(); ++it) {
|
||||||
if (it - this->values.begin() != 0) ss << ",";
|
if (it - this->values.begin() != 0) ss << ",";
|
||||||
|
@ -306,7 +314,7 @@ class ConfigOptionEnum : public ConfigOption
|
||||||
|
|
||||||
operator T() const { return this->value; };
|
operator T() const { return this->value; };
|
||||||
|
|
||||||
std::string serialize() {
|
std::string serialize() const {
|
||||||
t_config_enum_values enum_keys_map = ConfigOptionEnum<T>::get_enum_values();
|
t_config_enum_values enum_keys_map = ConfigOptionEnum<T>::get_enum_values();
|
||||||
for (t_config_enum_values::iterator it = enum_keys_map.begin(); it != enum_keys_map.end(); ++it) {
|
for (t_config_enum_values::iterator it = enum_keys_map.begin(); it != enum_keys_map.end(); ++it) {
|
||||||
if (it->second == static_cast<int>(this->value)) return it->first;
|
if (it->second == static_cast<int>(this->value)) return it->first;
|
||||||
|
@ -333,7 +341,7 @@ class ConfigOptionEnumGeneric : public ConfigOption
|
||||||
|
|
||||||
operator int() const { return this->value; };
|
operator int() const { return this->value; };
|
||||||
|
|
||||||
std::string serialize() {
|
std::string serialize() const {
|
||||||
for (t_config_enum_values::iterator it = this->keys_map->begin(); it != this->keys_map->end(); ++it) {
|
for (t_config_enum_values::iterator it = this->keys_map->begin(); it != this->keys_map->end(); ++it) {
|
||||||
if (it->second == this->value) return it->first;
|
if (it->second == this->value) return it->first;
|
||||||
}
|
}
|
||||||
|
|
109
xs/src/Flow.cpp
Normal file
109
xs/src/Flow.cpp
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
#include "Flow.hpp"
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
Flow
|
||||||
|
Flow::new_from_config_width(FlowRole role, const ConfigOptionFloatOrPercent &width, float nozzle_diameter, float height, float bridge_flow_ratio) {
|
||||||
|
float w;
|
||||||
|
if (!width.percent && width.value == 0) {
|
||||||
|
w = Flow::_width(role, nozzle_diameter, height, bridge_flow_ratio);
|
||||||
|
} else {
|
||||||
|
w = width.get_abs_value(height);
|
||||||
|
}
|
||||||
|
|
||||||
|
Flow flow(w, Flow::_spacing(w, nozzle_diameter, height, bridge_flow_ratio), nozzle_diameter);
|
||||||
|
if (bridge_flow_ratio > 0) flow.bridge = true;
|
||||||
|
return flow;
|
||||||
|
}
|
||||||
|
|
||||||
|
Flow
|
||||||
|
Flow::new_from_spacing(float spacing, float nozzle_diameter, float height, bool bridge) {
|
||||||
|
float w = Flow::_width_from_spacing(spacing, nozzle_diameter, height, bridge);
|
||||||
|
Flow flow(w, spacing, nozzle_diameter);
|
||||||
|
flow.bridge = bridge;
|
||||||
|
return flow;
|
||||||
|
}
|
||||||
|
|
||||||
|
double
|
||||||
|
Flow::mm3_per_mm(float h) {
|
||||||
|
if (this->bridge) {
|
||||||
|
return (this->width * this->width) * PI/4.0;
|
||||||
|
} else if (this->width >= (this->nozzle_diameter + h)) {
|
||||||
|
// rectangle with semicircles at the ends
|
||||||
|
return this->width * h + (h*h) / 4.0 * (PI-4.0);
|
||||||
|
} else {
|
||||||
|
// rectangle with shrunk semicircles at the ends
|
||||||
|
return this->nozzle_diameter * h * (1 - PI/4.0) + h * this->width * PI/4.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float
|
||||||
|
Flow::_width(FlowRole role, float nozzle_diameter, float height, float bridge_flow_ratio) {
|
||||||
|
if (bridge_flow_ratio > 0) {
|
||||||
|
return sqrt(bridge_flow_ratio * (nozzle_diameter*nozzle_diameter));
|
||||||
|
}
|
||||||
|
|
||||||
|
// here we calculate a sane default by matching the flow speed (at the nozzle) and the feed rate
|
||||||
|
float volume = (nozzle_diameter*nozzle_diameter) * PI/4.0;
|
||||||
|
float shape_threshold = nozzle_diameter * height + (height*height) * PI/4.0;
|
||||||
|
float width;
|
||||||
|
if (volume >= shape_threshold) {
|
||||||
|
// rectangle with semicircles at the ends
|
||||||
|
width = ((nozzle_diameter*nozzle_diameter) * PI + (height*height) * (4.0 - PI)) / (4.0 * height);
|
||||||
|
} else {
|
||||||
|
// rectangle with squished semicircles at the ends
|
||||||
|
width = nozzle_diameter * (nozzle_diameter/height - 4.0/PI + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
float min = nozzle_diameter * 1.05;
|
||||||
|
float max = -1;
|
||||||
|
if (role == frPerimeter || role == frSupportMaterial) {
|
||||||
|
min = max = nozzle_diameter;
|
||||||
|
} else if (role != frInfill) {
|
||||||
|
// do not limit width for sparse infill so that we use full native flow for it
|
||||||
|
max = nozzle_diameter * 1.7;
|
||||||
|
}
|
||||||
|
if (max != -1 && width > max) width = max;
|
||||||
|
if (width < min) width = min;
|
||||||
|
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
float
|
||||||
|
Flow::_width_from_spacing(float spacing, float nozzle_diameter, float height, bool bridge) {
|
||||||
|
if (bridge) {
|
||||||
|
return spacing - BRIDGE_EXTRA_SPACING;
|
||||||
|
}
|
||||||
|
|
||||||
|
float w_threshold = height + nozzle_diameter;
|
||||||
|
float s_threshold = w_threshold - OVERLAP_FACTOR * (w_threshold - (w_threshold - height * (1 - PI/4.0)));
|
||||||
|
|
||||||
|
if (spacing >= s_threshold) {
|
||||||
|
// rectangle with semicircles at the ends
|
||||||
|
return spacing + OVERLAP_FACTOR * height * (1 - PI/4.0);
|
||||||
|
} else {
|
||||||
|
// rectangle with shrunk semicircles at the ends
|
||||||
|
return (spacing + nozzle_diameter * OVERLAP_FACTOR * (PI/4.0 - 1)) / (1 + OVERLAP_FACTOR * (PI/4.0 - 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float
|
||||||
|
Flow::_spacing(float width, float nozzle_diameter, float height, float bridge_flow_ratio) {
|
||||||
|
if (bridge_flow_ratio > 0) {
|
||||||
|
return width + BRIDGE_EXTRA_SPACING;
|
||||||
|
}
|
||||||
|
|
||||||
|
float min_flow_spacing;
|
||||||
|
if (width >= (nozzle_diameter + height)) {
|
||||||
|
// rectangle with semicircles at the ends
|
||||||
|
min_flow_spacing = width - height * (1 - PI/4.0);
|
||||||
|
} else {
|
||||||
|
// rectangle with shrunk semicircles at the ends
|
||||||
|
min_flow_spacing = nozzle_diameter * (1 - PI/4.0) + width * PI/4.0;
|
||||||
|
}
|
||||||
|
return width - OVERLAP_FACTOR * (width - min_flow_spacing);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
48
xs/src/Flow.hpp
Normal file
48
xs/src/Flow.hpp
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
#ifndef slic3r_Flow_hpp_
|
||||||
|
#define slic3r_Flow_hpp_
|
||||||
|
|
||||||
|
#include <myinit.h>
|
||||||
|
#include "Config.hpp"
|
||||||
|
#include "ExtrusionEntity.hpp"
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
#define BRIDGE_EXTRA_SPACING 0.05
|
||||||
|
#define OVERLAP_FACTOR 1.0
|
||||||
|
|
||||||
|
enum FlowRole {
|
||||||
|
frPerimeter,
|
||||||
|
frInfill,
|
||||||
|
frSolidInfill,
|
||||||
|
frTopSolidInfill,
|
||||||
|
frSupportMaterial,
|
||||||
|
frSupportMaterialInterface,
|
||||||
|
};
|
||||||
|
|
||||||
|
class Flow
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
float width;
|
||||||
|
float spacing;
|
||||||
|
float nozzle_diameter;
|
||||||
|
bool bridge;
|
||||||
|
coord_t scaled_width;
|
||||||
|
coord_t scaled_spacing;
|
||||||
|
|
||||||
|
Flow(float _w, float _s, float _nd): width(_w), spacing(_s), nozzle_diameter(_nd), bridge(false) {
|
||||||
|
this->scaled_width = scale_(this->width);
|
||||||
|
this->scaled_spacing = scale_(this->spacing);
|
||||||
|
};
|
||||||
|
double mm3_per_mm(float h);
|
||||||
|
static Flow new_from_config_width(FlowRole role, const ConfigOptionFloatOrPercent &width, float nozzle_diameter, float height, float bridge_flow_ratio);
|
||||||
|
static Flow new_from_spacing(float spacing, float nozzle_diameter, float height, bool bridge);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static float _width(FlowRole role, float nozzle_diameter, float height, float bridge_flow_ratio);
|
||||||
|
static float _width_from_spacing(float spacing, float nozzle_diameter, float height, bool bridge);
|
||||||
|
static float _spacing(float width, float nozzle_diameter, float height, float bridge_flow_ratio);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -23,8 +23,8 @@ Point::rotate(double angle, Point* center)
|
||||||
{
|
{
|
||||||
double cur_x = (double)this->x;
|
double cur_x = (double)this->x;
|
||||||
double cur_y = (double)this->y;
|
double cur_y = (double)this->y;
|
||||||
this->x = (long)round( (double)center->x + cos(angle) * (cur_x - (double)center->x) - sin(angle) * (cur_y - (double)center->y) );
|
this->x = (coord_t)round( (double)center->x + cos(angle) * (cur_x - (double)center->x) - sin(angle) * (cur_y - (double)center->y) );
|
||||||
this->y = (long)round( (double)center->y + cos(angle) * (cur_y - (double)center->y) + sin(angle) * (cur_x - (double)center->x) );
|
this->y = (coord_t)round( (double)center->y + cos(angle) * (cur_y - (double)center->y) + sin(angle) * (cur_x - (double)center->x) );
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
|
@ -17,9 +17,9 @@ typedef std::vector<Pointf> Pointfs;
|
||||||
class Point
|
class Point
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
long x;
|
coord_t x;
|
||||||
long y;
|
coord_t y;
|
||||||
explicit Point(long _x = 0, long _y = 0): x(_x), y(_y) {};
|
explicit Point(coord_t _x = 0, coord_t _y = 0): x(_x), y(_y) {};
|
||||||
void scale(double factor);
|
void scale(double factor);
|
||||||
void translate(double x, double y);
|
void translate(double x, double y);
|
||||||
void rotate(double angle, Point* center);
|
void rotate(double angle, Point* center);
|
||||||
|
|
|
@ -20,8 +20,10 @@ extern "C" {
|
||||||
|
|
||||||
#define EPSILON 1e-4
|
#define EPSILON 1e-4
|
||||||
#define SCALING_FACTOR 0.000001
|
#define SCALING_FACTOR 0.000001
|
||||||
|
#define PI 3.141592653589793238
|
||||||
#define scale_(val) (val / SCALING_FACTOR)
|
#define scale_(val) (val / SCALING_FACTOR)
|
||||||
#define unscale(val) (val * SCALING_FACTOR)
|
#define unscale(val) (val * SCALING_FACTOR)
|
||||||
|
typedef long coord_t;
|
||||||
|
|
||||||
namespace Slic3r {}
|
namespace Slic3r {}
|
||||||
using namespace Slic3r;
|
using namespace Slic3r;
|
||||||
|
|
|
@ -4,7 +4,7 @@ use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
use Slic3r::XS;
|
use Slic3r::XS;
|
||||||
use Test::More tests => 88;
|
use Test::More tests => 89;
|
||||||
|
|
||||||
foreach my $config (Slic3r::Config->new, Slic3r::Config::Full->new) {
|
foreach my $config (Slic3r::Config->new, Slic3r::Config::Full->new) {
|
||||||
$config->set('layer_height', 0.3);
|
$config->set('layer_height', 0.3);
|
||||||
|
@ -110,6 +110,9 @@ foreach my $config (Slic3r::Config->new, Slic3r::Config::Full->new) {
|
||||||
my $config2 = Slic3r::Config->new;
|
my $config2 = Slic3r::Config->new;
|
||||||
$config2->apply_static($config);
|
$config2->apply_static($config);
|
||||||
is $config2->get('perimeters'), Slic3r::Config::print_config_def()->{perimeters}{default}, 'apply_static and print_config_def';
|
is $config2->get('perimeters'), Slic3r::Config::print_config_def()->{perimeters}{default}, 'apply_static and print_config_def';
|
||||||
|
|
||||||
|
$config->set('top_solid_infill_speed', 70);
|
||||||
|
is $config->get_abs_value('top_solid_infill_speed'), 70, 'get_abs_value() works when ratio_over references a floatOrPercent option';
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
29
xs/t/16_flow.t
Normal file
29
xs/t/16_flow.t
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
#!/usr/bin/perl
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use Slic3r::XS;
|
||||||
|
use Test::More tests => 2;
|
||||||
|
|
||||||
|
{
|
||||||
|
my $flow = Slic3r::Flow->new_from_width(
|
||||||
|
role => Slic3r::Flow::FLOW_ROLE_PERIMETER,
|
||||||
|
width => '1',
|
||||||
|
nozzle_diameter => 0.5,
|
||||||
|
layer_height => 0.3,
|
||||||
|
bridge_flow_ratio => 1,
|
||||||
|
);
|
||||||
|
isa_ok $flow, 'Slic3r::Flow', 'new_from_width';
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
my $flow = Slic3r::Flow->new(
|
||||||
|
width => 1,
|
||||||
|
spacing => 0.95,
|
||||||
|
nozzle_diameter => 0.5,
|
||||||
|
);
|
||||||
|
isa_ok $flow, 'Slic3r::Flow', 'new';
|
||||||
|
}
|
||||||
|
|
||||||
|
__END__
|
80
xs/xsp/Flow.xsp
Normal file
80
xs/xsp/Flow.xsp
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
%module{Slic3r::XS};
|
||||||
|
|
||||||
|
%{
|
||||||
|
#include <myinit.h>
|
||||||
|
#include "Flow.hpp"
|
||||||
|
%}
|
||||||
|
|
||||||
|
%name{Slic3r::Flow} class Flow {
|
||||||
|
~Flow();
|
||||||
|
%name{_new} Flow(float width, float spacing, float nozzle_diameter);
|
||||||
|
void set_bridge(bool bridge)
|
||||||
|
%code{% THIS->bridge = bridge; %};
|
||||||
|
Flow* clone()
|
||||||
|
%code{% const char* CLASS = "Slic3r::Flow"; RETVAL = new Flow(*THIS); %};
|
||||||
|
|
||||||
|
float width()
|
||||||
|
%code{% RETVAL = THIS->width; %};
|
||||||
|
float spacing()
|
||||||
|
%code{% RETVAL = THIS->spacing; %};
|
||||||
|
float nozzle_diameter()
|
||||||
|
%code{% RETVAL = THIS->nozzle_diameter; %};
|
||||||
|
bool bridge()
|
||||||
|
%code{% RETVAL = THIS->bridge; %};
|
||||||
|
long scaled_width()
|
||||||
|
%code{% RETVAL = THIS->scaled_width; %};
|
||||||
|
long scaled_spacing()
|
||||||
|
%code{% RETVAL = THIS->scaled_spacing; %};
|
||||||
|
|
||||||
|
double mm3_per_mm(float height);
|
||||||
|
%{
|
||||||
|
|
||||||
|
Flow*
|
||||||
|
_new_from_width(CLASS, role, width, nozzle_diameter, height, bridge_flow_ratio)
|
||||||
|
char* CLASS;
|
||||||
|
FlowRole role;
|
||||||
|
std::string width;
|
||||||
|
float nozzle_diameter;
|
||||||
|
float height;
|
||||||
|
float bridge_flow_ratio;
|
||||||
|
CODE:
|
||||||
|
ConfigOptionFloatOrPercent optwidth;
|
||||||
|
optwidth.deserialize(width);
|
||||||
|
RETVAL = new Flow(Flow::new_from_config_width(role, optwidth, nozzle_diameter, height, bridge_flow_ratio));
|
||||||
|
OUTPUT:
|
||||||
|
RETVAL
|
||||||
|
|
||||||
|
Flow*
|
||||||
|
_new_from_spacing(CLASS, spacing, nozzle_diameter, height, bridge)
|
||||||
|
char* CLASS;
|
||||||
|
float spacing;
|
||||||
|
float nozzle_diameter;
|
||||||
|
float height;
|
||||||
|
bool bridge;
|
||||||
|
CODE:
|
||||||
|
RETVAL = new Flow(Flow::new_from_spacing(spacing, nozzle_diameter, height, bridge));
|
||||||
|
OUTPUT:
|
||||||
|
RETVAL
|
||||||
|
|
||||||
|
%}
|
||||||
|
};
|
||||||
|
|
||||||
|
%package{Slic3r::Flow};
|
||||||
|
%{
|
||||||
|
|
||||||
|
IV
|
||||||
|
_constant()
|
||||||
|
ALIAS:
|
||||||
|
FLOW_ROLE_PERIMETER = frPerimeter
|
||||||
|
FLOW_ROLE_INFILL = frInfill
|
||||||
|
FLOW_ROLE_SOLID_INFILL = frSolidInfill
|
||||||
|
FLOW_ROLE_TOP_SOLID_INFILL = frTopSolidInfill
|
||||||
|
FLOW_ROLE_SUPPORT_MATERIAL = frSupportMaterial
|
||||||
|
FLOW_ROLE_SUPPORT_MATERIAL_INTERFACE = frSupportMaterialInterface
|
||||||
|
PROTOTYPE:
|
||||||
|
CODE:
|
||||||
|
RETVAL = ix;
|
||||||
|
OUTPUT: RETVAL
|
||||||
|
|
||||||
|
%}
|
||||||
|
|
|
@ -18,11 +18,13 @@ ExPolygonCollection* O_OBJECT
|
||||||
ExtrusionEntityCollection* O_OBJECT
|
ExtrusionEntityCollection* O_OBJECT
|
||||||
ExtrusionPath* O_OBJECT
|
ExtrusionPath* O_OBJECT
|
||||||
ExtrusionLoop* O_OBJECT
|
ExtrusionLoop* O_OBJECT
|
||||||
|
Flow* O_OBJECT
|
||||||
PrintState* O_OBJECT
|
PrintState* O_OBJECT
|
||||||
Surface* O_OBJECT
|
Surface* O_OBJECT
|
||||||
SurfaceCollection* O_OBJECT
|
SurfaceCollection* O_OBJECT
|
||||||
|
|
||||||
ExtrusionRole T_UV
|
ExtrusionRole T_UV
|
||||||
|
FlowRole T_UV
|
||||||
PrintStep T_UV
|
PrintStep T_UV
|
||||||
SurfaceType T_UV
|
SurfaceType T_UV
|
||||||
ClipperLib::JoinType T_UV
|
ClipperLib::JoinType T_UV
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
%typemap{FullPrintConfig*};
|
%typemap{FullPrintConfig*};
|
||||||
%typemap{ExPolygon*};
|
%typemap{ExPolygon*};
|
||||||
%typemap{ExPolygonCollection*};
|
%typemap{ExPolygonCollection*};
|
||||||
|
%typemap{Flow*};
|
||||||
%typemap{Line*};
|
%typemap{Line*};
|
||||||
%typemap{Polyline*};
|
%typemap{Polyline*};
|
||||||
%typemap{Polygon*};
|
%typemap{Polygon*};
|
||||||
|
@ -43,6 +44,12 @@
|
||||||
$CVar = (ExtrusionRole)SvUV($PerlVar);
|
$CVar = (ExtrusionRole)SvUV($PerlVar);
|
||||||
%};
|
%};
|
||||||
};
|
};
|
||||||
|
%typemap{FlowRole}{parsed}{
|
||||||
|
%cpp_type{FlowRole};
|
||||||
|
%precall_code{%
|
||||||
|
$CVar = (FlowRole)SvUV($PerlVar);
|
||||||
|
%};
|
||||||
|
};
|
||||||
%typemap{PrintStep}{parsed}{
|
%typemap{PrintStep}{parsed}{
|
||||||
%cpp_type{PrintStep};
|
%cpp_type{PrintStep};
|
||||||
%precall_code{%
|
%precall_code{%
|
||||||
|
|
Loading…
Reference in a new issue