Ported Infill unit tests from Perl to C++.

This commit is contained in:
Vojtech Bubnik 2022-05-02 14:34:39 +02:00
parent d88e9634f5
commit 33b2478b69
16 changed files with 387 additions and 711 deletions

View File

@ -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) {}

View File

@ -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);

View File

@ -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
View File

@ -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__

View File

@ -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");

View File

@ -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);
}
}
}

View File

@ -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") {
my $collection = Slic3r::Polyline::Collection->new( std::string gcode = Slic3r::Test::slice({ mesh(Slic3r::Test::TestMesh::cube_20x20x20, Vec3d::Zero(), 2.0) }, config);
Slic3r::Polyline->new([4,0], [10,0], [15,0]), THEN("gcode not empty") {
Slic3r::Polyline->new([10,5], [15,5], [20,5]), REQUIRE(! gcode.empty());
);
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('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});
} }
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)
{
// 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 == perimeter_extruder)
perimeter_points.emplace_back(line.new_XY_scaled(self));
else if (tool == infill_extruder)
infill_points.emplace_back(line.new_XY_scaled(self));
} }
}); });
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
THEN("infill not empty") {
REQUIRE(! infill_points.empty());
}
ok !%layers_with_extrusion, auto opt_width = config.opt<ConfigOptionFloatOrPercent>("infill_extrusion_width");
"solid_infill_below_area and solid_infill_every_layers are ignored when fill_density is 0"; 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); WHEN("A is sliced") {
$diff = [ grep { $_->area > 2*(($grow_d*2)**2) } @$diff ]; DynamicPrintConfig config = Slic3r::DynamicPrintConfig::full_print_config();
is scalar(@$diff), 0, 'no missing parts in solid shell when fill_density is 0'; 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)

View File

@ -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

View File

@ -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

View File

@ -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" { */

View File

@ -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");

View File

@ -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
%}

View File

@ -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
%}
};

View File

@ -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();
};

View File

@ -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

View File

@ -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};