Ported Infill unit tests from Perl to C++.
This commit is contained in:
parent
d88e9634f5
commit
33b2478b69
@ -10,6 +10,7 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "libslic3r.h"
|
#include "libslic3r.h"
|
||||||
#include "clonable_ptr.hpp"
|
#include "clonable_ptr.hpp"
|
||||||
@ -1989,6 +1990,7 @@ public:
|
|||||||
struct SetDeserializeItem {
|
struct SetDeserializeItem {
|
||||||
SetDeserializeItem(const char *opt_key, const char *opt_value, bool append = false) : opt_key(opt_key), opt_value(opt_value), append(append) {}
|
SetDeserializeItem(const char *opt_key, const char *opt_value, bool append = false) : opt_key(opt_key), opt_value(opt_value), append(append) {}
|
||||||
SetDeserializeItem(const std::string &opt_key, const std::string &opt_value, bool append = false) : opt_key(opt_key), opt_value(opt_value), append(append) {}
|
SetDeserializeItem(const std::string &opt_key, const std::string &opt_value, bool append = false) : opt_key(opt_key), opt_value(opt_value), append(append) {}
|
||||||
|
SetDeserializeItem(const std::string &opt_key, const std::string_view opt_value, bool append = false) : opt_key(opt_key), opt_value(opt_value), append(append) {}
|
||||||
SetDeserializeItem(const char *opt_key, const bool value, bool append = false) : opt_key(opt_key), opt_value(value ? "1" : "0"), append(append) {}
|
SetDeserializeItem(const char *opt_key, const bool value, bool append = false) : opt_key(opt_key), opt_value(value ? "1" : "0"), append(append) {}
|
||||||
SetDeserializeItem(const std::string &opt_key, const bool value, bool append = false) : opt_key(opt_key), opt_value(value ? "1" : "0"), append(append) {}
|
SetDeserializeItem(const std::string &opt_key, const bool value, bool append = false) : opt_key(opt_key), opt_value(value ? "1" : "0"), append(append) {}
|
||||||
SetDeserializeItem(const char *opt_key, const int value, bool append = false) : opt_key(opt_key), opt_value(std::to_string(value)), append(append) {}
|
SetDeserializeItem(const char *opt_key, const int value, bool append = false) : opt_key(opt_key), opt_value(std::to_string(value)), append(append) {}
|
||||||
|
@ -324,10 +324,10 @@ inline void extrusion_paths_append(ExtrusionPaths &dst, Polylines &&polylines, E
|
|||||||
polylines.clear();
|
polylines.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void extrusion_entities_append_paths(ExtrusionEntitiesPtr &dst, Polylines &polylines, ExtrusionRole role, double mm3_per_mm, float width, float height)
|
inline void extrusion_entities_append_paths(ExtrusionEntitiesPtr &dst, const Polylines &polylines, ExtrusionRole role, double mm3_per_mm, float width, float height)
|
||||||
{
|
{
|
||||||
dst.reserve(dst.size() + polylines.size());
|
dst.reserve(dst.size() + polylines.size());
|
||||||
for (Polyline &polyline : polylines)
|
for (const Polyline &polyline : polylines)
|
||||||
if (polyline.is_valid()) {
|
if (polyline.is_valid()) {
|
||||||
ExtrusionPath *extrusion_path = new ExtrusionPath(role, mm3_per_mm, width, height);
|
ExtrusionPath *extrusion_path = new ExtrusionPath(role, mm3_per_mm, width, height);
|
||||||
dst.push_back(extrusion_path);
|
dst.push_back(extrusion_path);
|
||||||
|
@ -35,6 +35,8 @@ public:
|
|||||||
float new_Z(const GCodeReader &reader) const { return this->has(Z) ? this->z() : reader.z(); }
|
float new_Z(const GCodeReader &reader) const { return this->has(Z) ? this->z() : reader.z(); }
|
||||||
float new_E(const GCodeReader &reader) const { return this->has(E) ? this->e() : reader.e(); }
|
float new_E(const GCodeReader &reader) const { return this->has(E) ? this->e() : reader.e(); }
|
||||||
float new_F(const GCodeReader &reader) const { return this->has(F) ? this->f() : reader.f(); }
|
float new_F(const GCodeReader &reader) const { return this->has(F) ? this->f() : reader.f(); }
|
||||||
|
Point new_XY_scaled(const GCodeReader &reader) const
|
||||||
|
{ return Point::new_scale(this->new_X(reader), this->new_Y(reader)); }
|
||||||
float dist_X(const GCodeReader &reader) const { return this->has(X) ? (this->x() - reader.x()) : 0; }
|
float dist_X(const GCodeReader &reader) const { return this->has(X) ? (this->x() - reader.x()) : 0; }
|
||||||
float dist_Y(const GCodeReader &reader) const { return this->has(Y) ? (this->y() - reader.y()) : 0; }
|
float dist_Y(const GCodeReader &reader) const { return this->has(Y) ? (this->y() - reader.y()) : 0; }
|
||||||
float dist_Z(const GCodeReader &reader) const { return this->has(Z) ? (this->z() - reader.z()) : 0; }
|
float dist_Z(const GCodeReader &reader) const { return this->has(Z) ? (this->z() - reader.z()) : 0; }
|
||||||
@ -134,6 +136,8 @@ public:
|
|||||||
float e() const { return m_position[E]; }
|
float e() const { return m_position[E]; }
|
||||||
float& f() { return m_position[F]; }
|
float& f() { return m_position[F]; }
|
||||||
float f() const { return m_position[F]; }
|
float f() const { return m_position[F]; }
|
||||||
|
Point xy_scaled() const { return Point::new_scale(this->x(), this->y()); }
|
||||||
|
|
||||||
|
|
||||||
// Returns 0 for gcfNoExtrusion.
|
// Returns 0 for gcfNoExtrusion.
|
||||||
char extrusion_axis() const { return m_extrusion_axis; }
|
char extrusion_axis() const { return m_extrusion_axis; }
|
||||||
|
318
t/fill.t
318
t/fill.t
@ -1,318 +0,0 @@
|
|||||||
use Test::More;
|
|
||||||
use strict;
|
|
||||||
use warnings;
|
|
||||||
|
|
||||||
#plan tests => 43;
|
|
||||||
# Test of a 100% coverage is off.
|
|
||||||
plan tests => 19;
|
|
||||||
|
|
||||||
BEGIN {
|
|
||||||
use FindBin;
|
|
||||||
use lib "$FindBin::Bin/../lib";
|
|
||||||
use local::lib "$FindBin::Bin/../local-lib";
|
|
||||||
}
|
|
||||||
|
|
||||||
use List::Util qw(first sum);
|
|
||||||
use Slic3r;
|
|
||||||
use Slic3r::Geometry qw(X Y scale unscale convex_hull);
|
|
||||||
use Slic3r::Geometry::Clipper qw(union diff diff_ex offset offset2_ex);
|
|
||||||
use Slic3r::Surface qw(:types);
|
|
||||||
use Slic3r::Test;
|
|
||||||
|
|
||||||
sub scale_points (@) { map [scale $_->[X], scale $_->[Y]], @_ }
|
|
||||||
|
|
||||||
{
|
|
||||||
my $expolygon = Slic3r::ExPolygon->new([ scale_points [0,0], [50,0], [50,50], [0,50] ]);
|
|
||||||
my $filler = Slic3r::Filler->new_from_type('rectilinear');
|
|
||||||
$filler->set_bounding_box($expolygon->bounding_box);
|
|
||||||
$filler->set_angle(0);
|
|
||||||
my $surface = Slic3r::Surface->new(
|
|
||||||
surface_type => S_TYPE_TOP,
|
|
||||||
expolygon => $expolygon,
|
|
||||||
);
|
|
||||||
my $flow = Slic3r::Flow->new(
|
|
||||||
width => 0.69,
|
|
||||||
height => 0.4,
|
|
||||||
nozzle_diameter => 0.50,
|
|
||||||
);
|
|
||||||
$filler->set_spacing($flow->spacing);
|
|
||||||
foreach my $angle (0, 45) {
|
|
||||||
$surface->expolygon->rotate(Slic3r::Geometry::deg2rad($angle), [0,0]);
|
|
||||||
my $paths = $filler->fill_surface($surface, layer_height => 0.4, density => 0.4);
|
|
||||||
is scalar @$paths, 1, 'one continuous path';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SKIP:
|
|
||||||
{
|
|
||||||
skip "The FillRectilinear2 does not fill the surface completely", 1;
|
|
||||||
|
|
||||||
my $test = sub {
|
|
||||||
my ($expolygon, $flow_spacing, $angle, $density) = @_;
|
|
||||||
|
|
||||||
my $filler = Slic3r::Filler->new_from_type('rectilinear');
|
|
||||||
$filler->set_bounding_box($expolygon->bounding_box);
|
|
||||||
$filler->set_angle($angle // 0);
|
|
||||||
# Adjust line spacing to fill the region.
|
|
||||||
$filler->set_dont_adjust(0);
|
|
||||||
$filler->set_link_max_length(scale(1.2*$flow_spacing));
|
|
||||||
my $surface = Slic3r::Surface->new(
|
|
||||||
surface_type => S_TYPE_BOTTOM,
|
|
||||||
expolygon => $expolygon,
|
|
||||||
);
|
|
||||||
my $flow = Slic3r::Flow->new(
|
|
||||||
width => $flow_spacing,
|
|
||||||
height => 0.4,
|
|
||||||
nozzle_diameter => $flow_spacing,
|
|
||||||
);
|
|
||||||
$filler->set_spacing($flow->spacing);
|
|
||||||
my $paths = $filler->fill_surface(
|
|
||||||
$surface,
|
|
||||||
layer_height => $flow->height,
|
|
||||||
density => $density // 1,
|
|
||||||
);
|
|
||||||
|
|
||||||
# check whether any part was left uncovered
|
|
||||||
my @grown_paths = map @{Slic3r::Polyline->new(@$_)->grow(scale $filler->spacing/2)}, @$paths;
|
|
||||||
my $uncovered = diff_ex([ @$expolygon ], [ @grown_paths ], 1);
|
|
||||||
|
|
||||||
# ignore very small dots
|
|
||||||
my $uncovered_filtered = [ grep $_->area > (scale $flow_spacing)**2, @$uncovered ];
|
|
||||||
|
|
||||||
is scalar(@$uncovered_filtered), 0, 'solid surface is fully filled';
|
|
||||||
|
|
||||||
if (0 && @$uncovered_filtered) {
|
|
||||||
require "Slic3r/SVG.pm";
|
|
||||||
Slic3r::SVG::output("uncovered.svg",
|
|
||||||
no_arrows => 1,
|
|
||||||
expolygons => [ $expolygon ],
|
|
||||||
blue_expolygons => [ @$uncovered ],
|
|
||||||
red_expolygons => [ @$uncovered_filtered ],
|
|
||||||
polylines => [ @$paths ],
|
|
||||||
);
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
my $expolygon = Slic3r::ExPolygon->new([
|
|
||||||
[6883102, 9598327.01296997],
|
|
||||||
[6883102, 20327272.01297],
|
|
||||||
[3116896, 20327272.01297],
|
|
||||||
[3116896, 9598327.01296997],
|
|
||||||
]);
|
|
||||||
$test->($expolygon, 0.55);
|
|
||||||
|
|
||||||
for (1..20) {
|
|
||||||
$expolygon->scale(1.05);
|
|
||||||
$test->($expolygon, 0.55);
|
|
||||||
}
|
|
||||||
|
|
||||||
$expolygon = Slic3r::ExPolygon->new(
|
|
||||||
[[59515297,5422499],[59531249,5578697],[59695801,6123186],[59965713,6630228],[60328214,7070685],[60773285,7434379],[61274561,7702115],[61819378,7866770],[62390306,7924789],[62958700,7866744],[63503012,7702244],[64007365,7434357],[64449960,7070398],[64809327,6634999],[65082143,6123325],[65245005,5584454],[65266967,5422499],[66267307,5422499],[66269190,8310081],[66275379,17810072],[66277259,20697500],[65267237,20697500],[65245004,20533538],[65082082,19994444],[64811462,19488579],[64450624,19048208],[64012101,18686514],[63503122,18415781],[62959151,18251378],[62453416,18198442],[62390147,18197355],[62200087,18200576],[61813519,18252990],[61274433,18415918],[60768598,18686517],[60327567,19047892],[59963609,19493297],[59695865,19994587],[59531222,20539379],[59515153,20697500],[58502480,20697500],[58502480,5422499]]
|
|
||||||
);
|
|
||||||
$test->($expolygon, 0.524341649025257);
|
|
||||||
|
|
||||||
$expolygon = Slic3r::ExPolygon->new([ scale_points [0,0], [98,0], [98,10], [0,10] ]);
|
|
||||||
$test->($expolygon, 0.5, 45, 0.99); # non-solid infill
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
my $collection = Slic3r::Polyline::Collection->new(
|
|
||||||
Slic3r::Polyline->new([0,15], [0,18], [0,20]),
|
|
||||||
Slic3r::Polyline->new([0,10], [0,8], [0,5]),
|
|
||||||
);
|
|
||||||
is_deeply
|
|
||||||
[ map $_->[Y], map @$_, @{$collection->chained_path_from(Slic3r::Point->new(0,30), 0)} ],
|
|
||||||
[20, 18, 15, 10, 8, 5],
|
|
||||||
'chained path';
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
my $collection = Slic3r::Polyline::Collection->new(
|
|
||||||
Slic3r::Polyline->new([4,0], [10,0], [15,0]),
|
|
||||||
Slic3r::Polyline->new([10,5], [15,5], [20,5]),
|
|
||||||
);
|
|
||||||
is_deeply
|
|
||||||
[ map $_->[X], map @$_, @{$collection->chained_path_from(Slic3r::Point->new(30,0), 0)} ],
|
|
||||||
[reverse 4, 10, 15, 10, 15, 20],
|
|
||||||
'chained path';
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
my $collection = Slic3r::ExtrusionPath::Collection->new(
|
|
||||||
map Slic3r::ExtrusionPath->new(polyline => $_, role => 0, mm3_per_mm => 1),
|
|
||||||
Slic3r::Polyline->new([0,15], [0,18], [0,20]),
|
|
||||||
Slic3r::Polyline->new([0,10], [0,8], [0,5]),
|
|
||||||
);
|
|
||||||
is_deeply
|
|
||||||
[ map $_->[Y], map @{$_->polyline}, @{$collection->chained_path_from(Slic3r::Point->new(0,30), 0)} ],
|
|
||||||
[20, 18, 15, 10, 8, 5],
|
|
||||||
'chained path';
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
my $collection = Slic3r::ExtrusionPath::Collection->new(
|
|
||||||
map Slic3r::ExtrusionPath->new(polyline => $_, role => 0, mm3_per_mm => 1),
|
|
||||||
Slic3r::Polyline->new([15,0], [10,0], [4,0]),
|
|
||||||
Slic3r::Polyline->new([10,5], [15,5], [20,5]),
|
|
||||||
);
|
|
||||||
is_deeply
|
|
||||||
[ map $_->[X], map @{$_->polyline}, @{$collection->chained_path_from(Slic3r::Point->new(30,0), 0)} ],
|
|
||||||
[reverse 4, 10, 15, 10, 15, 20],
|
|
||||||
'chained path';
|
|
||||||
}
|
|
||||||
|
|
||||||
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('top_fill_pattern', $pattern);
|
|
||||||
$config->set('bottom_fill_pattern', $pattern);
|
|
||||||
$config->set('perimeters', 1);
|
|
||||||
$config->set('skirts', 0);
|
|
||||||
$config->set('fill_density', 20);
|
|
||||||
$config->set('layer_height', 0.05);
|
|
||||||
$config->set('perimeter_extruder', 1);
|
|
||||||
$config->set('infill_extruder', 2);
|
|
||||||
my $print = Slic3r::Test::init_print('20mm_cube', config => $config, scale => 2);
|
|
||||||
ok my $gcode = Slic3r::Test::gcode($print), "successful $pattern infill generation";
|
|
||||||
my $tool = undef;
|
|
||||||
my @perimeter_points = my @infill_points = ();
|
|
||||||
Slic3r::GCode::Reader->new->parse($gcode, sub {
|
|
||||||
my ($self, $cmd, $args, $info) = @_;
|
|
||||||
|
|
||||||
if ($cmd =~ /^T(\d+)/) {
|
|
||||||
$tool = $1;
|
|
||||||
} elsif ($cmd eq 'G1' && $info->{extruding} && $info->{dist_XY} > 0) {
|
|
||||||
if ($tool == $config->perimeter_extruder-1) {
|
|
||||||
push @perimeter_points, Slic3r::Point->new_scale($args->{X}, $args->{Y});
|
|
||||||
} elsif ($tool == $config->infill_extruder-1) {
|
|
||||||
push @infill_points, Slic3r::Point->new_scale($args->{X}, $args->{Y});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
my $convex_hull = convex_hull(\@perimeter_points);
|
|
||||||
ok !(defined first { !$convex_hull->contains_point($_) } @infill_points), "infill does not exceed perimeters ($pattern)";
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
$config->set('infill_extrusion_width', 0.5);
|
|
||||||
$config->set('wipe_into_infill', 0);
|
|
||||||
$config->set('fill_density', 40);
|
|
||||||
$config->set('cooling', [ 0 ]); # for preventing speeds from being altered
|
|
||||||
$config->set('first_layer_speed', '100%'); # for preventing speeds from being altered
|
|
||||||
|
|
||||||
my $test = sub {
|
|
||||||
my $print = Slic3r::Test::init_print('pyramid', config => $config);
|
|
||||||
|
|
||||||
my $tool = undef;
|
|
||||||
my @infill_extrusions = (); # array of polylines
|
|
||||||
Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub {
|
|
||||||
my ($self, $cmd, $args, $info) = @_;
|
|
||||||
|
|
||||||
if ($cmd =~ /^T(\d+)/) {
|
|
||||||
$tool = $1;
|
|
||||||
} elsif ($cmd eq 'G1' && $info->{extruding} && $info->{dist_XY} > 0) {
|
|
||||||
if ($tool == $config->infill_extruder-1) {
|
|
||||||
push @infill_extrusions, Slic3r::Line->new_scale(
|
|
||||||
[ $self->X, $self->Y ],
|
|
||||||
[ $info->{new_X}, $info->{new_Y} ],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return 0 if !@infill_extrusions; # prevent calling convex_hull() with no points
|
|
||||||
|
|
||||||
my $convex_hull = convex_hull([ map $_->pp, map @$_, @infill_extrusions ]);
|
|
||||||
return unscale unscale sum(map $_->area, @{offset([$convex_hull], scale(+$config->infill_extrusion_width/2))});
|
|
||||||
};
|
|
||||||
|
|
||||||
my $tolerance = 5; # mm^2
|
|
||||||
|
|
||||||
$config->set('solid_infill_below_area', 0);
|
|
||||||
ok $test->() < $tolerance,
|
|
||||||
'no infill is generated when using infill_only_where_needed on a pyramid';
|
|
||||||
|
|
||||||
$config->set('solid_infill_below_area', 70);
|
|
||||||
ok abs($test->() - $config->solid_infill_below_area) < $tolerance,
|
|
||||||
'infill is only generated under the forced solid shells';
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
my $config = Slic3r::Config::new_from_defaults;
|
|
||||||
$config->set('skirts', 0);
|
|
||||||
$config->set('perimeters', 1);
|
|
||||||
$config->set('fill_density', 0);
|
|
||||||
$config->set('top_solid_layers', 0);
|
|
||||||
$config->set('bottom_solid_layers', 0);
|
|
||||||
$config->set('solid_infill_below_area', 20000000);
|
|
||||||
$config->set('solid_infill_every_layers', 2);
|
|
||||||
$config->set('perimeter_speed', 99);
|
|
||||||
$config->set('external_perimeter_speed', 99);
|
|
||||||
$config->set('cooling', [ 0 ]);
|
|
||||||
$config->set('first_layer_speed', '100%');
|
|
||||||
|
|
||||||
my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
|
|
||||||
my %layers_with_extrusion = ();
|
|
||||||
Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub {
|
|
||||||
my ($self, $cmd, $args, $info) = @_;
|
|
||||||
|
|
||||||
if ($cmd eq 'G1' && $info->{dist_XY} > 0 && $info->{extruding}) {
|
|
||||||
if (($args->{F} // $self->F) != $config->perimeter_speed*60) {
|
|
||||||
$layers_with_extrusion{$self->Z} = ($args->{F} // $self->F);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
ok !%layers_with_extrusion,
|
|
||||||
"solid_infill_below_area and solid_infill_every_layers are ignored when fill_density is 0";
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
my $config = Slic3r::Config::new_from_defaults;
|
|
||||||
$config->set('skirts', 0);
|
|
||||||
$config->set('perimeters', 3);
|
|
||||||
$config->set('fill_density', 0);
|
|
||||||
$config->set('layer_height', 0.2);
|
|
||||||
$config->set('first_layer_height', 0.2);
|
|
||||||
$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);
|
|
||||||
$config->set('solid_infill_extrusion_width', 0.52);
|
|
||||||
$config->set('first_layer_extrusion_width', 0);
|
|
||||||
|
|
||||||
my $print = Slic3r::Test::init_print('A', config => $config);
|
|
||||||
my %infill = (); # Z => [ Line, Line ... ]
|
|
||||||
my $tool = undef;
|
|
||||||
Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub {
|
|
||||||
my ($self, $cmd, $args, $info) = @_;
|
|
||||||
|
|
||||||
if ($cmd =~ /^T(\d+)/) {
|
|
||||||
$tool = $1;
|
|
||||||
} elsif ($cmd eq 'G1' && $info->{extruding} && $info->{dist_XY} > 0) {
|
|
||||||
if ($tool == $config->infill_extruder-1) {
|
|
||||||
my $z = 1 * $self->Z;
|
|
||||||
$infill{$z} ||= [];
|
|
||||||
push @{$infill{$z}}, Slic3r::Line->new_scale(
|
|
||||||
[ $self->X, $self->Y ],
|
|
||||||
[ $info->{new_X}, $info->{new_Y} ],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
my $grow_d = scale($config->infill_extrusion_width)/2;
|
|
||||||
my $layer0_infill = union([ map @{$_->grow($grow_d)}, @{ $infill{0.2} } ]);
|
|
||||||
my $layer1_infill = union([ map @{$_->grow($grow_d)}, @{ $infill{0.4} } ]);
|
|
||||||
my $diff = diff($layer0_infill, $layer1_infill);
|
|
||||||
$diff = offset2_ex($diff, -$grow_d, +$grow_d);
|
|
||||||
$diff = [ grep { $_->area > 2*(($grow_d*2)**2) } @$diff ];
|
|
||||||
is scalar(@$diff), 0, 'no missing parts in solid shell when fill_density is 0';
|
|
||||||
}
|
|
||||||
|
|
||||||
__END__
|
|
@ -187,6 +187,19 @@ TriangleMesh mesh(TestMesh m)
|
|||||||
return mesh;
|
return mesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TriangleMesh mesh(TestMesh min, Vec3d translate, Vec3d scale)
|
||||||
|
{
|
||||||
|
TriangleMesh m = mesh(min);
|
||||||
|
m.translate(translate.cast<float>());
|
||||||
|
m.scale(scale.cast<float>());
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
TriangleMesh mesh(TestMesh m, Vec3d translate, double scale)
|
||||||
|
{
|
||||||
|
return mesh(m, translate, Vec3d(scale, scale, scale));
|
||||||
|
}
|
||||||
|
|
||||||
static bool verbose_gcode()
|
static bool verbose_gcode()
|
||||||
{
|
{
|
||||||
const char *v = std::getenv("SLIC3R_TESTS_GCODE");
|
const char *v = std::getenv("SLIC3R_TESTS_GCODE");
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include "libslic3r/ExtrusionEntityCollection.hpp"
|
#include "libslic3r/ExtrusionEntityCollection.hpp"
|
||||||
#include "libslic3r/ExtrusionEntity.hpp"
|
#include "libslic3r/ExtrusionEntity.hpp"
|
||||||
#include "libslic3r/Point.hpp"
|
#include "libslic3r/Point.hpp"
|
||||||
|
#include "libslic3r/ShortestPath.hpp"
|
||||||
#include "libslic3r/libslic3r.h"
|
#include "libslic3r/libslic3r.h"
|
||||||
|
|
||||||
#include "test_data.hpp"
|
#include "test_data.hpp"
|
||||||
@ -83,3 +84,60 @@ SCENARIO("ExtrusionEntityCollection: Polygon flattening", "[ExtrusionEntity]") {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("ExtrusionEntityCollection: Chained path", "[ExtrusionEntity]") {
|
||||||
|
struct Test {
|
||||||
|
Polylines unchained;
|
||||||
|
Polylines chained;
|
||||||
|
Point initial_point;
|
||||||
|
};
|
||||||
|
std::vector<Test> tests {
|
||||||
|
{
|
||||||
|
{
|
||||||
|
{ {0,15}, {0,18}, {0,20} },
|
||||||
|
{ {0,10}, {0,8}, {0,5} }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{ {0,20}, {0,18}, {0,15} },
|
||||||
|
{ {0,10}, {0,8}, {0,5} }
|
||||||
|
},
|
||||||
|
{ 0,30 }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{
|
||||||
|
{ {4,0}, {10,0}, {15,0} },
|
||||||
|
{ {10,5}, {15,5}, {20,5} }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{ {20,5}, {15,5}, {10,5} },
|
||||||
|
{ {15,0}, {10,0}, {4,0} }
|
||||||
|
},
|
||||||
|
{ 30,0 }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{
|
||||||
|
{ {15,0}, {10,0}, {4,0} },
|
||||||
|
{ {10,5}, {15,5}, {20,5} }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{ {20,5}, {15,5}, {10,5} },
|
||||||
|
{ {15,0}, {10,0}, {4,0} }
|
||||||
|
},
|
||||||
|
{ 30,0 }
|
||||||
|
},
|
||||||
|
};
|
||||||
|
for (const Test &test : tests) {
|
||||||
|
Polylines chained = chain_polylines(test.unchained, &test.initial_point);
|
||||||
|
REQUIRE(chained == test.chained);
|
||||||
|
ExtrusionEntityCollection unchained_extrusions;
|
||||||
|
extrusion_entities_append_paths(unchained_extrusions.entities, test.unchained,
|
||||||
|
erInternalInfill, 0., 0.4f, 0.3f);
|
||||||
|
ExtrusionEntityCollection chained_extrusions = unchained_extrusions.chained_path_from(test.initial_point);
|
||||||
|
REQUIRE(chained_extrusions.entities.size() == test.chained.size());
|
||||||
|
for (size_t i = 0; i < chained_extrusions.entities.size(); ++ i) {
|
||||||
|
const Points &p1 = test.chained[i].points;
|
||||||
|
const Points &p2 = dynamic_cast<const ExtrusionPath*>(chained_extrusions.entities[i])->polyline.points;
|
||||||
|
REQUIRE(p1 == p2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -7,6 +7,7 @@
|
|||||||
#include "libslic3r/Fill/Fill.hpp"
|
#include "libslic3r/Fill/Fill.hpp"
|
||||||
#include "libslic3r/Flow.hpp"
|
#include "libslic3r/Flow.hpp"
|
||||||
#include "libslic3r/Geometry.hpp"
|
#include "libslic3r/Geometry.hpp"
|
||||||
|
#include "libslic3r/Geometry/ConvexHull.hpp"
|
||||||
#include "libslic3r/Print.hpp"
|
#include "libslic3r/Print.hpp"
|
||||||
#include "libslic3r/SVG.hpp"
|
#include "libslic3r/SVG.hpp"
|
||||||
#include "libslic3r/libslic3r.h"
|
#include "libslic3r/libslic3r.h"
|
||||||
@ -14,6 +15,7 @@
|
|||||||
#include "test_data.hpp"
|
#include "test_data.hpp"
|
||||||
|
|
||||||
using namespace Slic3r;
|
using namespace Slic3r;
|
||||||
|
using namespace std::literals;
|
||||||
|
|
||||||
bool test_if_solid_surface_filled(const ExPolygon& expolygon, double flow_spacing, double angle = 0, double density = 1.0);
|
bool test_if_solid_surface_filled(const ExPolygon& expolygon, double flow_spacing, double angle = 0, double density = 1.0);
|
||||||
|
|
||||||
@ -43,7 +45,7 @@ TEST_CASE("Fill: Pattern Path Length", "[Fill]") {
|
|||||||
SECTION("Square") {
|
SECTION("Square") {
|
||||||
Slic3r::Points test_set;
|
Slic3r::Points test_set;
|
||||||
test_set.reserve(4);
|
test_set.reserve(4);
|
||||||
std::vector<Vec2d> points {Vec2d(0,0), Vec2d(100,0), Vec2d(100,100), Vec2d(0,100)};
|
std::vector<Vec2d> points { {0,0}, {100,0}, {100,100}, {0,100} };
|
||||||
for (size_t i = 0; i < 4; ++i) {
|
for (size_t i = 0; i < 4; ++i) {
|
||||||
std::transform(points.cbegin()+i, points.cend(), std::back_inserter(test_set), [] (const Vec2d& a) -> Point { return Point::new_scale(a.x(), a.y()); } );
|
std::transform(points.cbegin()+i, points.cend(), std::back_inserter(test_set), [] (const Vec2d& a) -> Point { return Point::new_scale(a.x(), a.y()); } );
|
||||||
std::transform(points.cbegin(), points.cbegin()+i, std::back_inserter(test_set), [] (const Vec2d& a) -> Point { return Point::new_scale(a.x(), a.y()); } );
|
std::transform(points.cbegin(), points.cbegin()+i, std::back_inserter(test_set), [] (const Vec2d& a) -> Point { return Point::new_scale(a.x(), a.y()); } );
|
||||||
@ -118,26 +120,28 @@ TEST_CASE("Fill: Pattern Path Length", "[Fill]") {
|
|||||||
REQUIRE(std::abs(paths[0].length() - static_cast<double>(scale_(3*100 + 2*50))) - SCALED_EPSILON > 0); // path has expected length
|
REQUIRE(std::abs(paths[0].length() - static_cast<double>(scale_(3*100 + 2*50))) - SCALED_EPSILON > 0); // path has expected length
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("Rotated Square") {
|
SECTION("Rotated Square produces one continuous path") {
|
||||||
Slic3r::Points square { Point::new_scale(0,0), Point::new_scale(50,0), Point::new_scale(50,50), Point::new_scale(0,50)};
|
Slic3r::ExPolygon expolygon(Polygon::new_scale({ {0, 0}, {50, 0}, {50, 50}, {0, 50} }));
|
||||||
Slic3r::ExPolygon expolygon(square);
|
|
||||||
std::unique_ptr<Slic3r::Fill> filler(Slic3r::Fill::new_from_type("rectilinear"));
|
std::unique_ptr<Slic3r::Fill> filler(Slic3r::Fill::new_from_type("rectilinear"));
|
||||||
filler->bounding_box = get_extents(expolygon.contour);
|
filler->bounding_box = get_extents(expolygon);
|
||||||
filler->angle = 0;
|
filler->angle = 0;
|
||||||
|
|
||||||
Surface surface(stTop, expolygon);
|
Surface surface(stTop, expolygon);
|
||||||
auto flow = Slic3r::Flow(0.69f, 0.4f, 0.50f);
|
// width, height, nozzle_dmr
|
||||||
|
auto flow = Slic3r::Flow(0.69f, 0.4f, 0.5f);
|
||||||
|
|
||||||
FillParams fill_params;
|
FillParams fill_params;
|
||||||
fill_params.density = 1.0;
|
for (auto density : { 0.4, 1.0 }) {
|
||||||
|
fill_params.density = density;
|
||||||
filler->spacing = flow.spacing();
|
filler->spacing = flow.spacing();
|
||||||
|
|
||||||
for (auto angle : { 0.0, 45.0}) {
|
for (auto angle : { 0.0, 45.0}) {
|
||||||
surface.expolygon.rotate(angle, Point(0,0));
|
surface.expolygon.rotate(angle, Point(0,0));
|
||||||
Polylines paths = filler->fill_surface(&surface, fill_params);
|
Polylines paths = filler->fill_surface(&surface, fill_params);
|
||||||
|
// one continuous path
|
||||||
REQUIRE(paths.size() == 1);
|
REQUIRE(paths.size() == 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#if 0 // Disabled temporarily due to precission issues on the Mac VM
|
#if 0 // Disabled temporarily due to precission issues on the Mac VM
|
||||||
SECTION("Solid surface fill") {
|
SECTION("Solid surface fill") {
|
||||||
@ -190,202 +194,226 @@ TEST_CASE("Fill: Pattern Path Length", "[Fill]") {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
SCENARIO("Infill does not exceed perimeters", "[Fill]")
|
||||||
{
|
{
|
||||||
my $collection = Slic3r::Polyline::Collection->new(
|
auto test = [](const std::string_view pattern) {
|
||||||
Slic3r::Polyline->new([0,15], [0,18], [0,20]),
|
DynamicPrintConfig config = Slic3r::DynamicPrintConfig::full_print_config();
|
||||||
Slic3r::Polyline->new([0,10], [0,8], [0,5]),
|
config.set_deserialize_strict({
|
||||||
);
|
{ "nozzle_diameter", "0.4, 0.4, 0.4, 0.4" },
|
||||||
is_deeply
|
{ "fill_pattern", pattern },
|
||||||
[ map $_->[Y], map @$_, @{$collection->chained_path_from(Slic3r::Point->new(0,30), 0)} ],
|
{ "top_fill_pattern", pattern },
|
||||||
[20, 18, 15, 10, 8, 5],
|
{ "bottom_fill_pattern", pattern },
|
||||||
'chained path';
|
{ "perimeters", 1 },
|
||||||
}
|
{ "skirts", 0 },
|
||||||
|
{ "fill_density", 0.2 },
|
||||||
|
{ "layer_height", 0.05 },
|
||||||
|
{ "perimeter_extruder", 1 },
|
||||||
|
{ "infill_extruder", 2 }
|
||||||
|
});
|
||||||
|
|
||||||
|
WHEN("40mm cube sliced") {
|
||||||
|
std::string gcode = Slic3r::Test::slice({ mesh(Slic3r::Test::TestMesh::cube_20x20x20, Vec3d::Zero(), 2.0) }, config);
|
||||||
|
THEN("gcode not empty") {
|
||||||
|
REQUIRE(! gcode.empty());
|
||||||
|
}
|
||||||
|
THEN("infill does not exceed perimeters") {
|
||||||
|
GCodeReader parser;
|
||||||
|
const int perimeter_extruder = config.opt_int("perimeter_extruder");
|
||||||
|
const int infill_extruder = config.opt_int("infill_extruder");
|
||||||
|
int tool = -1;
|
||||||
|
Points perimeter_points;
|
||||||
|
Points infill_points;
|
||||||
|
parser.parse_buffer(gcode, [&tool, &perimeter_points, &infill_points, perimeter_extruder, infill_extruder]
|
||||||
|
(Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line)
|
||||||
{
|
{
|
||||||
my $collection = Slic3r::Polyline::Collection->new(
|
// if the command is a T command, set the the current tool
|
||||||
Slic3r::Polyline->new([4,0], [10,0], [15,0]),
|
if (boost::starts_with(line.cmd(), "T")) {
|
||||||
Slic3r::Polyline->new([10,5], [15,5], [20,5]),
|
tool = atoi(line.cmd().data() + 1) + 1;
|
||||||
);
|
} else if (line.cmd() == "G1" && line.extruding(self) && line.dist_XY(self) > 0) {
|
||||||
is_deeply
|
if (tool == perimeter_extruder)
|
||||||
[ map $_->[X], map @$_, @{$collection->chained_path_from(Slic3r::Point->new(30,0), 0)} ],
|
perimeter_points.emplace_back(line.new_XY_scaled(self));
|
||||||
[reverse 4, 10, 15, 10, 15, 20],
|
else if (tool == infill_extruder)
|
||||||
'chained path';
|
infill_points.emplace_back(line.new_XY_scaled(self));
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
my $collection = Slic3r::ExtrusionPath::Collection->new(
|
|
||||||
map Slic3r::ExtrusionPath->new(polyline => $_, role => 0, mm3_per_mm => 1),
|
|
||||||
Slic3r::Polyline->new([0,15], [0,18], [0,20]),
|
|
||||||
Slic3r::Polyline->new([0,10], [0,8], [0,5]),
|
|
||||||
);
|
|
||||||
is_deeply
|
|
||||||
[ map $_->[Y], map @{$_->polyline}, @{$collection->chained_path_from(Slic3r::Point->new(0,30), 0)} ],
|
|
||||||
[20, 18, 15, 10, 8, 5],
|
|
||||||
'chained path';
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
my $collection = Slic3r::ExtrusionPath::Collection->new(
|
|
||||||
map Slic3r::ExtrusionPath->new(polyline => $_, role => 0, mm3_per_mm => 1),
|
|
||||||
Slic3r::Polyline->new([15,0], [10,0], [4,0]),
|
|
||||||
Slic3r::Polyline->new([10,5], [15,5], [20,5]),
|
|
||||||
);
|
|
||||||
is_deeply
|
|
||||||
[ map $_->[X], map @{$_->polyline}, @{$collection->chained_path_from(Slic3r::Point->new(30,0), 0)} ],
|
|
||||||
[reverse 4, 10, 15, 10, 15, 20],
|
|
||||||
'chained path';
|
|
||||||
}
|
|
||||||
|
|
||||||
for my $pattern (qw(rectilinear honeycomb hilbertcurve concentric)) {
|
|
||||||
my $config = Slic3r::Config->new_from_defaults;
|
|
||||||
$config->set('fill_pattern', $pattern);
|
|
||||||
$config->set('external_fill_pattern', $pattern);
|
|
||||||
$config->set('perimeters', 1);
|
|
||||||
$config->set('skirts', 0);
|
|
||||||
$config->set('fill_density', 20);
|
|
||||||
$config->set('layer_height', 0.05);
|
|
||||||
$config->set('perimeter_extruder', 1);
|
|
||||||
$config->set('infill_extruder', 2);
|
|
||||||
my $print = Slic3r::Test::init_print('20mm_cube', config => $config, scale => 2);
|
|
||||||
ok my $gcode = Slic3r::Test::gcode($print), "successful $pattern infill generation";
|
|
||||||
my $tool = undef;
|
|
||||||
my @perimeter_points = my @infill_points = ();
|
|
||||||
Slic3r::GCode::Reader->new->parse($gcode, sub {
|
|
||||||
my ($self, $cmd, $args, $info) = @_;
|
|
||||||
|
|
||||||
if ($cmd =~ /^T(\d+)/) {
|
|
||||||
$tool = $1;
|
|
||||||
} elsif ($cmd eq 'G1' && $info->{extruding} && $info->{dist_XY} > 0) {
|
|
||||||
if ($tool == $config->perimeter_extruder-1) {
|
|
||||||
push @perimeter_points, Slic3r::Point->new_scale($args->{X}, $args->{Y});
|
|
||||||
} elsif ($tool == $config->infill_extruder-1) {
|
|
||||||
push @infill_points, Slic3r::Point->new_scale($args->{X}, $args->{Y});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
my $convex_hull = convex_hull(\@perimeter_points);
|
auto convex_hull = Geometry::convex_hull(perimeter_points);
|
||||||
ok !(defined first { !$convex_hull->contains_point($_) } @infill_points), "infill does not exceed perimeters ($pattern)";
|
int num_inside = std::count_if(infill_points.begin(), infill_points.end(), [&convex_hull](const Point &pt){ return convex_hull.contains(pt); });
|
||||||
}
|
REQUIRE(num_inside == infill_points.size());
|
||||||
|
|
||||||
{
|
|
||||||
my $config = Slic3r::Config->new_from_defaults;
|
|
||||||
$config->set('infill_only_where_needed', 1);
|
|
||||||
$config->set('bottom_solid_layers', 0);
|
|
||||||
$config->set('infill_extruder', 2);
|
|
||||||
$config->set('infill_extrusion_width', 0.5);
|
|
||||||
$config->set('fill_density', 40);
|
|
||||||
$config->set('cooling', 0); # for preventing speeds from being altered
|
|
||||||
$config->set('first_layer_speed', '100%'); # for preventing speeds from being altered
|
|
||||||
|
|
||||||
my $test = sub {
|
|
||||||
my $print = Slic3r::Test::init_print('pyramid', config => $config);
|
|
||||||
|
|
||||||
my $tool = undef;
|
|
||||||
my @infill_extrusions = (); # array of polylines
|
|
||||||
Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub {
|
|
||||||
my ($self, $cmd, $args, $info) = @_;
|
|
||||||
|
|
||||||
if ($cmd =~ /^T(\d+)/) {
|
|
||||||
$tool = $1;
|
|
||||||
} elsif ($cmd eq 'G1' && $info->{extruding} && $info->{dist_XY} > 0) {
|
|
||||||
if ($tool == $config->infill_extruder-1) {
|
|
||||||
push @infill_extrusions, Slic3r::Line->new_scale(
|
|
||||||
[ $self->X, $self->Y ],
|
|
||||||
[ $info->{new_X}, $info->{new_Y} ],
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
return 0 if !@infill_extrusions; # prevent calling convex_hull() with no points
|
|
||||||
|
|
||||||
my $convex_hull = convex_hull([ map $_->pp, map @$_, @infill_extrusions ]);
|
|
||||||
return unscale unscale sum(map $_->area, @{offset([$convex_hull], scale(+$config->infill_extrusion_width/2))});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
my $tolerance = 5; # mm^2
|
GIVEN("Rectilinear") { test("rectilinear"sv); }
|
||||||
|
GIVEN("Honeycomb") { test("honeycomb"sv); }
|
||||||
$config->set('solid_infill_below_area', 0);
|
GIVEN("HilbertCurve") { test("hilbertcurve"sv); }
|
||||||
ok $test->() < $tolerance,
|
GIVEN("Concentric") { test("concentric"sv); }
|
||||||
'no infill is generated when using infill_only_where_needed on a pyramid';
|
|
||||||
|
|
||||||
$config->set('solid_infill_below_area', 70);
|
|
||||||
ok abs($test->() - $config->solid_infill_below_area) < $tolerance,
|
|
||||||
'infill is only generated under the forced solid shells';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SCENARIO("Infill only where needed", "[Fill]")
|
||||||
{
|
{
|
||||||
my $config = Slic3r::Config->new_from_defaults;
|
DynamicPrintConfig config = Slic3r::DynamicPrintConfig::full_print_config();
|
||||||
$config->set('skirts', 0);
|
config.set_deserialize_strict({
|
||||||
$config->set('perimeters', 1);
|
{ "nozzle_diameter", "0.4, 0.4, 0.4, 0.4" },
|
||||||
$config->set('fill_density', 0);
|
{ "infill_only_where_needed", true },
|
||||||
$config->set('top_solid_layers', 0);
|
{ "bottom_solid_layers", 0 },
|
||||||
$config->set('bottom_solid_layers', 0);
|
{ "infill_extruder", 2 },
|
||||||
$config->set('solid_infill_below_area', 20000000);
|
{ "infill_extrusion_width", 0.5 },
|
||||||
$config->set('solid_infill_every_layers', 2);
|
{ "wipe_into_infill", false },
|
||||||
$config->set('perimeter_speed', 99);
|
{ "fill_density", 0.4 },
|
||||||
$config->set('external_perimeter_speed', 99);
|
// for preventing speeds from being altered
|
||||||
$config->set('cooling', 0);
|
{ "cooling", "0, 0, 0, 0" },
|
||||||
$config->set('first_layer_speed', '100%');
|
// for preventing speeds from being altered
|
||||||
|
{ "first_layer_speed", "100%" }
|
||||||
|
});
|
||||||
|
|
||||||
my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
|
auto test = [&config]() -> double {
|
||||||
my %layers_with_extrusion = ();
|
std::string gcode = Slic3r::Test::slice({ Slic3r::Test::TestMesh::pyramid }, config);
|
||||||
Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub {
|
THEN("gcode not empty") {
|
||||||
my ($self, $cmd, $args, $info) = @_;
|
REQUIRE(! gcode.empty());
|
||||||
|
}
|
||||||
|
|
||||||
if ($cmd eq 'G1' && $info->{dist_XY} > 0 && $info->{extruding}) {
|
GCodeReader parser;
|
||||||
if (($args->{F} // $self->F) != $config->perimeter_speed*60) {
|
int tool = -1;
|
||||||
$layers_with_extrusion{$self->Z} = ($args->{F} // $self->F);
|
const int infill_extruder = config.opt_int("infill_extruder");
|
||||||
|
Points infill_points;
|
||||||
|
parser.parse_buffer(gcode, [&tool, &infill_points, infill_extruder](Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line)
|
||||||
|
{
|
||||||
|
// if the command is a T command, set the the current tool
|
||||||
|
if (boost::starts_with(line.cmd(), "T")) {
|
||||||
|
tool = atoi(line.cmd().data() + 1) + 1;
|
||||||
|
} else if (line.cmd() == "G1" && line.extruding(self) && line.dist_XY(self) > 0) {
|
||||||
|
if (tool == infill_extruder) {
|
||||||
|
infill_points.emplace_back(self.xy_scaled());
|
||||||
|
infill_points.emplace_back(line.new_XY_scaled(self));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
// prevent calling convex_hull() with no points
|
||||||
ok !%layers_with_extrusion,
|
THEN("infill not empty") {
|
||||||
"solid_infill_below_area and solid_infill_every_layers are ignored when fill_density is 0";
|
REQUIRE(! infill_points.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto opt_width = config.opt<ConfigOptionFloatOrPercent>("infill_extrusion_width");
|
||||||
|
REQUIRE(! opt_width->percent);
|
||||||
|
Polygons convex_hull = expand(Geometry::convex_hull(infill_points), scaled<float>(opt_width->value / 2));
|
||||||
|
return SCALING_FACTOR * SCALING_FACTOR * std::accumulate(convex_hull.begin(), convex_hull.end(), 0., [](double acc, const Polygon &poly){ return acc + poly.area(); });
|
||||||
|
};
|
||||||
|
|
||||||
|
double tolerance = 5; // mm^2
|
||||||
|
|
||||||
|
GIVEN("solid_infill_below_area == 0") {
|
||||||
|
config.opt_float("solid_infill_below_area") = 0;
|
||||||
|
WHEN("pyramid is sliced ") {
|
||||||
|
auto area = test();
|
||||||
|
THEN("no infill is generated when using infill_only_where_needed on a pyramid") {
|
||||||
|
REQUIRE(area < tolerance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GIVEN("solid_infill_below_area == 70") {
|
||||||
|
config.opt_float("solid_infill_below_area") = 70;
|
||||||
|
WHEN("pyramid is sliced ") {
|
||||||
|
auto area = test();
|
||||||
|
THEN("infill is only generated under the forced solid shells") {
|
||||||
|
REQUIRE(std::abs(area - 70) < tolerance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SCENARIO("Infill density zero", "[Fill]")
|
||||||
{
|
{
|
||||||
my $config = Slic3r::Config->new_from_defaults;
|
WHEN("20mm cube is sliced") {
|
||||||
$config->set('skirts', 0);
|
DynamicPrintConfig config = Slic3r::DynamicPrintConfig::full_print_config();
|
||||||
$config->set('perimeters', 3);
|
config.set_deserialize_strict({
|
||||||
$config->set('fill_density', 0);
|
{ "skirts", 0 },
|
||||||
$config->set('layer_height', 0.2);
|
{ "perimeters", 1 },
|
||||||
$config->set('first_layer_height', 0.2);
|
{ "fill_density", 0 },
|
||||||
$config->set('nozzle_diameter', [0.35]);
|
{ "top_solid_layers", 0 },
|
||||||
$config->set('infill_extruder', 2);
|
{ "bottom_solid_layers", 0 },
|
||||||
$config->set('solid_infill_extruder', 2);
|
{ "solid_infill_below_area", 20000000 },
|
||||||
$config->set('infill_extrusion_width', 0.52);
|
{ "solid_infill_every_layers", 2 },
|
||||||
$config->set('solid_infill_extrusion_width', 0.52);
|
{ "perimeter_speed", 99 },
|
||||||
$config->set('first_layer_extrusion_width', 0);
|
{ "external_perimeter_speed", 99 },
|
||||||
|
{ "cooling", "0" },
|
||||||
|
{ "first_layer_speed", "100%" }
|
||||||
|
});
|
||||||
|
|
||||||
my $print = Slic3r::Test::init_print('A', config => $config);
|
std::string gcode = Slic3r::Test::slice({ Slic3r::Test::TestMesh::cube_20x20x20 }, config);
|
||||||
my %infill = (); # Z => [ Line, Line ... ]
|
THEN("gcode not empty") {
|
||||||
my $tool = undef;
|
REQUIRE(! gcode.empty());
|
||||||
Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub {
|
|
||||||
my ($self, $cmd, $args, $info) = @_;
|
|
||||||
|
|
||||||
if ($cmd =~ /^T(\d+)/) {
|
|
||||||
$tool = $1;
|
|
||||||
} elsif ($cmd eq 'G1' && $info->{extruding} && $info->{dist_XY} > 0) {
|
|
||||||
if ($tool == $config->infill_extruder-1) {
|
|
||||||
my $z = 1 * $self->Z;
|
|
||||||
$infill{$z} ||= [];
|
|
||||||
push @{$infill{$z}}, Slic3r::Line->new_scale(
|
|
||||||
[ $self->X, $self->Y ],
|
|
||||||
[ $info->{new_X}, $info->{new_Y} ],
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
THEN("solid_infill_below_area and solid_infill_every_layers are ignored when fill_density is 0") {
|
||||||
|
GCodeReader parser;
|
||||||
|
const double perimeter_speed = config.opt_float("perimeter_speed");
|
||||||
|
std::map<double, double> layers_with_extrusion;
|
||||||
|
parser.parse_buffer(gcode, [&layers_with_extrusion, perimeter_speed](Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line) {
|
||||||
|
if (line.cmd() == "G1" && line.extruding(self) && line.dist_XY(self) > 0) {
|
||||||
|
double f = line.new_F(self);
|
||||||
|
if (std::abs(f - perimeter_speed * 60.) > 0.01)
|
||||||
|
// It is a perimeter.
|
||||||
|
layers_with_extrusion[self.z()] = f;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
my $grow_d = scale($config->infill_extrusion_width)/2;
|
REQUIRE(layers_with_extrusion.empty());
|
||||||
my $layer0_infill = union([ map @{$_->grow($grow_d)}, @{ $infill{0.2} } ]);
|
}
|
||||||
my $layer1_infill = union([ map @{$_->grow($grow_d)}, @{ $infill{0.4} } ]);
|
|
||||||
my $diff = diff($layer0_infill, $layer1_infill);
|
|
||||||
$diff = offset2_ex($diff, -$grow_d, +$grow_d);
|
|
||||||
$diff = [ grep { $_->area > 2*(($grow_d*2)**2) } @$diff ];
|
|
||||||
is scalar(@$diff), 0, 'no missing parts in solid shell when fill_density is 0';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WHEN("A is sliced") {
|
||||||
|
DynamicPrintConfig config = Slic3r::DynamicPrintConfig::full_print_config();
|
||||||
|
config.set_deserialize_strict({
|
||||||
|
{ "skirts", 0 },
|
||||||
|
{ "perimeters", 3 },
|
||||||
|
{ "fill_density", 0 },
|
||||||
|
{ "layer_height", 0.2 },
|
||||||
|
{ "first_layer_height", 0.2 },
|
||||||
|
{ "nozzle_diameter", "0.35,0.35,0.35,0.35" },
|
||||||
|
{ "infill_extruder", 2 },
|
||||||
|
{ "solid_infill_extruder", 2 },
|
||||||
|
{ "infill_extrusion_width", 0.52 },
|
||||||
|
{ "solid_infill_extrusion_width", 0.52 },
|
||||||
|
{ "first_layer_extrusion_width", 0 }
|
||||||
|
});
|
||||||
|
|
||||||
|
std::string gcode = Slic3r::Test::slice({ Slic3r::Test::TestMesh::A }, config);
|
||||||
|
THEN("gcode not empty") {
|
||||||
|
REQUIRE(! gcode.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
THEN("no missing parts in solid shell when fill_density is 0") {
|
||||||
|
GCodeReader parser;
|
||||||
|
int tool = -1;
|
||||||
|
const int infill_extruder = config.opt_int("infill_extruder");
|
||||||
|
std::map<coord_t, Lines> infill;
|
||||||
|
parser.parse_buffer(gcode, [&tool, &infill, infill_extruder](Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line) {
|
||||||
|
if (boost::starts_with(line.cmd(), "T")) {
|
||||||
|
tool = atoi(line.cmd().data() + 1) + 1;
|
||||||
|
} else if (line.cmd() == "G1" && line.extruding(self) && line.dist_XY(self) > 0) {
|
||||||
|
if (tool == infill_extruder)
|
||||||
|
infill[scaled<coord_t>(self.z())].emplace_back(self.xy_scaled(), line.new_XY_scaled(self));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
auto opt_width = config.opt<ConfigOptionFloatOrPercent>("infill_extrusion_width");
|
||||||
|
REQUIRE(! opt_width->percent);
|
||||||
|
auto grow_d = scaled<float>(opt_width->value / 2);
|
||||||
|
auto inflate_lines = [grow_d](const Lines &lines) {
|
||||||
|
Polygons out;
|
||||||
|
for (const Line &line : lines)
|
||||||
|
append(out, offset(Polyline{ line.a, line.b }, grow_d, Slic3r::ClipperLib::jtSquare, 3.));
|
||||||
|
return union_(out);
|
||||||
|
};
|
||||||
|
Polygons layer0_infill = inflate_lines(infill[scaled<coord_t>(0.2)]);
|
||||||
|
Polygons layer1_infill = inflate_lines(infill[scaled<coord_t>(0.4)]);
|
||||||
|
ExPolygons poly = opening_ex(diff_ex(layer0_infill, layer1_infill), grow_d);
|
||||||
|
const double threshold = 2. * sqr(grow_d * 2.);
|
||||||
|
int missing_parts = std::count_if(poly.begin(), poly.end(), [threshold](const ExPolygon &poly){ return poly.area() > threshold; });
|
||||||
|
REQUIRE(missing_parts == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
{
|
{
|
||||||
# GH: #2697
|
# GH: #2697
|
||||||
my $config = Slic3r::Config->new_from_defaults;
|
my $config = Slic3r::Config->new_from_defaults;
|
||||||
@ -427,6 +455,78 @@ for my $pattern (qw(rectilinear honeycomb hilbertcurve concentric)) {
|
|||||||
my @holes = map @{$_->holes}, @$covered;
|
my @holes = map @{$_->holes}, @$covered;
|
||||||
ok sum(map unscale unscale $_->area*-1, @holes) < 1, 'no gaps between top solid infill and perimeters';
|
ok sum(map unscale unscale $_->area*-1, @holes) < 1, 'no gaps between top solid infill and perimeters';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
skip "The FillRectilinear2 does not fill the surface completely", 1;
|
||||||
|
|
||||||
|
my $test = sub {
|
||||||
|
my ($expolygon, $flow_spacing, $angle, $density) = @_;
|
||||||
|
|
||||||
|
my $filler = Slic3r::Filler->new_from_type('rectilinear');
|
||||||
|
$filler->set_bounding_box($expolygon->bounding_box);
|
||||||
|
$filler->set_angle($angle // 0);
|
||||||
|
# Adjust line spacing to fill the region.
|
||||||
|
$filler->set_dont_adjust(0);
|
||||||
|
$filler->set_link_max_length(scale(1.2*$flow_spacing));
|
||||||
|
my $surface = Slic3r::Surface->new(
|
||||||
|
surface_type => S_TYPE_BOTTOM,
|
||||||
|
expolygon => $expolygon,
|
||||||
|
);
|
||||||
|
my $flow = Slic3r::Flow->new(
|
||||||
|
width => $flow_spacing,
|
||||||
|
height => 0.4,
|
||||||
|
nozzle_diameter => $flow_spacing,
|
||||||
|
);
|
||||||
|
$filler->set_spacing($flow->spacing);
|
||||||
|
my $paths = $filler->fill_surface(
|
||||||
|
$surface,
|
||||||
|
layer_height => $flow->height,
|
||||||
|
density => $density // 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
# check whether any part was left uncovered
|
||||||
|
my @grown_paths = map @{Slic3r::Polyline->new(@$_)->grow(scale $filler->spacing/2)}, @$paths;
|
||||||
|
my $uncovered = diff_ex([ @$expolygon ], [ @grown_paths ], 1);
|
||||||
|
|
||||||
|
# ignore very small dots
|
||||||
|
my $uncovered_filtered = [ grep $_->area > (scale $flow_spacing)**2, @$uncovered ];
|
||||||
|
|
||||||
|
is scalar(@$uncovered_filtered), 0, 'solid surface is fully filled';
|
||||||
|
|
||||||
|
if (0 && @$uncovered_filtered) {
|
||||||
|
require "Slic3r/SVG.pm";
|
||||||
|
Slic3r::SVG::output("uncovered.svg",
|
||||||
|
no_arrows => 1,
|
||||||
|
expolygons => [ $expolygon ],
|
||||||
|
blue_expolygons => [ @$uncovered ],
|
||||||
|
red_expolygons => [ @$uncovered_filtered ],
|
||||||
|
polylines => [ @$paths ],
|
||||||
|
);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
my $expolygon = Slic3r::ExPolygon->new([
|
||||||
|
[6883102, 9598327.01296997],
|
||||||
|
[6883102, 20327272.01297],
|
||||||
|
[3116896, 20327272.01297],
|
||||||
|
[3116896, 9598327.01296997],
|
||||||
|
]);
|
||||||
|
$test->($expolygon, 0.55);
|
||||||
|
|
||||||
|
for (1..20) {
|
||||||
|
$expolygon->scale(1.05);
|
||||||
|
$test->($expolygon, 0.55);
|
||||||
|
}
|
||||||
|
|
||||||
|
$expolygon = Slic3r::ExPolygon->new(
|
||||||
|
[[59515297,5422499],[59531249,5578697],[59695801,6123186],[59965713,6630228],[60328214,7070685],[60773285,7434379],[61274561,7702115],[61819378,7866770],[62390306,7924789],[62958700,7866744],[63503012,7702244],[64007365,7434357],[64449960,7070398],[64809327,6634999],[65082143,6123325],[65245005,5584454],[65266967,5422499],[66267307,5422499],[66269190,8310081],[66275379,17810072],[66277259,20697500],[65267237,20697500],[65245004,20533538],[65082082,19994444],[64811462,19488579],[64450624,19048208],[64012101,18686514],[63503122,18415781],[62959151,18251378],[62453416,18198442],[62390147,18197355],[62200087,18200576],[61813519,18252990],[61274433,18415918],[60768598,18686517],[60327567,19047892],[59963609,19493297],[59695865,19994587],[59531222,20539379],[59515153,20697500],[58502480,20697500],[58502480,5422499]]
|
||||||
|
);
|
||||||
|
$test->($expolygon, 0.524341649025257);
|
||||||
|
|
||||||
|
$expolygon = Slic3r::ExPolygon->new([ scale_points [0,0], [98,0], [98,10], [0,10] ]);
|
||||||
|
$test->($expolygon, 0.5, 45, 0.99); # non-solid infill
|
||||||
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
bool test_if_solid_surface_filled(const ExPolygon& expolygon, double flow_spacing, double angle, double density)
|
bool test_if_solid_surface_filled(const ExPolygon& expolygon, double flow_spacing, double angle, double density)
|
||||||
|
@ -53,11 +53,8 @@ set(XS_XSP_FILES
|
|||||||
${XSP_DIR}/ExtrusionLoop.xsp
|
${XSP_DIR}/ExtrusionLoop.xsp
|
||||||
${XSP_DIR}/ExtrusionMultiPath.xsp
|
${XSP_DIR}/ExtrusionMultiPath.xsp
|
||||||
${XSP_DIR}/ExtrusionPath.xsp
|
${XSP_DIR}/ExtrusionPath.xsp
|
||||||
${XSP_DIR}/ExtrusionSimulator.xsp
|
|
||||||
${XSP_DIR}/Filler.xsp
|
|
||||||
${XSP_DIR}/Flow.xsp
|
${XSP_DIR}/Flow.xsp
|
||||||
${XSP_DIR}/GCode.xsp
|
${XSP_DIR}/GCode.xsp
|
||||||
# ${XSP_DIR}/GCodeSender.xsp
|
|
||||||
${XSP_DIR}/Geometry.xsp
|
${XSP_DIR}/Geometry.xsp
|
||||||
${XSP_DIR}/Layer.xsp
|
${XSP_DIR}/Layer.xsp
|
||||||
${XSP_DIR}/Line.xsp
|
${XSP_DIR}/Line.xsp
|
||||||
|
@ -133,23 +133,6 @@ sub clone {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
package Slic3r::ExtrusionSimulator;
|
|
||||||
|
|
||||||
sub new {
|
|
||||||
my ($class, %args) = @_;
|
|
||||||
return $class->_new();
|
|
||||||
}
|
|
||||||
|
|
||||||
package Slic3r::Filler;
|
|
||||||
|
|
||||||
sub fill_surface {
|
|
||||||
my ($self, $surface, %args) = @_;
|
|
||||||
$self->set_density($args{density}) if defined($args{density});
|
|
||||||
$self->set_dont_adjust($args{dont_adjust}) if defined($args{dont_adjust});
|
|
||||||
$self->set_complete($args{complete}) if defined($args{complete});
|
|
||||||
return $self->_fill_surface($surface);
|
|
||||||
}
|
|
||||||
|
|
||||||
package Slic3r::Flow;
|
package Slic3r::Flow;
|
||||||
|
|
||||||
sub new {
|
sub new {
|
||||||
@ -255,19 +238,12 @@ for my $class (qw(
|
|||||||
Slic3r::ExtrusionMultiPath
|
Slic3r::ExtrusionMultiPath
|
||||||
Slic3r::ExtrusionPath
|
Slic3r::ExtrusionPath
|
||||||
Slic3r::ExtrusionPath::Collection
|
Slic3r::ExtrusionPath::Collection
|
||||||
Slic3r::ExtrusionSimulator
|
|
||||||
Slic3r::Filler
|
|
||||||
Slic3r::Flow
|
Slic3r::Flow
|
||||||
Slic3r::GCode
|
Slic3r::GCode
|
||||||
Slic3r::GCode::PlaceholderParser
|
Slic3r::GCode::PlaceholderParser
|
||||||
Slic3r::Geometry::BoundingBox
|
Slic3r::Geometry::BoundingBox
|
||||||
Slic3r::Geometry::BoundingBoxf
|
Slic3r::Geometry::BoundingBoxf
|
||||||
Slic3r::Geometry::BoundingBoxf3
|
Slic3r::Geometry::BoundingBoxf3
|
||||||
Slic3r::GUI::_3DScene::GLShader
|
|
||||||
Slic3r::GUI::_3DScene::GLVolume
|
|
||||||
Slic3r::GUI::Preset
|
|
||||||
Slic3r::GUI::PresetCollection
|
|
||||||
Slic3r::GUI::Tab
|
|
||||||
Slic3r::Layer
|
Slic3r::Layer
|
||||||
Slic3r::Layer::Region
|
Slic3r::Layer::Region
|
||||||
Slic3r::Layer::Support
|
Slic3r::Layer::Support
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
// #include <libslic3r/GCodeSender.hpp>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
/* extern "C" { */
|
/* extern "C" { */
|
||||||
|
@ -9,8 +9,6 @@ REGISTER_CLASS(ExtrusionMultiPath, "ExtrusionMultiPath");
|
|||||||
REGISTER_CLASS(ExtrusionPath, "ExtrusionPath");
|
REGISTER_CLASS(ExtrusionPath, "ExtrusionPath");
|
||||||
REGISTER_CLASS(ExtrusionLoop, "ExtrusionLoop");
|
REGISTER_CLASS(ExtrusionLoop, "ExtrusionLoop");
|
||||||
REGISTER_CLASS(ExtrusionEntityCollection, "ExtrusionPath::Collection");
|
REGISTER_CLASS(ExtrusionEntityCollection, "ExtrusionPath::Collection");
|
||||||
REGISTER_CLASS(ExtrusionSimulator, "ExtrusionSimulator");
|
|
||||||
REGISTER_CLASS(Filler, "Filler");
|
|
||||||
REGISTER_CLASS(Flow, "Flow");
|
REGISTER_CLASS(Flow, "Flow");
|
||||||
REGISTER_CLASS(CoolingBuffer, "GCode::CoolingBuffer");
|
REGISTER_CLASS(CoolingBuffer, "GCode::CoolingBuffer");
|
||||||
REGISTER_CLASS(GCode, "GCode");
|
REGISTER_CLASS(GCode, "GCode");
|
||||||
|
@ -1,50 +0,0 @@
|
|||||||
%module{Slic3r::XS};
|
|
||||||
|
|
||||||
%{
|
|
||||||
#include <xsinit.h>
|
|
||||||
#include "libslic3r/ExtrusionSimulator.hpp"
|
|
||||||
%}
|
|
||||||
|
|
||||||
%name{Slic3r::ExtrusionSimulator} class ExtrusionSimulator {
|
|
||||||
~ExtrusionSimulator();
|
|
||||||
%name{_new} ExtrusionSimulator();
|
|
||||||
|
|
||||||
Clone<ExtrusionSimulator> clone()
|
|
||||||
%code{% RETVAL = THIS; %};
|
|
||||||
|
|
||||||
void set_image_size(Point *image_size)
|
|
||||||
%code{% THIS->set_image_size(*image_size); %};
|
|
||||||
void set_viewport(BoundingBox *viewport)
|
|
||||||
%code{% THIS->set_viewport(*viewport); %};
|
|
||||||
void set_bounding_box(BoundingBox *bbox)
|
|
||||||
%code{% THIS->set_bounding_box(*bbox); %};
|
|
||||||
|
|
||||||
void reset_accumulator();
|
|
||||||
void extrude_to_accumulator(ExtrusionPath *path, Point *shift, ExtrusionSimulationType simulationType)
|
|
||||||
%code{% THIS->extrude_to_accumulator(*path, *shift, simulationType); %};
|
|
||||||
void evaluate_accumulator(ExtrusionSimulationType simulationType);
|
|
||||||
void* image_ptr()
|
|
||||||
%code{% RETVAL = const_cast<void*>(const_cast<Slic3r::ExtrusionSimulator*>(THIS)->image_ptr()); %};
|
|
||||||
|
|
||||||
%{
|
|
||||||
|
|
||||||
%}
|
|
||||||
};
|
|
||||||
|
|
||||||
%package{Slic3r::ExtrusionSimulator};
|
|
||||||
%{
|
|
||||||
|
|
||||||
IV
|
|
||||||
_constant()
|
|
||||||
ALIAS:
|
|
||||||
EXTRSIM_SIMPLE = ExtrusionSimulationSimple
|
|
||||||
EXTRSIM_DONT_SPREAD = ExtrusionSimulationDontSpread
|
|
||||||
EXTRSIM_SPREAD_NFULL = ExtrisopmSimulationSpreadNotOverfilled
|
|
||||||
EXTRSIM_SPREAD_FULL = ExtrusionSimulationSpreadFull
|
|
||||||
EXTRSIM_SPREAD_EXCESS = ExtrusionSimulationSpreadExcess
|
|
||||||
PROTOTYPE:
|
|
||||||
CODE:
|
|
||||||
RETVAL = ix;
|
|
||||||
OUTPUT: RETVAL
|
|
||||||
|
|
||||||
%}
|
|
@ -1,65 +0,0 @@
|
|||||||
%module{Slic3r::XS};
|
|
||||||
|
|
||||||
%{
|
|
||||||
#include <xsinit.h>
|
|
||||||
#include "libslic3r/Fill/Fill.hpp"
|
|
||||||
#include "libslic3r/ExtrusionEntity.hpp"
|
|
||||||
#include "libslic3r/ExtrusionEntityCollection.hpp"
|
|
||||||
%}
|
|
||||||
|
|
||||||
%name{Slic3r::Filler} class Filler {
|
|
||||||
~Filler();
|
|
||||||
|
|
||||||
void set_bounding_box(BoundingBox *bbox)
|
|
||||||
%code{% THIS->fill->set_bounding_box(*bbox); %};
|
|
||||||
void set_spacing(coordf_t spacing)
|
|
||||||
%code{% THIS->fill->spacing = spacing; %};
|
|
||||||
coordf_t spacing()
|
|
||||||
%code{% RETVAL = THIS->fill->spacing; %};
|
|
||||||
void set_layer_id(size_t layer_id)
|
|
||||||
%code{% THIS->fill->layer_id = layer_id; %};
|
|
||||||
void set_z(coordf_t z)
|
|
||||||
%code{% THIS->fill->z = z; %};
|
|
||||||
void set_angle(float angle)
|
|
||||||
%code{% THIS->fill->angle = angle; %};
|
|
||||||
void set_link_max_length(coordf_t len)
|
|
||||||
%code{% THIS->fill->link_max_length = len; %};
|
|
||||||
void set_loop_clipping(coordf_t clipping)
|
|
||||||
%code{% THIS->fill->loop_clipping = clipping; %};
|
|
||||||
|
|
||||||
bool use_bridge_flow()
|
|
||||||
%code{% RETVAL = THIS->fill->use_bridge_flow(); %};
|
|
||||||
bool no_sort()
|
|
||||||
%code{% RETVAL = THIS->fill->no_sort(); %};
|
|
||||||
|
|
||||||
void set_density(float density)
|
|
||||||
%code{% THIS->params.density = density; %};
|
|
||||||
void set_dont_adjust(bool dont_adjust)
|
|
||||||
%code{% THIS->params.dont_adjust = dont_adjust; %};
|
|
||||||
|
|
||||||
PolylineCollection* _fill_surface(Surface *surface)
|
|
||||||
%code{%
|
|
||||||
PolylineCollection *pc = NULL;
|
|
||||||
if (THIS->fill != NULL) {
|
|
||||||
pc = new PolylineCollection();
|
|
||||||
pc->polylines = THIS->fill->fill_surface(surface, THIS->params);
|
|
||||||
}
|
|
||||||
RETVAL = pc;
|
|
||||||
%};
|
|
||||||
|
|
||||||
%{
|
|
||||||
|
|
||||||
Filler*
|
|
||||||
new_from_type(CLASS, type)
|
|
||||||
char* CLASS;
|
|
||||||
std::string type;
|
|
||||||
CODE:
|
|
||||||
Filler *filler = new Filler();
|
|
||||||
filler->fill = Fill::new_from_type(type);
|
|
||||||
RETVAL = filler;
|
|
||||||
OUTPUT:
|
|
||||||
RETVAL
|
|
||||||
|
|
||||||
%}
|
|
||||||
|
|
||||||
};
|
|
@ -1,24 +0,0 @@
|
|||||||
%module{Slic3r::XS};
|
|
||||||
|
|
||||||
%{
|
|
||||||
#include <xsinit.h>
|
|
||||||
#include "libslic3r/GCodeSender.hpp"
|
|
||||||
%}
|
|
||||||
|
|
||||||
%name{Slic3r::GCode::Sender} class GCodeSender {
|
|
||||||
GCodeSender();
|
|
||||||
~GCodeSender();
|
|
||||||
|
|
||||||
bool connect(std::string port, unsigned int baud_rate);
|
|
||||||
void disconnect();
|
|
||||||
bool is_connected();
|
|
||||||
bool wait_connected(unsigned int timeout = 3);
|
|
||||||
int queue_size();
|
|
||||||
void send(std::string s, bool priority = false);
|
|
||||||
void pause_queue();
|
|
||||||
void resume_queue();
|
|
||||||
void purge_queue(bool priority = false);
|
|
||||||
std::vector<std::string> purge_log();
|
|
||||||
std::string getT();
|
|
||||||
std::string getB();
|
|
||||||
};
|
|
@ -118,14 +118,6 @@ ExtrusionLoop* O_OBJECT_SLIC3R
|
|||||||
Ref<ExtrusionLoop> O_OBJECT_SLIC3R_T
|
Ref<ExtrusionLoop> O_OBJECT_SLIC3R_T
|
||||||
Clone<ExtrusionLoop> O_OBJECT_SLIC3R_T
|
Clone<ExtrusionLoop> O_OBJECT_SLIC3R_T
|
||||||
|
|
||||||
ExtrusionSimulator* O_OBJECT_SLIC3R
|
|
||||||
Ref<ExtrusionSimulator> O_OBJECT_SLIC3R_T
|
|
||||||
Clone<ExtrusionSimulator> O_OBJECT_SLIC3R_T
|
|
||||||
|
|
||||||
Filler* O_OBJECT_SLIC3R
|
|
||||||
Ref<Filler> O_OBJECT_SLIC3R_T
|
|
||||||
Clone<Filler> O_OBJECT_SLIC3R_T
|
|
||||||
|
|
||||||
Flow* O_OBJECT_SLIC3R
|
Flow* O_OBJECT_SLIC3R
|
||||||
Ref<Flow> O_OBJECT_SLIC3R_T
|
Ref<Flow> O_OBJECT_SLIC3R_T
|
||||||
Clone<Flow> O_OBJECT_SLIC3R_T
|
Clone<Flow> O_OBJECT_SLIC3R_T
|
||||||
|
@ -58,9 +58,6 @@
|
|||||||
%typemap{ExPolygonCollection*};
|
%typemap{ExPolygonCollection*};
|
||||||
%typemap{Ref<ExPolygonCollection>}{simple};
|
%typemap{Ref<ExPolygonCollection>}{simple};
|
||||||
%typemap{Clone<ExPolygonCollection>}{simple};
|
%typemap{Clone<ExPolygonCollection>}{simple};
|
||||||
%typemap{Filler*};
|
|
||||||
%typemap{Ref<Filler>}{simple};
|
|
||||||
%typemap{Clone<Filler>}{simple};
|
|
||||||
%typemap{Flow*};
|
%typemap{Flow*};
|
||||||
%typemap{Ref<Flow>}{simple};
|
%typemap{Ref<Flow>}{simple};
|
||||||
%typemap{Clone<Flow>}{simple};
|
%typemap{Clone<Flow>}{simple};
|
||||||
@ -88,9 +85,6 @@
|
|||||||
%typemap{ExtrusionLoop*};
|
%typemap{ExtrusionLoop*};
|
||||||
%typemap{Ref<ExtrusionLoop>}{simple};
|
%typemap{Ref<ExtrusionLoop>}{simple};
|
||||||
%typemap{Clone<ExtrusionLoop>}{simple};
|
%typemap{Clone<ExtrusionLoop>}{simple};
|
||||||
%typemap{ExtrusionSimulator*};
|
|
||||||
%typemap{Ref<ExtrusionSimulator>}{simple};
|
|
||||||
%typemap{Clone<ExtrusionSimulator>}{simple};
|
|
||||||
%typemap{TriangleMesh*};
|
%typemap{TriangleMesh*};
|
||||||
%typemap{Ref<TriangleMesh>}{simple};
|
%typemap{Ref<TriangleMesh>}{simple};
|
||||||
%typemap{Clone<TriangleMesh>}{simple};
|
%typemap{Clone<TriangleMesh>}{simple};
|
||||||
|
Loading…
Reference in New Issue
Block a user