Refactored PerimeterGenerator to output out_fill_surfaces as ExPolygons,
not SurfaceCollection. Reworked combineinfill.t, 07_extrusionpath.t, 08_extrusionloop.t to c++. Removed Layer / ExtrusionPath / ExtrusionLoop / ExtrusionEntityCollection from Perl bindings.
This commit is contained in:
parent
237e56c7ce
commit
d041fa6c0c
@ -6,9 +6,4 @@ use warnings;
|
|||||||
use List::Util qw(min max sum first);
|
use List::Util qw(min max sum first);
|
||||||
use Slic3r::Surface ':types';
|
use Slic3r::Surface ':types';
|
||||||
|
|
||||||
sub layers {
|
|
||||||
my $self = shift;
|
|
||||||
return [ map $self->get_layer($_), 0..($self->layer_count - 1) ];
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
@ -426,12 +426,12 @@ void Layer::make_perimeters()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SurfaceCollection fill_surfaces;
|
ExPolygons fill_expolygons;
|
||||||
if (layerms.size() == 1) { // optimization
|
if (layerms.size() == 1) { // optimization
|
||||||
(*layerm)->m_fill_expolygons.clear();
|
(*layerm)->m_fill_expolygons.clear();
|
||||||
(*layerm)->m_fill_surfaces.clear();
|
(*layerm)->m_fill_surfaces.clear();
|
||||||
(*layerm)->make_perimeters((*layerm)->slices(), &fill_surfaces);
|
(*layerm)->make_perimeters((*layerm)->slices(), fill_expolygons);
|
||||||
(*layerm)->m_fill_expolygons = to_expolygons(fill_surfaces.surfaces);
|
(*layerm)->m_fill_expolygons = std::move(fill_expolygons);
|
||||||
} else {
|
} else {
|
||||||
SurfaceCollection new_slices;
|
SurfaceCollection new_slices;
|
||||||
// Use the region with highest infill rate, as the make_perimeters() function below decides on the gap fill based on the infill existence.
|
// Use the region with highest infill rate, as the make_perimeters() function below decides on the gap fill based on the infill existence.
|
||||||
@ -452,12 +452,12 @@ void Layer::make_perimeters()
|
|||||||
new_slices.append(offset_ex(surfaces_with_extra_perimeters.second, ClipperSafetyOffset), surfaces_with_extra_perimeters.second.front());
|
new_slices.append(offset_ex(surfaces_with_extra_perimeters.second, ClipperSafetyOffset), surfaces_with_extra_perimeters.second.front());
|
||||||
}
|
}
|
||||||
// make perimeters
|
// make perimeters
|
||||||
layerm_config->make_perimeters(new_slices, &fill_surfaces);
|
layerm_config->make_perimeters(new_slices, fill_expolygons);
|
||||||
// assign fill_surfaces to each layer
|
// assign fill_surfaces to each layer
|
||||||
if (! fill_surfaces.empty()) {
|
if (! fill_expolygons.empty()) {
|
||||||
// Separate the fill surfaces.
|
// Separate the fill surfaces.
|
||||||
for (LayerRegion *l : layerms)
|
for (LayerRegion *l : layerms)
|
||||||
l->m_fill_expolygons = intersection_ex(fill_surfaces.surfaces, l->slices().surfaces);
|
l->m_fill_expolygons = intersection_ex(l->slices().surfaces, fill_expolygons);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,7 +67,7 @@ public:
|
|||||||
|
|
||||||
void slices_to_fill_surfaces_clipped();
|
void slices_to_fill_surfaces_clipped();
|
||||||
void prepare_fill_surfaces();
|
void prepare_fill_surfaces();
|
||||||
void make_perimeters(const SurfaceCollection &slices, SurfaceCollection* fill_surfaces);
|
void make_perimeters(const SurfaceCollection &slices, ExPolygons &fill_expolygons);
|
||||||
void process_external_surfaces(const Layer *lower_layer, const Polygons *lower_layer_covered);
|
void process_external_surfaces(const Layer *lower_layer, const Polygons *lower_layer_covered);
|
||||||
double infill_area_threshold() const;
|
double infill_area_threshold() const;
|
||||||
// Trim surfaces by trimming polygons. Used by the elephant foot compensation at the 1st layer.
|
// Trim surfaces by trimming polygons. Used by the elephant foot compensation at the 1st layer.
|
||||||
|
@ -59,7 +59,7 @@ void LayerRegion::slices_to_fill_surfaces_clipped()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollection* fill_surfaces)
|
void LayerRegion::make_perimeters(const SurfaceCollection &slices, ExPolygons &fill_expolygons)
|
||||||
{
|
{
|
||||||
m_perimeters.clear();
|
m_perimeters.clear();
|
||||||
m_thin_fills.clear();
|
m_thin_fills.clear();
|
||||||
@ -100,7 +100,7 @@ void LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollec
|
|||||||
// output:
|
// output:
|
||||||
m_perimeters,
|
m_perimeters,
|
||||||
m_thin_fills,
|
m_thin_fills,
|
||||||
*fill_surfaces);
|
fill_expolygons);
|
||||||
else
|
else
|
||||||
PerimeterGenerator::process_classic(
|
PerimeterGenerator::process_classic(
|
||||||
// input:
|
// input:
|
||||||
@ -111,7 +111,7 @@ void LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollec
|
|||||||
// output:
|
// output:
|
||||||
m_perimeters,
|
m_perimeters,
|
||||||
m_thin_fills,
|
m_thin_fills,
|
||||||
*fill_surfaces);
|
fill_expolygons);
|
||||||
}
|
}
|
||||||
|
|
||||||
//#define EXTERNAL_SURFACES_OFFSET_PARAMETERS ClipperLib::jtMiter, 3.
|
//#define EXTERNAL_SURFACES_OFFSET_PARAMETERS ClipperLib::jtMiter, 3.
|
||||||
|
@ -611,7 +611,7 @@ void PerimeterGenerator::process_arachne(
|
|||||||
// Gaps without the thin walls
|
// Gaps without the thin walls
|
||||||
ExtrusionEntityCollection &out_gap_fill,
|
ExtrusionEntityCollection &out_gap_fill,
|
||||||
// Infills without the gap fills
|
// Infills without the gap fills
|
||||||
SurfaceCollection &out_fill_surfaces)
|
ExPolygons &out_fill_expolygons)
|
||||||
{
|
{
|
||||||
// other perimeters
|
// other perimeters
|
||||||
coord_t perimeter_spacing = params.perimeter_flow.scaled_spacing();
|
coord_t perimeter_spacing = params.perimeter_flow.scaled_spacing();
|
||||||
@ -817,12 +817,11 @@ void PerimeterGenerator::process_arachne(
|
|||||||
// collapse too narrow infill areas
|
// collapse too narrow infill areas
|
||||||
const auto min_perimeter_infill_spacing = coord_t(solid_infill_spacing * (1. - INSET_OVERLAP_TOLERANCE));
|
const auto min_perimeter_infill_spacing = coord_t(solid_infill_spacing * (1. - INSET_OVERLAP_TOLERANCE));
|
||||||
// append infill areas to fill_surfaces
|
// append infill areas to fill_surfaces
|
||||||
out_fill_surfaces.append(
|
append(out_fill_expolygons,
|
||||||
offset2_ex(
|
offset2_ex(
|
||||||
union_ex(pp),
|
union_ex(pp),
|
||||||
float(- min_perimeter_infill_spacing / 2.),
|
float(- min_perimeter_infill_spacing / 2.),
|
||||||
float(inset + min_perimeter_infill_spacing / 2.)),
|
float(inset + min_perimeter_infill_spacing / 2.)));
|
||||||
stInternal);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -839,7 +838,7 @@ void PerimeterGenerator::process_classic(
|
|||||||
// Gaps without the thin walls
|
// Gaps without the thin walls
|
||||||
ExtrusionEntityCollection &out_gap_fill,
|
ExtrusionEntityCollection &out_gap_fill,
|
||||||
// Infills without the gap fills
|
// Infills without the gap fills
|
||||||
SurfaceCollection &out_fill_surfaces)
|
ExPolygons &out_fill_expolygons)
|
||||||
{
|
{
|
||||||
// other perimeters
|
// other perimeters
|
||||||
coord_t perimeter_width = params.perimeter_flow.scaled_width();
|
coord_t perimeter_width = params.perimeter_flow.scaled_width();
|
||||||
@ -1094,12 +1093,11 @@ void PerimeterGenerator::process_classic(
|
|||||||
// collapse too narrow infill areas
|
// collapse too narrow infill areas
|
||||||
coord_t min_perimeter_infill_spacing = coord_t(solid_infill_spacing * (1. - INSET_OVERLAP_TOLERANCE));
|
coord_t min_perimeter_infill_spacing = coord_t(solid_infill_spacing * (1. - INSET_OVERLAP_TOLERANCE));
|
||||||
// append infill areas to fill_surfaces
|
// append infill areas to fill_surfaces
|
||||||
out_fill_surfaces.append(
|
append(out_fill_expolygons,
|
||||||
offset2_ex(
|
offset2_ex(
|
||||||
union_ex(pp),
|
union_ex(pp),
|
||||||
float(- inset - min_perimeter_infill_spacing / 2.),
|
float(- inset - min_perimeter_infill_spacing / 2.),
|
||||||
float(min_perimeter_infill_spacing / 2.)),
|
float(min_perimeter_infill_spacing / 2.)));
|
||||||
stInternal);
|
|
||||||
} // for each island
|
} // for each island
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@ void process_classic(
|
|||||||
// Gaps without the thin walls
|
// Gaps without the thin walls
|
||||||
ExtrusionEntityCollection &out_gap_fill,
|
ExtrusionEntityCollection &out_gap_fill,
|
||||||
// Infills without the gap fills
|
// Infills without the gap fills
|
||||||
SurfaceCollection &out_fill_surfaces);
|
ExPolygons &out_fill_expolygons);
|
||||||
|
|
||||||
void process_arachne(
|
void process_arachne(
|
||||||
// Inputs:
|
// Inputs:
|
||||||
@ -92,7 +92,7 @@ void process_arachne(
|
|||||||
// Gaps without the thin walls
|
// Gaps without the thin walls
|
||||||
ExtrusionEntityCollection &out_gap_fill,
|
ExtrusionEntityCollection &out_gap_fill,
|
||||||
// Infills without the gap fills
|
// Infills without the gap fills
|
||||||
SurfaceCollection &out_fill_surfaces);
|
ExPolygons &out_fill_expolygons);
|
||||||
|
|
||||||
ExtrusionMultiPath thick_polyline_to_multi_path(const ThickPolyline &thick_polyline, ExtrusionRole role, const Flow &flow, float tolerance, float merge_tolerance);
|
ExtrusionMultiPath thick_polyline_to_multi_path(const ThickPolyline &thick_polyline, ExtrusionRole role, const Flow &flow, float tolerance, float merge_tolerance);
|
||||||
|
|
||||||
|
@ -32,12 +32,13 @@
|
|||||||
#include "Technologies.hpp"
|
#include "Technologies.hpp"
|
||||||
#include "Semver.hpp"
|
#include "Semver.hpp"
|
||||||
|
|
||||||
|
using coord_t =
|
||||||
#if 1
|
#if 1
|
||||||
// Saves around 32% RAM after slicing step, 6.7% after G-code export (tested on PrusaSlicer 2.2.0 final).
|
// Saves around 32% RAM after slicing step, 6.7% after G-code export (tested on PrusaSlicer 2.2.0 final).
|
||||||
using coord_t = int32_t;
|
int32_t;
|
||||||
#else
|
#else
|
||||||
//FIXME At least FillRectilinear2 and std::boost Voronoi require coord_t to be 32bit.
|
//FIXME At least FillRectilinear2 and std::boost Voronoi require coord_t to be 32bit.
|
||||||
typedef int64_t coord_t;
|
int64_t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using coordf_t = double;
|
using coordf_t = double;
|
||||||
@ -366,4 +367,4 @@ inline IntegerOnly<I, I> fast_round_up(double a)
|
|||||||
|
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
|
||||||
#endif
|
#endif // _libslic3r_h_
|
||||||
|
@ -1,110 +0,0 @@
|
|||||||
use Test::More;
|
|
||||||
use strict;
|
|
||||||
use warnings;
|
|
||||||
|
|
||||||
BEGIN {
|
|
||||||
use FindBin;
|
|
||||||
use lib "$FindBin::Bin/../lib";
|
|
||||||
use local::lib "$FindBin::Bin/../local-lib";
|
|
||||||
}
|
|
||||||
|
|
||||||
use List::Util qw(first);
|
|
||||||
use Slic3r;
|
|
||||||
use Slic3r::Surface ':types';
|
|
||||||
use Slic3r::Test;
|
|
||||||
|
|
||||||
plan tests => 8;
|
|
||||||
|
|
||||||
{
|
|
||||||
my $test = sub {
|
|
||||||
my ($config) = @_;
|
|
||||||
|
|
||||||
my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
|
|
||||||
ok my $gcode = Slic3r::Test::gcode($print), "infill_every_layers does not crash";
|
|
||||||
|
|
||||||
my $tool = undef;
|
|
||||||
my %layers = (); # layer_z => 1
|
|
||||||
my %layer_infill = (); # layer_z => has_infill
|
|
||||||
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 && $tool != $config->support_material_extruder-1) {
|
|
||||||
$layer_infill{$self->Z} //= 0;
|
|
||||||
if ($tool == $config->infill_extruder-1) {
|
|
||||||
$layer_infill{$self->Z} = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
# Previously, all G-code commands had a fixed number of decimal points with means with redundant zeros after decimal points.
|
|
||||||
# We changed this behavior and got rid of these redundant padding zeros, which caused this test to fail
|
|
||||||
# because the position in Z-axis is compared as a string, and previously, G-code contained the following two commands:
|
|
||||||
# "G1 Z5 F5000 ; lift nozzle"
|
|
||||||
# "G1 Z5.000 F7800.000"
|
|
||||||
# That has a different Z-axis position from the view of string comparisons of floating-point numbers.
|
|
||||||
# To correct the computation of the number of printed layers, even in the case of string comparisons of floating-point numbers,
|
|
||||||
# we filtered out the G-code command with the commend 'lift nozzle'.
|
|
||||||
$layers{$args->{Z}} = 1 if $cmd eq 'G1' && $info->{dist_Z} && index($info->{comment}, 'lift nozzle') == -1;
|
|
||||||
});
|
|
||||||
|
|
||||||
my $layers_with_perimeters = scalar(keys %layer_infill);
|
|
||||||
my $layers_with_infill = grep $_ > 0, values %layer_infill;
|
|
||||||
is scalar(keys %layers), $layers_with_perimeters+$config->raft_layers, 'expected number of layers';
|
|
||||||
|
|
||||||
if ($config->raft_layers == 0) {
|
|
||||||
# first infill layer printed directly on print bed is not combined, so we don't consider it.
|
|
||||||
$layers_with_infill--;
|
|
||||||
$layers_with_perimeters--;
|
|
||||||
}
|
|
||||||
|
|
||||||
# we expect that infill is generated for half the number of combined layers
|
|
||||||
# plus for each single layer that was not combined (remainder)
|
|
||||||
is $layers_with_infill,
|
|
||||||
int($layers_with_perimeters/$config->infill_every_layers) + ($layers_with_perimeters % $config->infill_every_layers),
|
|
||||||
'infill is only present in correct number of layers';
|
|
||||||
};
|
|
||||||
|
|
||||||
my $config = Slic3r::Config::new_from_defaults;
|
|
||||||
$config->set('layer_height', 0.2);
|
|
||||||
$config->set('first_layer_height', 0.2);
|
|
||||||
$config->set('nozzle_diameter', [0.5,0.5,0.5,0.5]);
|
|
||||||
$config->set('infill_every_layers', 2);
|
|
||||||
$config->set('perimeter_extruder', 1);
|
|
||||||
$config->set('infill_extruder', 2);
|
|
||||||
$config->set('wipe_into_infill', 0);
|
|
||||||
$config->set('support_material_extruder', 3);
|
|
||||||
$config->set('support_material_interface_extruder', 3);
|
|
||||||
$config->set('top_solid_layers', 0);
|
|
||||||
$config->set('bottom_solid_layers', 0);
|
|
||||||
$test->($config);
|
|
||||||
|
|
||||||
$config->set('skirts', 0); # prevent usage of perimeter_extruder in raft layers
|
|
||||||
$config->set('raft_layers', 5);
|
|
||||||
$test->($config);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
my $config = Slic3r::Config::new_from_defaults;
|
|
||||||
$config->set('layer_height', 0.2);
|
|
||||||
$config->set('first_layer_height', 0.2);
|
|
||||||
$config->set('nozzle_diameter', [0.5]);
|
|
||||||
$config->set('infill_every_layers', 2);
|
|
||||||
|
|
||||||
my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
|
|
||||||
$print->process;
|
|
||||||
|
|
||||||
ok defined(first { @{$_->get_region(0)->fill_surfaces->filter_by_type(S_TYPE_INTERNALVOID)} > 0 }
|
|
||||||
@{$print->print->get_object(0)->layers}),
|
|
||||||
'infill combination produces internal void surfaces';
|
|
||||||
|
|
||||||
# we disable combination after infill has been generated
|
|
||||||
$config->set('infill_every_layers', 1);
|
|
||||||
$print->apply($print->print->model->clone, $config);
|
|
||||||
$print->process;
|
|
||||||
|
|
||||||
ok !(defined first { @{$_->get_region(0)->fill_surfaces} == 0 }
|
|
||||||
@{$print->print->get_object(0)->layers}),
|
|
||||||
'infill combination is idempotent';
|
|
||||||
}
|
|
||||||
|
|
||||||
__END__
|
|
@ -35,7 +35,254 @@ static Slic3r::ExtrusionPaths random_paths(size_t count = 10, size_t length = 20
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
SCENARIO("ExtrusionEntityCollection: Polygon flattening", "[ExtrusionEntity]") {
|
SCENARIO("ExtrusionPath", "[ExtrusionEntity]") {
|
||||||
|
GIVEN("Simple path") {
|
||||||
|
Slic3r::ExtrusionPath path{ erExternalPerimeter };
|
||||||
|
path.polyline = { { 100, 100 }, { 200, 100 }, { 200, 200 } };
|
||||||
|
path.mm3_per_mm = 1.;
|
||||||
|
THEN("first point") {
|
||||||
|
REQUIRE(path.first_point() == path.polyline.front());
|
||||||
|
}
|
||||||
|
THEN("cloned") {
|
||||||
|
auto cloned = std::unique_ptr<ExtrusionEntity>(path.clone());
|
||||||
|
REQUIRE(cloned->role() == path.role());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static ExtrusionPath new_extrusion_path(const Polyline &polyline, ExtrusionRole role, double mm3_per_mm)
|
||||||
|
{
|
||||||
|
ExtrusionPath path(role);
|
||||||
|
path.polyline = polyline;
|
||||||
|
path.mm3_per_mm = 1.;
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
SCENARIO("ExtrusionLoop", "[ExtrusionEntity]")
|
||||||
|
{
|
||||||
|
GIVEN("Square") {
|
||||||
|
Polygon square { { 100, 100 }, { 200, 100 }, { 200, 200 }, { 100, 200 } };
|
||||||
|
|
||||||
|
ExtrusionLoop loop;
|
||||||
|
loop.paths.emplace_back(new_extrusion_path(square.split_at_first_point(), erExternalPerimeter, 1.));
|
||||||
|
THEN("polygon area") {
|
||||||
|
REQUIRE(loop.polygon().area() == Approx(square.area()));
|
||||||
|
}
|
||||||
|
THEN("loop length") {
|
||||||
|
REQUIRE(loop.length() == Approx(square.length()));
|
||||||
|
}
|
||||||
|
|
||||||
|
WHEN("cloned") {
|
||||||
|
auto loop2 = std::unique_ptr<ExtrusionLoop>(dynamic_cast<ExtrusionLoop*>(loop.clone()));
|
||||||
|
THEN("cloning worked") {
|
||||||
|
REQUIRE(loop2 != nullptr);
|
||||||
|
}
|
||||||
|
THEN("loop contains one path") {
|
||||||
|
REQUIRE(loop2->paths.size() == 1);
|
||||||
|
}
|
||||||
|
THEN("cloned role") {
|
||||||
|
REQUIRE(loop2->paths.front().role() == erExternalPerimeter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
WHEN("cloned and split") {
|
||||||
|
auto loop2 = std::unique_ptr<ExtrusionLoop>(dynamic_cast<ExtrusionLoop*>(loop.clone()));
|
||||||
|
loop2->split_at_vertex(square.points[2]);
|
||||||
|
THEN("splitting a single-path loop results in a single path") {
|
||||||
|
REQUIRE(loop2->paths.size() == 1);
|
||||||
|
}
|
||||||
|
THEN("path has correct number of points") {
|
||||||
|
REQUIRE(loop2->paths.front().size() == 5);
|
||||||
|
}
|
||||||
|
THEN("expected point order") {
|
||||||
|
REQUIRE(loop2->paths.front().polyline[0] == square.points[2]);
|
||||||
|
REQUIRE(loop2->paths.front().polyline[1] == square.points[3]);
|
||||||
|
REQUIRE(loop2->paths.front().polyline[2] == square.points[0]);
|
||||||
|
REQUIRE(loop2->paths.front().polyline[3] == square.points[1]);
|
||||||
|
REQUIRE(loop2->paths.front().polyline[4] == square.points[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GIVEN("Loop with two pieces") {
|
||||||
|
Polyline polyline1 { { 100, 100 }, { 200, 100 }, { 200, 200 } };
|
||||||
|
Polyline polyline2 { { 200, 200 }, { 100, 200 }, { 100, 100 } };
|
||||||
|
ExtrusionLoop loop;
|
||||||
|
loop.paths.emplace_back(new_extrusion_path(polyline1, erExternalPerimeter, 1.));
|
||||||
|
loop.paths.emplace_back(new_extrusion_path(polyline2, erOverhangPerimeter, 1.));
|
||||||
|
|
||||||
|
double tot_len = polyline1.length() + polyline2.length();
|
||||||
|
THEN("length") {
|
||||||
|
REQUIRE(loop.length() == Approx(tot_len));
|
||||||
|
}
|
||||||
|
|
||||||
|
WHEN("splitting at intermediate point") {
|
||||||
|
auto loop2 = std::unique_ptr<ExtrusionLoop>(dynamic_cast<ExtrusionLoop*>(loop.clone()));
|
||||||
|
loop2->split_at_vertex(polyline1.points[1]);
|
||||||
|
THEN("length after splitting is unchanged") {
|
||||||
|
REQUIRE(loop2->length() == Approx(tot_len));
|
||||||
|
}
|
||||||
|
THEN("loop contains three paths after splitting") {
|
||||||
|
REQUIRE(loop2->paths.size() == 3);
|
||||||
|
}
|
||||||
|
THEN("expected starting point") {
|
||||||
|
REQUIRE(loop2->paths.front().polyline.front() == polyline1.points[1]);
|
||||||
|
}
|
||||||
|
THEN("expected ending point") {
|
||||||
|
REQUIRE(loop2->paths.back().polyline.back() == polyline1.points[1]);
|
||||||
|
}
|
||||||
|
THEN("paths have common point") {
|
||||||
|
REQUIRE(loop2->paths.front().polyline.back() == loop2->paths[1].polyline.front());
|
||||||
|
REQUIRE(loop2->paths[1].polyline.back() == loop2->paths[2].polyline.front());
|
||||||
|
}
|
||||||
|
THEN("expected order after splitting") {
|
||||||
|
REQUIRE(loop2->paths.front().role() == erExternalPerimeter);
|
||||||
|
REQUIRE(loop2->paths[1].role() == erOverhangPerimeter);
|
||||||
|
REQUIRE(loop2->paths[2].role() == erExternalPerimeter);
|
||||||
|
}
|
||||||
|
THEN("path has correct number of points") {
|
||||||
|
REQUIRE(loop2->paths.front().polyline.size() == 2);
|
||||||
|
REQUIRE(loop2->paths[1].polyline.size() == 3);
|
||||||
|
REQUIRE(loop2->paths[2].polyline.size() == 2);
|
||||||
|
}
|
||||||
|
THEN("clipped path has expected length") {
|
||||||
|
double l = loop2->length();
|
||||||
|
ExtrusionPaths paths;
|
||||||
|
loop2->clip_end(3, &paths);
|
||||||
|
double l2 = 0;
|
||||||
|
for (const ExtrusionPath &p : paths)
|
||||||
|
l2 += p.length();
|
||||||
|
REQUIRE(l2 == Approx(l - 3.));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WHEN("splitting at endpoint") {
|
||||||
|
auto loop2 = std::unique_ptr<ExtrusionLoop>(dynamic_cast<ExtrusionLoop*>(loop.clone()));
|
||||||
|
loop2->split_at_vertex(polyline2.points.front());
|
||||||
|
THEN("length after splitting is unchanged") {
|
||||||
|
REQUIRE(loop2->length() == Approx(tot_len));
|
||||||
|
}
|
||||||
|
THEN("loop contains two paths after splitting") {
|
||||||
|
REQUIRE(loop2->paths.size() == 2);
|
||||||
|
}
|
||||||
|
THEN("expected starting point") {
|
||||||
|
REQUIRE(loop2->paths.front().polyline.front() == polyline2.points.front());
|
||||||
|
}
|
||||||
|
THEN("expected ending point") {
|
||||||
|
REQUIRE(loop2->paths.back().polyline.back() == polyline2.points.front());
|
||||||
|
}
|
||||||
|
THEN("paths have common point") {
|
||||||
|
REQUIRE(loop2->paths.front().polyline.back() == loop2->paths[1].polyline.front());
|
||||||
|
REQUIRE(loop2->paths[1].polyline.back() == loop2->paths.front().polyline.front());
|
||||||
|
}
|
||||||
|
THEN("expected order after splitting") {
|
||||||
|
REQUIRE(loop2->paths.front().role() == erOverhangPerimeter);
|
||||||
|
REQUIRE(loop2->paths[1].role() == erExternalPerimeter);
|
||||||
|
}
|
||||||
|
THEN("path has correct number of points") {
|
||||||
|
REQUIRE(loop2->paths.front().polyline.size() == 3);
|
||||||
|
REQUIRE(loop2->paths[1].polyline.size() == 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WHEN("splitting at an edge") {
|
||||||
|
Point point(250, 150);
|
||||||
|
auto loop2 = std::unique_ptr<ExtrusionLoop>(dynamic_cast<ExtrusionLoop*>(loop.clone()));
|
||||||
|
loop2->split_at(point, false, 0);
|
||||||
|
THEN("length after splitting is unchanged") {
|
||||||
|
REQUIRE(loop2->length() == Approx(tot_len));
|
||||||
|
}
|
||||||
|
Point expected_start_point(200, 150);
|
||||||
|
THEN("expected starting point") {
|
||||||
|
REQUIRE(loop2->paths.front().polyline.front() == expected_start_point);
|
||||||
|
}
|
||||||
|
THEN("expected ending point") {
|
||||||
|
REQUIRE(loop2->paths.back().polyline.back() == expected_start_point);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GIVEN("Loop with four pieces") {
|
||||||
|
Polyline polyline1 { { 59312736, 4821067 }, { 64321068, 4821067 }, { 64321068, 4821067 }, { 64321068, 9321068 }, { 59312736, 9321068 } };
|
||||||
|
Polyline polyline2 { { 59312736, 9321068 }, { 9829401, 9321068 } };
|
||||||
|
Polyline polyline3 { { 9829401, 9321068 }, { 4821067, 9321068 }, { 4821067, 4821067 }, { 9829401, 4821067 } };
|
||||||
|
Polyline polyline4 { { 9829401, 4821067 }, { 59312736,4821067 } };
|
||||||
|
ExtrusionLoop loop;
|
||||||
|
loop.paths.emplace_back(new_extrusion_path(polyline1, erExternalPerimeter, 1.));
|
||||||
|
loop.paths.emplace_back(new_extrusion_path(polyline2, erOverhangPerimeter, 1.));
|
||||||
|
loop.paths.emplace_back(new_extrusion_path(polyline3, erExternalPerimeter, 1.));
|
||||||
|
loop.paths.emplace_back(new_extrusion_path(polyline4, erOverhangPerimeter, 1.));
|
||||||
|
double len = loop.length();
|
||||||
|
WHEN("splitting at vertex") {
|
||||||
|
Point point(4821067, 9321068);
|
||||||
|
if (! loop.split_at_vertex(point))
|
||||||
|
loop.split_at(point, false, 0);
|
||||||
|
THEN("total length is preserved after splitting") {
|
||||||
|
REQUIRE(loop.length() == Approx(len));
|
||||||
|
}
|
||||||
|
THEN("order is correctly preserved after splitting") {
|
||||||
|
REQUIRE(loop.paths.front().role() == erExternalPerimeter);
|
||||||
|
REQUIRE(loop.paths[1].role() == erOverhangPerimeter);
|
||||||
|
REQUIRE(loop.paths[2].role() == erExternalPerimeter);
|
||||||
|
REQUIRE(loop.paths[3].role() == erOverhangPerimeter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GIVEN("Some complex loop") {
|
||||||
|
ExtrusionLoop loop;
|
||||||
|
loop.paths.emplace_back(new_extrusion_path(
|
||||||
|
Polyline { { 15896783, 15868739 }, { 24842049, 12117558 }, { 33853238, 15801279 }, { 37591780, 24780128 }, { 37591780, 24844970 },
|
||||||
|
{ 33853231, 33825297 }, { 24842049, 37509013 }, { 15896798, 33757841 }, { 12211841, 24812544 }, { 15896783, 15868739 } },
|
||||||
|
erExternalPerimeter, 1.));
|
||||||
|
double len = loop.length();
|
||||||
|
THEN("split_at() preserves total length") {
|
||||||
|
loop.split_at({ 15896783, 15868739 }, false, 0);
|
||||||
|
REQUIRE(loop.length() == Approx(len));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SCENARIO("ExtrusionEntityCollection: Basics", "[ExtrusionEntity]")
|
||||||
|
{
|
||||||
|
Polyline polyline { { 100, 100 }, { 200, 100 }, { 200, 200 } };
|
||||||
|
ExtrusionPath path = new_extrusion_path(polyline, erExternalPerimeter, 1.);
|
||||||
|
ExtrusionLoop loop;
|
||||||
|
loop.paths.emplace_back(new_extrusion_path(Polygon(polyline.points).split_at_first_point(), erInternalInfill, 1.));
|
||||||
|
ExtrusionEntityCollection collection;
|
||||||
|
collection.append(path);
|
||||||
|
THEN("no_sort is false by default") {
|
||||||
|
REQUIRE(! collection.no_sort);
|
||||||
|
}
|
||||||
|
collection.append(collection);
|
||||||
|
THEN("append ExtrusionEntityCollection") {
|
||||||
|
REQUIRE(collection.entities.size() == 2);
|
||||||
|
}
|
||||||
|
collection.append(path);
|
||||||
|
THEN("append ExtrusionPath") {
|
||||||
|
REQUIRE(collection.entities.size() == 3);
|
||||||
|
}
|
||||||
|
collection.append(loop);
|
||||||
|
THEN("append ExtrusionLoop") {
|
||||||
|
REQUIRE(collection.entities.size() == 4);
|
||||||
|
}
|
||||||
|
THEN("appended collection was duplicated") {
|
||||||
|
REQUIRE(dynamic_cast<ExtrusionEntityCollection*>(collection.entities[1])->entities.size() == 1);
|
||||||
|
}
|
||||||
|
WHEN("cloned") {
|
||||||
|
auto coll2 = std::unique_ptr<ExtrusionEntityCollection>(dynamic_cast<ExtrusionEntityCollection*>(collection.clone()));
|
||||||
|
THEN("expected no_sort value") {
|
||||||
|
assert(! coll2->no_sort);
|
||||||
|
}
|
||||||
|
coll2->no_sort = true;
|
||||||
|
THEN("no_sort is kept after clone") {
|
||||||
|
auto coll3 = std::unique_ptr<ExtrusionEntityCollection>(dynamic_cast<ExtrusionEntityCollection*>(coll2->clone()));
|
||||||
|
assert(coll3->no_sort);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SCENARIO("ExtrusionEntityCollection: Polygon flattening", "[ExtrusionEntity]")
|
||||||
|
{
|
||||||
srand(0xDEADBEEF); // consistent seed for test reproducibility.
|
srand(0xDEADBEEF); // consistent seed for test reproducibility.
|
||||||
|
|
||||||
// Generate one specific random path set and save it for later comparison
|
// Generate one specific random path set and save it for later comparison
|
||||||
@ -101,7 +348,7 @@ TEST_CASE("ExtrusionEntityCollection: Chained path", "[ExtrusionEntity]") {
|
|||||||
{ {0,20}, {0,18}, {0,15} },
|
{ {0,20}, {0,18}, {0,15} },
|
||||||
{ {0,10}, {0,8}, {0,5} }
|
{ {0,10}, {0,8}, {0,5} }
|
||||||
},
|
},
|
||||||
{ 0,30 }
|
{ 0, 30 }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
@ -112,7 +359,7 @@ TEST_CASE("ExtrusionEntityCollection: Chained path", "[ExtrusionEntity]") {
|
|||||||
{ {20,5}, {15,5}, {10,5} },
|
{ {20,5}, {15,5}, {10,5} },
|
||||||
{ {15,0}, {10,0}, {4,0} }
|
{ {15,0}, {10,0}, {4,0} }
|
||||||
},
|
},
|
||||||
{ 30,0 }
|
{ 30, 0 }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
@ -123,7 +370,7 @@ TEST_CASE("ExtrusionEntityCollection: Chained path", "[ExtrusionEntity]") {
|
|||||||
{ {20,5}, {15,5}, {10,5} },
|
{ {20,5}, {15,5}, {10,5} },
|
||||||
{ {15,0}, {10,0}, {4,0} }
|
{ {15,0}, {10,0}, {4,0} }
|
||||||
},
|
},
|
||||||
{ 30,0 }
|
{ 30, 0 }
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
for (const Test &test : tests) {
|
for (const Test &test : tests) {
|
||||||
@ -132,12 +379,24 @@ TEST_CASE("ExtrusionEntityCollection: Chained path", "[ExtrusionEntity]") {
|
|||||||
ExtrusionEntityCollection unchained_extrusions;
|
ExtrusionEntityCollection unchained_extrusions;
|
||||||
extrusion_entities_append_paths(unchained_extrusions.entities, test.unchained,
|
extrusion_entities_append_paths(unchained_extrusions.entities, test.unchained,
|
||||||
erInternalInfill, 0., 0.4f, 0.3f);
|
erInternalInfill, 0., 0.4f, 0.3f);
|
||||||
ExtrusionEntityCollection chained_extrusions = unchained_extrusions.chained_path_from(test.initial_point);
|
THEN("Chaining works") {
|
||||||
REQUIRE(chained_extrusions.entities.size() == test.chained.size());
|
ExtrusionEntityCollection chained_extrusions = unchained_extrusions.chained_path_from(test.initial_point);
|
||||||
for (size_t i = 0; i < chained_extrusions.entities.size(); ++ i) {
|
REQUIRE(chained_extrusions.entities.size() == test.chained.size());
|
||||||
const Points &p1 = test.chained[i].points;
|
for (size_t i = 0; i < chained_extrusions.entities.size(); ++ i) {
|
||||||
const Points &p2 = dynamic_cast<const ExtrusionPath*>(chained_extrusions.entities[i])->polyline.points;
|
const Points &p1 = test.chained[i].points;
|
||||||
REQUIRE(p1 == p2);
|
const Points &p2 = dynamic_cast<const ExtrusionPath*>(chained_extrusions.entities[i])->polyline.points;
|
||||||
|
REQUIRE(p1 == p2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
THEN("Chaining produces no change with no_sort") {
|
||||||
|
unchained_extrusions.no_sort = true;
|
||||||
|
ExtrusionEntityCollection chained_extrusions = unchained_extrusions.chained_path_from(test.initial_point);
|
||||||
|
REQUIRE(chained_extrusions.entities.size() == test.unchained.size());
|
||||||
|
for (size_t i = 0; i < chained_extrusions.entities.size(); ++ i) {
|
||||||
|
const Points &p1 = test.unchained[i].points;
|
||||||
|
const Points &p2 = dynamic_cast<const ExtrusionPath*>(chained_extrusions.entities[i])->polyline.points;
|
||||||
|
REQUIRE(p1 == p2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,14 +3,17 @@
|
|||||||
#include <numeric>
|
#include <numeric>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
|
#include "libslic3r/libslic3r.h"
|
||||||
|
|
||||||
#include "libslic3r/ClipperUtils.hpp"
|
#include "libslic3r/ClipperUtils.hpp"
|
||||||
#include "libslic3r/Fill/Fill.hpp"
|
#include "libslic3r/Fill/Fill.hpp"
|
||||||
#include "libslic3r/Flow.hpp"
|
#include "libslic3r/Flow.hpp"
|
||||||
|
#include "libslic3r/Layer.hpp"
|
||||||
#include "libslic3r/Geometry.hpp"
|
#include "libslic3r/Geometry.hpp"
|
||||||
#include "libslic3r/Geometry/ConvexHull.hpp"
|
#include "libslic3r/Geometry/ConvexHull.hpp"
|
||||||
|
#include "libslic3r/Point.hpp"
|
||||||
#include "libslic3r/Print.hpp"
|
#include "libslic3r/Print.hpp"
|
||||||
#include "libslic3r/SVG.hpp"
|
#include "libslic3r/SVG.hpp"
|
||||||
#include "libslic3r/libslic3r.h"
|
|
||||||
|
|
||||||
#include "test_data.hpp"
|
#include "test_data.hpp"
|
||||||
|
|
||||||
@ -329,6 +332,130 @@ SCENARIO("Infill only where needed", "[Fill]")
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SCENARIO("Combine infill", "[Fill]")
|
||||||
|
{
|
||||||
|
{
|
||||||
|
auto test = [](const DynamicPrintConfig &config) {
|
||||||
|
std::string gcode = Test::slice({ Test::TestMesh::cube_20x20x20 }, config);
|
||||||
|
THEN("infill_every_layers does not crash") {
|
||||||
|
REQUIRE(! gcode.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
Slic3r::GCodeReader parser;
|
||||||
|
int tool = -1;
|
||||||
|
std::set<coord_t> layers; // layer_z => 1
|
||||||
|
std::map<coord_t, bool> layer_infill; // layer_z => has_infill
|
||||||
|
const int infill_extruder = config.opt_int("infill_extruder");
|
||||||
|
const int support_material_extruder = config.opt_int("support_material_extruder");
|
||||||
|
parser.parse_buffer(gcode,
|
||||||
|
[&tool, &layers, &layer_infill, infill_extruder, support_material_extruder](Slic3r::GCodeReader &self, const Slic3r::GCodeReader::GCodeLine &line)
|
||||||
|
{
|
||||||
|
coord_t z = line.new_Z(self) / SCALING_FACTOR;
|
||||||
|
if (boost::starts_with(line.cmd(), "T")) {
|
||||||
|
tool = atoi(line.cmd().data() + 1);
|
||||||
|
} else if (line.cmd_is("G1") && line.extruding(self) && line.dist_XY(self) > 0 && tool + 1 != support_material_extruder) {
|
||||||
|
if (tool + 1 == infill_extruder)
|
||||||
|
layer_infill[z] = true;
|
||||||
|
else if (auto it = layer_infill.find(z); it == layer_infill.end())
|
||||||
|
layer_infill.insert(it, std::make_pair(z, false));
|
||||||
|
}
|
||||||
|
// Previously, all G-code commands had a fixed number of decimal points with means with redundant zeros after decimal points.
|
||||||
|
// We changed this behavior and got rid of these redundant padding zeros, which caused this test to fail
|
||||||
|
// because the position in Z-axis is compared as a string, and previously, G-code contained the following two commands:
|
||||||
|
// "G1 Z5 F5000 ; lift nozzle"
|
||||||
|
// "G1 Z5.000 F7800.000"
|
||||||
|
// That has a different Z-axis position from the view of string comparisons of floating-point numbers.
|
||||||
|
// To correct the computation of the number of printed layers, even in the case of string comparisons of floating-point numbers,
|
||||||
|
// we filtered out the G-code command with the commend 'lift nozzle'.
|
||||||
|
if (line.cmd_is("G1") && line.dist_Z(self) != 0 && line.comment().find("lift nozzle") == std::string::npos)
|
||||||
|
layers.insert(z);
|
||||||
|
});
|
||||||
|
|
||||||
|
auto layers_with_perimeters = int(layer_infill.size());
|
||||||
|
auto layers_with_infill = int(std::count_if(layer_infill.begin(), layer_infill.end(), [](auto &v){ return v.second; }));
|
||||||
|
THEN("expected number of layers") {
|
||||||
|
REQUIRE(layers.size() == layers_with_perimeters + config.opt_int("raft_layers"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.opt_int("raft_layers") == 0) {
|
||||||
|
// first infill layer printed directly on print bed is not combined, so we don't consider it.
|
||||||
|
-- layers_with_infill;
|
||||||
|
-- layers_with_perimeters;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we expect that infill is generated for half the number of combined layers
|
||||||
|
// plus for each single layer that was not combined (remainder)
|
||||||
|
THEN("infill is only present in correct number of layers") {
|
||||||
|
int infill_every = config.opt_int("infill_every_layers");
|
||||||
|
REQUIRE(layers_with_infill == int(layers_with_perimeters / infill_every) + (layers_with_perimeters % infill_every));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
auto config = Slic3r::DynamicPrintConfig::full_print_config_with({
|
||||||
|
{ "nozzle_diameter", "0.5, 0.5, 0.5, 0.5" },
|
||||||
|
{ "layer_height", 0.2 },
|
||||||
|
{ "first_layer_height", 0.2 },
|
||||||
|
{ "infill_every_layers", 2 },
|
||||||
|
{ "perimeter_extruder", 1 },
|
||||||
|
{ "infill_extruder", 2 },
|
||||||
|
{ "wipe_into_infill", false },
|
||||||
|
{ "support_material_extruder", 3 },
|
||||||
|
{ "support_material_interface_extruder", 3 },
|
||||||
|
{ "top_solid_layers", 0 },
|
||||||
|
{ "bottom_solid_layers", 0 }
|
||||||
|
});
|
||||||
|
|
||||||
|
test(config);
|
||||||
|
|
||||||
|
// Reuse the config above
|
||||||
|
config.set_deserialize_strict({
|
||||||
|
{ "skirts", 0 }, // prevent usage of perimeter_extruder in raft layers
|
||||||
|
{ "raft_layers", 5 }
|
||||||
|
});
|
||||||
|
test(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
WHEN("infill_every_layers == 2") {
|
||||||
|
Slic3r::Print print;
|
||||||
|
Slic3r::Test::init_and_process_print({ Test::TestMesh::cube_20x20x20 }, print, {
|
||||||
|
{ "nozzle_diameter", "0.5" },
|
||||||
|
{ "layer_height", 0.2 },
|
||||||
|
{ "first_layer_height", 0.2 },
|
||||||
|
{ "infill_every_layers", 2 }
|
||||||
|
});
|
||||||
|
THEN("infill combination produces internal void surfaces") {
|
||||||
|
bool has_void = false;
|
||||||
|
for (const Layer *layer : print.get_object(0)->layers())
|
||||||
|
if (layer->get_region(0)->fill_surfaces().filter_by_type(stInternalVoid).size() > 0) {
|
||||||
|
has_void = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
REQUIRE(has_void);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WHEN("infill_every_layers disabled") {
|
||||||
|
// we disable combination after infill has been generated
|
||||||
|
Slic3r::Print print;
|
||||||
|
Slic3r::Test::init_and_process_print({ Test::TestMesh::cube_20x20x20 }, print, {
|
||||||
|
{ "nozzle_diameter", "0.5" },
|
||||||
|
{ "layer_height", 0.2 },
|
||||||
|
{ "first_layer_height", 0.2 },
|
||||||
|
{ "infill_every_layers", 1 }
|
||||||
|
});
|
||||||
|
|
||||||
|
THEN("infill combination is idempotent") {
|
||||||
|
bool has_infill_on_each_layer = true;
|
||||||
|
for (const Layer *layer : print.get_object(0)->layers())
|
||||||
|
if (layer->get_region(0)->fill_surfaces().empty()) {
|
||||||
|
has_infill_on_each_layer = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
REQUIRE(has_infill_on_each_layer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SCENARIO("Infill density zero", "[Fill]")
|
SCENARIO("Infill density zero", "[Fill]")
|
||||||
{
|
{
|
||||||
WHEN("20mm cube is sliced") {
|
WHEN("20mm cube is sliced") {
|
||||||
|
@ -44,7 +44,7 @@ SCENARIO("Perimeter nesting", "[Perimeters]")
|
|||||||
|
|
||||||
ExtrusionEntityCollection loops;
|
ExtrusionEntityCollection loops;
|
||||||
ExtrusionEntityCollection gap_fill;
|
ExtrusionEntityCollection gap_fill;
|
||||||
SurfaceCollection fill_surfaces;
|
ExPolygons fill_expolygons;
|
||||||
Flow flow(1., 1., 1.);
|
Flow flow(1., 1., 1.);
|
||||||
PerimeterGenerator::Parameters perimeter_generator_params(
|
PerimeterGenerator::Parameters perimeter_generator_params(
|
||||||
1., // layer height
|
1., // layer height
|
||||||
@ -67,7 +67,7 @@ SCENARIO("Perimeter nesting", "[Perimeters]")
|
|||||||
// cache:
|
// cache:
|
||||||
lower_layer_polygons_cache,
|
lower_layer_polygons_cache,
|
||||||
// output:
|
// output:
|
||||||
loops, gap_fill, fill_surfaces);
|
loops, gap_fill, fill_expolygons);
|
||||||
|
|
||||||
THEN("expected number of collections") {
|
THEN("expected number of collections") {
|
||||||
REQUIRE(loops.entities.size() == data.expolygons.size());
|
REQUIRE(loops.entities.size() == data.expolygons.size());
|
||||||
|
@ -46,11 +46,7 @@ set(XS_XSP_FILES
|
|||||||
${XSP_DIR}/BoundingBox.xsp
|
${XSP_DIR}/BoundingBox.xsp
|
||||||
${XSP_DIR}/Config.xsp
|
${XSP_DIR}/Config.xsp
|
||||||
${XSP_DIR}/ExPolygon.xsp
|
${XSP_DIR}/ExPolygon.xsp
|
||||||
${XSP_DIR}/ExtrusionEntityCollection.xsp
|
|
||||||
${XSP_DIR}/ExtrusionLoop.xsp
|
|
||||||
${XSP_DIR}/ExtrusionPath.xsp
|
|
||||||
${XSP_DIR}/Geometry.xsp
|
${XSP_DIR}/Geometry.xsp
|
||||||
${XSP_DIR}/Layer.xsp
|
|
||||||
${XSP_DIR}/Line.xsp
|
${XSP_DIR}/Line.xsp
|
||||||
${XSP_DIR}/Model.xsp
|
${XSP_DIR}/Model.xsp
|
||||||
${XSP_DIR}/Point.xsp
|
${XSP_DIR}/Point.xsp
|
||||||
|
@ -159,8 +159,6 @@ for my $class (qw(
|
|||||||
Slic3r::ExtrusionPath
|
Slic3r::ExtrusionPath
|
||||||
Slic3r::ExtrusionPath::Collection
|
Slic3r::ExtrusionPath::Collection
|
||||||
Slic3r::Geometry::BoundingBox
|
Slic3r::Geometry::BoundingBox
|
||||||
Slic3r::Layer
|
|
||||||
Slic3r::Layer::Region
|
|
||||||
Slic3r::Line
|
Slic3r::Line
|
||||||
Slic3r::Model
|
Slic3r::Model
|
||||||
Slic3r::Model::Instance
|
Slic3r::Model::Instance
|
||||||
|
@ -8,8 +8,6 @@ REGISTER_CLASS(ExtrusionPath, "ExtrusionPath");
|
|||||||
REGISTER_CLASS(ExtrusionLoop, "ExtrusionLoop");
|
REGISTER_CLASS(ExtrusionLoop, "ExtrusionLoop");
|
||||||
REGISTER_CLASS(ExtrusionEntityCollection, "ExtrusionPath::Collection");
|
REGISTER_CLASS(ExtrusionEntityCollection, "ExtrusionPath::Collection");
|
||||||
REGISTER_CLASS(GCode, "GCode");
|
REGISTER_CLASS(GCode, "GCode");
|
||||||
REGISTER_CLASS(Layer, "Layer");
|
|
||||||
REGISTER_CLASS(LayerRegion, "Layer::Region");
|
|
||||||
REGISTER_CLASS(Line, "Line");
|
REGISTER_CLASS(Line, "Line");
|
||||||
REGISTER_CLASS(Polygon, "Polygon");
|
REGISTER_CLASS(Polygon, "Polygon");
|
||||||
REGISTER_CLASS(Polyline, "Polyline");
|
REGISTER_CLASS(Polyline, "Polyline");
|
||||||
|
@ -1,36 +0,0 @@
|
|||||||
#!/usr/bin/perl
|
|
||||||
|
|
||||||
use strict;
|
|
||||||
use warnings;
|
|
||||||
|
|
||||||
use Slic3r::XS;
|
|
||||||
use Test::More tests => 5;
|
|
||||||
|
|
||||||
my $points = [
|
|
||||||
[100, 100],
|
|
||||||
[200, 100],
|
|
||||||
[200, 200],
|
|
||||||
];
|
|
||||||
|
|
||||||
my $path = Slic3r::ExtrusionPath->new(
|
|
||||||
polyline => Slic3r::Polyline->new(@$points),
|
|
||||||
role => Slic3r::ExtrusionPath::EXTR_ROLE_EXTERNAL_PERIMETER,
|
|
||||||
mm3_per_mm => 1,
|
|
||||||
);
|
|
||||||
|
|
||||||
$path->reverse;
|
|
||||||
is_deeply $path->polyline->pp, [ reverse @$points ], 'reverse path';
|
|
||||||
|
|
||||||
$path->append([ 150, 150 ]);
|
|
||||||
is scalar(@$path), 4, 'append to path';
|
|
||||||
|
|
||||||
$path->pop_back;
|
|
||||||
is scalar(@$path), 3, 'pop_back from path';
|
|
||||||
|
|
||||||
ok $path->first_point->coincides_with($path->polyline->[0]), 'first_point';
|
|
||||||
|
|
||||||
$path = $path->clone;
|
|
||||||
|
|
||||||
is $path->role, Slic3r::ExtrusionPath::EXTR_ROLE_EXTERNAL_PERIMETER, 'role';
|
|
||||||
|
|
||||||
__END__
|
|
@ -1,157 +0,0 @@
|
|||||||
#!/usr/bin/perl
|
|
||||||
|
|
||||||
use strict;
|
|
||||||
use warnings;
|
|
||||||
|
|
||||||
use List::Util qw(sum);
|
|
||||||
use Slic3r::XS;
|
|
||||||
use Test::More tests => 46;
|
|
||||||
|
|
||||||
{
|
|
||||||
my $square = [
|
|
||||||
[100, 100],
|
|
||||||
[200, 100],
|
|
||||||
[200, 200],
|
|
||||||
[100, 200],
|
|
||||||
];
|
|
||||||
my $square_p = Slic3r::Polygon->new(@$square);
|
|
||||||
|
|
||||||
my $loop = Slic3r::ExtrusionLoop->new;
|
|
||||||
$loop->append(Slic3r::ExtrusionPath->new(
|
|
||||||
polyline => $square_p->split_at_first_point,
|
|
||||||
role => Slic3r::ExtrusionPath::EXTR_ROLE_EXTERNAL_PERIMETER,
|
|
||||||
mm3_per_mm => 1,
|
|
||||||
));
|
|
||||||
|
|
||||||
isa_ok $loop, 'Slic3r::ExtrusionLoop';
|
|
||||||
isa_ok $loop->polygon, 'Slic3r::Polygon', 'loop polygon';
|
|
||||||
is $loop->polygon->area, $square_p->area, 'polygon area';
|
|
||||||
is $loop->length, $square_p->length(), 'loop length';
|
|
||||||
|
|
||||||
$loop = $loop->clone;
|
|
||||||
|
|
||||||
is scalar(@$loop), 1, 'loop contains one path';
|
|
||||||
{
|
|
||||||
my $path = $loop->[0];
|
|
||||||
is $path->role, Slic3r::ExtrusionPath::EXTR_ROLE_EXTERNAL_PERIMETER, 'role';
|
|
||||||
}
|
|
||||||
|
|
||||||
$loop->split_at_vertex($square_p->[2]);
|
|
||||||
is scalar(@$loop), 1, 'splitting a single-path loop results in a single path';
|
|
||||||
is scalar(@{$loop->[0]->polyline}), 5, 'path has correct number of points';
|
|
||||||
ok $loop->[0]->polyline->[0]->coincides_with($square_p->[2]), 'expected point order';
|
|
||||||
ok $loop->[0]->polyline->[1]->coincides_with($square_p->[3]), 'expected point order';
|
|
||||||
ok $loop->[0]->polyline->[2]->coincides_with($square_p->[0]), 'expected point order';
|
|
||||||
ok $loop->[0]->polyline->[3]->coincides_with($square_p->[1]), 'expected point order';
|
|
||||||
ok $loop->[0]->polyline->[4]->coincides_with($square_p->[2]), 'expected point order';
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
my $polyline1 = Slic3r::Polyline->new([100,100], [200,100], [200,200]);
|
|
||||||
my $polyline2 = Slic3r::Polyline->new([200,200], [100,200], [100,100]);
|
|
||||||
|
|
||||||
my $loop = Slic3r::ExtrusionLoop->new_from_paths(
|
|
||||||
Slic3r::ExtrusionPath->new(
|
|
||||||
polyline => $polyline1,
|
|
||||||
role => Slic3r::ExtrusionPath::EXTR_ROLE_EXTERNAL_PERIMETER,
|
|
||||||
mm3_per_mm => 1,
|
|
||||||
),
|
|
||||||
Slic3r::ExtrusionPath->new(
|
|
||||||
polyline => $polyline2,
|
|
||||||
role => Slic3r::ExtrusionPath::EXTR_ROLE_OVERHANG_PERIMETER,
|
|
||||||
mm3_per_mm => 1,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
my $tot_len = sum($polyline1->length, $polyline2->length);
|
|
||||||
is $loop->length, $tot_len, 'length';
|
|
||||||
is scalar(@$loop), 2, 'loop contains two paths';
|
|
||||||
|
|
||||||
{
|
|
||||||
# check splitting at intermediate point
|
|
||||||
my $loop2 = $loop->clone;
|
|
||||||
isa_ok $loop2, 'Slic3r::ExtrusionLoop';
|
|
||||||
$loop2->split_at_vertex($polyline1->[1]);
|
|
||||||
is $loop2->length, $tot_len, 'length after splitting is unchanged';
|
|
||||||
is scalar(@$loop2), 3, 'loop contains three paths after splitting';
|
|
||||||
ok $loop2->[0]->polyline->[0]->coincides_with($polyline1->[1]), 'expected starting point';
|
|
||||||
ok $loop2->[-1]->polyline->[-1]->coincides_with($polyline1->[1]), 'expected ending point';
|
|
||||||
ok $loop2->[0]->polyline->[-1]->coincides_with($loop2->[1]->polyline->[0]), 'paths have common point';
|
|
||||||
ok $loop2->[1]->polyline->[-1]->coincides_with($loop2->[2]->polyline->[0]), 'paths have common point';
|
|
||||||
is $loop2->[0]->role, Slic3r::ExtrusionPath::EXTR_ROLE_EXTERNAL_PERIMETER, 'expected order after splitting';
|
|
||||||
is $loop2->[1]->role, Slic3r::ExtrusionPath::EXTR_ROLE_OVERHANG_PERIMETER, 'expected order after splitting';
|
|
||||||
is $loop2->[2]->role, Slic3r::ExtrusionPath::EXTR_ROLE_EXTERNAL_PERIMETER, 'expected order after splitting';
|
|
||||||
is scalar(@{$loop2->[0]->polyline}), 2, 'path has correct number of points';
|
|
||||||
is scalar(@{$loop2->[1]->polyline}), 3, 'path has correct number of points';
|
|
||||||
is scalar(@{$loop2->[2]->polyline}), 2, 'path has correct number of points';
|
|
||||||
|
|
||||||
my @paths = @{$loop2->clip_end(3)};
|
|
||||||
is sum(map $_->length, @paths), $loop2->length - 3, 'returned paths have expected length';
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
# check splitting at endpoint
|
|
||||||
my $loop2 = $loop->clone;
|
|
||||||
$loop2->split_at_vertex($polyline2->[0]);
|
|
||||||
is $loop2->length, $tot_len, 'length after splitting is unchanged';
|
|
||||||
is scalar(@$loop2), 2, 'loop contains two paths after splitting';
|
|
||||||
ok $loop2->[0]->polyline->[0]->coincides_with($polyline2->[0]), 'expected starting point';
|
|
||||||
ok $loop2->[-1]->polyline->[-1]->coincides_with($polyline2->[0]), 'expected ending point';
|
|
||||||
ok $loop2->[0]->polyline->[-1]->coincides_with($loop2->[1]->polyline->[0]), 'paths have common point';
|
|
||||||
ok $loop2->[1]->polyline->[-1]->coincides_with($loop2->[0]->polyline->[0]), 'paths have common point';
|
|
||||||
is $loop2->[0]->role, Slic3r::ExtrusionPath::EXTR_ROLE_OVERHANG_PERIMETER, 'expected order after splitting';
|
|
||||||
is $loop2->[1]->role, Slic3r::ExtrusionPath::EXTR_ROLE_EXTERNAL_PERIMETER, 'expected order after splitting';
|
|
||||||
is scalar(@{$loop2->[0]->polyline}), 3, 'path has correct number of points';
|
|
||||||
is scalar(@{$loop2->[1]->polyline}), 3, 'path has correct number of points';
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
my $loop2 = $loop->clone;
|
|
||||||
my $point = Slic3r::Point->new(250,150);
|
|
||||||
$loop2->split_at($point);
|
|
||||||
is $loop2->length, $tot_len, 'length after splitting is unchanged';
|
|
||||||
is scalar(@$loop2), 3, 'loop contains three paths after splitting';
|
|
||||||
my $expected_start_point = Slic3r::Point->new(200,150);
|
|
||||||
ok $loop2->[0]->polyline->[0]->coincides_with($expected_start_point), 'expected starting point';
|
|
||||||
ok $loop2->[-1]->polyline->[-1]->coincides_with($expected_start_point), 'expected ending point';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
my @polylines = (
|
|
||||||
Slic3r::Polyline->new([59312736,4821067],[64321068,4821067],[64321068,4821067],[64321068,9321068],[59312736,9321068]),
|
|
||||||
Slic3r::Polyline->new([59312736,9321068],[9829401,9321068]),
|
|
||||||
Slic3r::Polyline->new([9829401,9321068],[4821067,9321068],[4821067,4821067],[9829401,4821067]),
|
|
||||||
Slic3r::Polyline->new([9829401,4821067],[59312736,4821067]),
|
|
||||||
);
|
|
||||||
my $loop = Slic3r::ExtrusionLoop->new;
|
|
||||||
$loop->append($_) for (
|
|
||||||
Slic3r::ExtrusionPath->new(polyline => $polylines[0], role => Slic3r::ExtrusionPath::EXTR_ROLE_EXTERNAL_PERIMETER, mm3_per_mm => 1),
|
|
||||||
Slic3r::ExtrusionPath->new(polyline => $polylines[1], role => Slic3r::ExtrusionPath::EXTR_ROLE_OVERHANG_PERIMETER, mm3_per_mm => 1),
|
|
||||||
Slic3r::ExtrusionPath->new(polyline => $polylines[2], role => Slic3r::ExtrusionPath::EXTR_ROLE_EXTERNAL_PERIMETER, mm3_per_mm => 1),
|
|
||||||
Slic3r::ExtrusionPath->new(polyline => $polylines[3], role => Slic3r::ExtrusionPath::EXTR_ROLE_OVERHANG_PERIMETER, mm3_per_mm => 1),
|
|
||||||
);
|
|
||||||
my $len = $loop->length;
|
|
||||||
my $point = Slic3r::Point->new(4821067,9321068);
|
|
||||||
$loop->split_at_vertex($point) or $loop->split_at($point);
|
|
||||||
is $loop->length, $len, 'total length is preserved after splitting';
|
|
||||||
is_deeply [ map $_->role, @$loop ], [
|
|
||||||
Slic3r::ExtrusionPath::EXTR_ROLE_EXTERNAL_PERIMETER,
|
|
||||||
Slic3r::ExtrusionPath::EXTR_ROLE_OVERHANG_PERIMETER,
|
|
||||||
Slic3r::ExtrusionPath::EXTR_ROLE_EXTERNAL_PERIMETER,
|
|
||||||
Slic3r::ExtrusionPath::EXTR_ROLE_OVERHANG_PERIMETER,
|
|
||||||
Slic3r::ExtrusionPath::EXTR_ROLE_EXTERNAL_PERIMETER,
|
|
||||||
], 'order is correctly preserved after splitting';
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
my $loop = Slic3r::ExtrusionLoop->new;
|
|
||||||
$loop->append(Slic3r::ExtrusionPath->new(
|
|
||||||
polyline => Slic3r::Polyline->new([15896783,15868739],[24842049,12117558],[33853238,15801279],[37591780,24780128],[37591780,24844970],[33853231,33825297],[24842049,37509013],[15896798,33757841],[12211841,24812544],[15896783,15868739]),
|
|
||||||
role => Slic3r::ExtrusionPath::EXTR_ROLE_EXTERNAL_PERIMETER, mm3_per_mm => 1
|
|
||||||
));
|
|
||||||
my $len = $loop->length;
|
|
||||||
$loop->split_at(Slic3r::Point->new(15896783,15868739));
|
|
||||||
is $loop->length, $len, 'split_at() preserves total length';
|
|
||||||
}
|
|
||||||
|
|
||||||
__END__
|
|
@ -1,91 +0,0 @@
|
|||||||
#!/usr/bin/perl
|
|
||||||
|
|
||||||
use strict;
|
|
||||||
use warnings;
|
|
||||||
|
|
||||||
use Slic3r::XS;
|
|
||||||
use Test::More tests => 13;
|
|
||||||
|
|
||||||
my $points = [
|
|
||||||
[100, 100],
|
|
||||||
[200, 100],
|
|
||||||
[200, 200],
|
|
||||||
];
|
|
||||||
|
|
||||||
my $path = Slic3r::ExtrusionPath->new(
|
|
||||||
polyline => Slic3r::Polyline->new(@$points),
|
|
||||||
role => Slic3r::ExtrusionPath::EXTR_ROLE_EXTERNAL_PERIMETER,
|
|
||||||
mm3_per_mm => 1,
|
|
||||||
);
|
|
||||||
|
|
||||||
my $loop = Slic3r::ExtrusionLoop->new_from_paths(
|
|
||||||
Slic3r::ExtrusionPath->new(
|
|
||||||
polyline => Slic3r::Polygon->new(@$points)->split_at_first_point,
|
|
||||||
role => Slic3r::ExtrusionPath::EXTR_ROLE_FILL,
|
|
||||||
mm3_per_mm => 1,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
my $collection = Slic3r::ExtrusionPath::Collection->new(
|
|
||||||
$path,
|
|
||||||
);
|
|
||||||
isa_ok $collection, 'Slic3r::ExtrusionPath::Collection', 'collection object with items in constructor';
|
|
||||||
ok !$collection->no_sort, 'no_sort is false by default';
|
|
||||||
|
|
||||||
$collection->append($collection);
|
|
||||||
is scalar(@$collection), 2, 'append ExtrusionPath::Collection';
|
|
||||||
|
|
||||||
$collection->append($path);
|
|
||||||
is scalar(@$collection), 3, 'append ExtrusionPath';
|
|
||||||
|
|
||||||
$collection->append($loop);
|
|
||||||
is scalar(@$collection), 4, 'append ExtrusionLoop';
|
|
||||||
|
|
||||||
is scalar(@{$collection->[1]}), 1, 'appended collection was duplicated';
|
|
||||||
|
|
||||||
{
|
|
||||||
my $collection_loop = $collection->[3];
|
|
||||||
$collection_loop->polygon->scale(2);
|
|
||||||
is_deeply $collection->[3]->polygon->pp, $collection_loop->polygon->pp, 'items are returned by reference';
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
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_from';
|
|
||||||
is_deeply
|
|
||||||
[ map $_->y, map @{$_->polyline}, @{$collection->chained_path(0)} ],
|
|
||||||
[15, 18, 20, 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_from';
|
|
||||||
|
|
||||||
$collection->no_sort(1);
|
|
||||||
my @foo = @{$collection->chained_path(0)};
|
|
||||||
pass 'chained_path with no_sort';
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
my $coll2 = $collection->clone;
|
|
||||||
ok !$coll2->no_sort, 'expected no_sort value';
|
|
||||||
$coll2->no_sort(1);
|
|
||||||
ok $coll2->clone->no_sort, 'no_sort is kept after clone';
|
|
||||||
}
|
|
||||||
|
|
||||||
__END__
|
|
@ -1,102 +0,0 @@
|
|||||||
%module{Slic3r::XS};
|
|
||||||
|
|
||||||
%{
|
|
||||||
#include <xsinit.h>
|
|
||||||
#include "libslic3r/ExtrusionEntityCollection.hpp"
|
|
||||||
%}
|
|
||||||
|
|
||||||
%name{Slic3r::ExtrusionPath::Collection} class ExtrusionEntityCollection {
|
|
||||||
%name{_new} ExtrusionEntityCollection();
|
|
||||||
~ExtrusionEntityCollection();
|
|
||||||
Clone<ExtrusionEntityCollection> clone()
|
|
||||||
%code{% RETVAL = (ExtrusionEntityCollection*)THIS->clone(); %};
|
|
||||||
void reverse();
|
|
||||||
void clear();
|
|
||||||
ExtrusionEntityCollection* chained_path(bool no_reverse, ExtrusionRole role = erMixed)
|
|
||||||
%code{%
|
|
||||||
if (no_reverse)
|
|
||||||
croak("no_reverse must be false");
|
|
||||||
RETVAL = new ExtrusionEntityCollection();
|
|
||||||
*RETVAL = THIS->chained_path_from(THIS->entities.front()->first_point());
|
|
||||||
%};
|
|
||||||
ExtrusionEntityCollection* chained_path_from(Point* start_near, bool no_reverse, ExtrusionRole role = erMixed)
|
|
||||||
%code{%
|
|
||||||
if (no_reverse)
|
|
||||||
croak("no_reverse must be false");
|
|
||||||
RETVAL = new ExtrusionEntityCollection();
|
|
||||||
*RETVAL = THIS->chained_path_from(*start_near, role);
|
|
||||||
%};
|
|
||||||
Clone<Point> first_point();
|
|
||||||
Clone<Point> last_point();
|
|
||||||
int count()
|
|
||||||
%code{% RETVAL = THIS->entities.size(); %};
|
|
||||||
int items_count()
|
|
||||||
%code{% RETVAL = THIS->items_count(); %};
|
|
||||||
ExtrusionEntityCollection* flatten()
|
|
||||||
%code{%
|
|
||||||
RETVAL = new ExtrusionEntityCollection();
|
|
||||||
*RETVAL = THIS->flatten();
|
|
||||||
%};
|
|
||||||
double min_mm3_per_mm();
|
|
||||||
bool empty()
|
|
||||||
%code{% RETVAL = THIS->entities.empty(); %};
|
|
||||||
Polygons polygons_covered_by_width();
|
|
||||||
Polygons polygons_covered_by_spacing();
|
|
||||||
%{
|
|
||||||
|
|
||||||
SV*
|
|
||||||
ExtrusionEntityCollection::arrayref()
|
|
||||||
CODE:
|
|
||||||
AV* av = newAV();
|
|
||||||
av_fill(av, THIS->entities.size()-1);
|
|
||||||
int i = 0;
|
|
||||||
for (ExtrusionEntitiesPtr::iterator it = THIS->entities.begin(); it != THIS->entities.end(); ++it) {
|
|
||||||
SV* sv = newSV(0);
|
|
||||||
// return our item by reference
|
|
||||||
if (ExtrusionPath* path = dynamic_cast<ExtrusionPath*>(*it)) {
|
|
||||||
sv_setref_pv( sv, perl_class_name_ref(path), path );
|
|
||||||
} else if (ExtrusionLoop* loop = dynamic_cast<ExtrusionLoop*>(*it)) {
|
|
||||||
sv_setref_pv( sv, perl_class_name_ref(loop), loop );
|
|
||||||
} else if (ExtrusionEntityCollection* collection = dynamic_cast<ExtrusionEntityCollection*>(*it)) {
|
|
||||||
sv_setref_pv( sv, perl_class_name_ref(collection), collection );
|
|
||||||
} else {
|
|
||||||
croak("Unexpected type in ExtrusionEntityCollection");
|
|
||||||
}
|
|
||||||
av_store(av, i++, sv);
|
|
||||||
}
|
|
||||||
RETVAL = newRV_noinc((SV*)av);
|
|
||||||
OUTPUT:
|
|
||||||
RETVAL
|
|
||||||
|
|
||||||
void
|
|
||||||
ExtrusionEntityCollection::append(...)
|
|
||||||
CODE:
|
|
||||||
for (unsigned int i = 1; i < items; i++) {
|
|
||||||
if(!sv_isobject( ST(i) ) || (SvTYPE(SvRV( ST(i) )) != SVt_PVMG)) {
|
|
||||||
croak("Argument %d is not object", i);
|
|
||||||
}
|
|
||||||
ExtrusionEntity* entity = (ExtrusionEntity *)SvIV((SV*)SvRV( ST(i) ));
|
|
||||||
// append COPIES
|
|
||||||
if (ExtrusionPath* path = dynamic_cast<ExtrusionPath*>(entity)) {
|
|
||||||
THIS->entities.push_back( new ExtrusionPath(*path) );
|
|
||||||
} else if (ExtrusionLoop* loop = dynamic_cast<ExtrusionLoop*>(entity)) {
|
|
||||||
THIS->entities.push_back( new ExtrusionLoop(*loop) );
|
|
||||||
} else if(ExtrusionEntityCollection* collection = dynamic_cast<ExtrusionEntityCollection*>(entity)) {
|
|
||||||
THIS->entities.push_back( collection->clone() );
|
|
||||||
} else {
|
|
||||||
croak("Argument %d is of unknown type", i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
ExtrusionEntityCollection::no_sort(...)
|
|
||||||
CODE:
|
|
||||||
if (items > 1) {
|
|
||||||
THIS->no_sort = SvTRUE(ST(1));
|
|
||||||
}
|
|
||||||
RETVAL = THIS->no_sort;
|
|
||||||
OUTPUT:
|
|
||||||
RETVAL
|
|
||||||
|
|
||||||
%}
|
|
||||||
};
|
|
@ -1,65 +0,0 @@
|
|||||||
%module{Slic3r::XS};
|
|
||||||
|
|
||||||
%{
|
|
||||||
#include <xsinit.h>
|
|
||||||
#include "libslic3r/ExtrusionEntity.hpp"
|
|
||||||
%}
|
|
||||||
|
|
||||||
%name{Slic3r::ExtrusionLoop} class ExtrusionLoop {
|
|
||||||
ExtrusionLoop();
|
|
||||||
~ExtrusionLoop();
|
|
||||||
Clone<ExtrusionLoop> clone()
|
|
||||||
%code{% RETVAL = THIS; %};
|
|
||||||
void reverse();
|
|
||||||
bool make_clockwise();
|
|
||||||
bool make_counter_clockwise();
|
|
||||||
Clone<Point> first_point();
|
|
||||||
Clone<Point> last_point();
|
|
||||||
Clone<Polygon> polygon();
|
|
||||||
void append(ExtrusionPath* path)
|
|
||||||
%code{% THIS->paths.push_back(*path); %};
|
|
||||||
double length();
|
|
||||||
bool split_at_vertex(Point* point)
|
|
||||||
%code{% RETVAL = THIS->split_at_vertex(*point); %};
|
|
||||||
void split_at(Point* point, int prefer_non_overhang = 0, double scaled_epsilon = 0.)
|
|
||||||
%code{% THIS->split_at(*point, prefer_non_overhang != 0, scaled_epsilon); %};
|
|
||||||
ExtrusionPaths clip_end(double distance)
|
|
||||||
%code{% THIS->clip_end(distance, &RETVAL); %};
|
|
||||||
bool has_overhang_point(Point* point)
|
|
||||||
%code{% RETVAL = THIS->has_overhang_point(*point); %};
|
|
||||||
ExtrusionRole role() const;
|
|
||||||
ExtrusionLoopRole loop_role() const;
|
|
||||||
Polygons polygons_covered_by_width();
|
|
||||||
Polygons polygons_covered_by_spacing();
|
|
||||||
%{
|
|
||||||
|
|
||||||
SV*
|
|
||||||
ExtrusionLoop::arrayref()
|
|
||||||
CODE:
|
|
||||||
AV* av = newAV();
|
|
||||||
av_fill(av, THIS->paths.size()-1);
|
|
||||||
for (ExtrusionPaths::iterator it = THIS->paths.begin(); it != THIS->paths.end(); ++it) {
|
|
||||||
av_store(av, it - THIS->paths.begin(), perl_to_SV_ref(*it));
|
|
||||||
}
|
|
||||||
RETVAL = newRV_noinc((SV*)av);
|
|
||||||
OUTPUT:
|
|
||||||
RETVAL
|
|
||||||
|
|
||||||
%}
|
|
||||||
};
|
|
||||||
|
|
||||||
%package{Slic3r::ExtrusionLoop};
|
|
||||||
%{
|
|
||||||
|
|
||||||
IV
|
|
||||||
_constant()
|
|
||||||
ALIAS:
|
|
||||||
EXTRL_ROLE_DEFAULT = elrDefault
|
|
||||||
EXTRL_ROLE_CONTOUR_INTERNAL_PERIMETER = elrContourInternalPerimeter
|
|
||||||
EXTRL_ROLE_SKIRT = elrSkirt
|
|
||||||
PROTOTYPE:
|
|
||||||
CODE:
|
|
||||||
RETVAL = ix;
|
|
||||||
OUTPUT: RETVAL
|
|
||||||
|
|
||||||
%}
|
|
@ -1,126 +0,0 @@
|
|||||||
%module{Slic3r::XS};
|
|
||||||
|
|
||||||
%{
|
|
||||||
#include <xsinit.h>
|
|
||||||
#include "libslic3r/ExtrusionEntity.hpp"
|
|
||||||
#include "libslic3r/ExtrusionEntityCollection.hpp"
|
|
||||||
%}
|
|
||||||
|
|
||||||
%name{Slic3r::ExtrusionPath} class ExtrusionPath {
|
|
||||||
~ExtrusionPath();
|
|
||||||
SV* arrayref()
|
|
||||||
%code{% RETVAL = to_AV(&THIS->polyline); %};
|
|
||||||
SV* pp()
|
|
||||||
%code{% RETVAL = to_SV_pureperl(&THIS->polyline); %};
|
|
||||||
void pop_back()
|
|
||||||
%code{% THIS->polyline.points.pop_back(); %};
|
|
||||||
void reverse();
|
|
||||||
Lines lines()
|
|
||||||
%code{% RETVAL = THIS->polyline.lines(); %};
|
|
||||||
Clone<Point> first_point();
|
|
||||||
Clone<Point> last_point();
|
|
||||||
void clip_end(double distance);
|
|
||||||
void simplify(double tolerance);
|
|
||||||
double length();
|
|
||||||
ExtrusionRole role() const;
|
|
||||||
bool is_bridge()
|
|
||||||
%code{% RETVAL = is_bridge(THIS->role()); %};
|
|
||||||
Polygons polygons_covered_by_width();
|
|
||||||
Polygons polygons_covered_by_spacing();
|
|
||||||
%{
|
|
||||||
|
|
||||||
ExtrusionPath*
|
|
||||||
_new(CLASS, polyline_sv, role, mm3_per_mm, width, height)
|
|
||||||
char* CLASS;
|
|
||||||
SV* polyline_sv;
|
|
||||||
ExtrusionRole role;
|
|
||||||
double mm3_per_mm;
|
|
||||||
float width;
|
|
||||||
float height;
|
|
||||||
CODE:
|
|
||||||
RETVAL = new ExtrusionPath (role);
|
|
||||||
from_SV_check(polyline_sv, &RETVAL->polyline);
|
|
||||||
RETVAL->mm3_per_mm = mm3_per_mm;
|
|
||||||
RETVAL->width = width;
|
|
||||||
RETVAL->height = height;
|
|
||||||
OUTPUT:
|
|
||||||
RETVAL
|
|
||||||
|
|
||||||
Ref<Polyline>
|
|
||||||
ExtrusionPath::polyline(...)
|
|
||||||
CODE:
|
|
||||||
if (items > 1) {
|
|
||||||
from_SV_check(ST(1), &THIS->polyline);
|
|
||||||
}
|
|
||||||
RETVAL = &(THIS->polyline);
|
|
||||||
OUTPUT:
|
|
||||||
RETVAL
|
|
||||||
|
|
||||||
double
|
|
||||||
ExtrusionPath::mm3_per_mm(...)
|
|
||||||
CODE:
|
|
||||||
if (items > 1) {
|
|
||||||
THIS->mm3_per_mm = (double)SvNV(ST(1));
|
|
||||||
}
|
|
||||||
RETVAL = THIS->mm3_per_mm;
|
|
||||||
OUTPUT:
|
|
||||||
RETVAL
|
|
||||||
|
|
||||||
float
|
|
||||||
ExtrusionPath::width(...)
|
|
||||||
CODE:
|
|
||||||
if (items > 1) {
|
|
||||||
THIS->width = (float)SvNV(ST(1));
|
|
||||||
}
|
|
||||||
RETVAL = THIS->width;
|
|
||||||
OUTPUT:
|
|
||||||
RETVAL
|
|
||||||
|
|
||||||
float
|
|
||||||
ExtrusionPath::height(...)
|
|
||||||
CODE:
|
|
||||||
if (items > 1) {
|
|
||||||
THIS->height = (float)SvNV(ST(1));
|
|
||||||
}
|
|
||||||
RETVAL = THIS->height;
|
|
||||||
OUTPUT:
|
|
||||||
RETVAL
|
|
||||||
|
|
||||||
void
|
|
||||||
ExtrusionPath::append(...)
|
|
||||||
CODE:
|
|
||||||
for (unsigned int i = 1; i < items; i++) {
|
|
||||||
Point p;
|
|
||||||
from_SV_check(ST(i), &p);
|
|
||||||
THIS->polyline.points.push_back(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
%}
|
|
||||||
};
|
|
||||||
|
|
||||||
%package{Slic3r::ExtrusionPath};
|
|
||||||
%{
|
|
||||||
|
|
||||||
IV
|
|
||||||
_constant()
|
|
||||||
ALIAS:
|
|
||||||
EXTR_ROLE_NONE = erNone
|
|
||||||
EXTR_ROLE_PERIMETER = erPerimeter
|
|
||||||
EXTR_ROLE_EXTERNAL_PERIMETER = erExternalPerimeter
|
|
||||||
EXTR_ROLE_OVERHANG_PERIMETER = erOverhangPerimeter
|
|
||||||
EXTR_ROLE_FILL = erInternalInfill
|
|
||||||
EXTR_ROLE_SOLIDFILL = erSolidInfill
|
|
||||||
EXTR_ROLE_TOPSOLIDFILL = erTopSolidInfill
|
|
||||||
EXTR_ROLE_BRIDGE = erBridgeInfill
|
|
||||||
EXTR_ROLE_GAPFILL = erGapFill
|
|
||||||
EXTR_ROLE_SKIRT = erSkirt
|
|
||||||
EXTR_ROLE_SUPPORTMATERIAL = erSupportMaterial
|
|
||||||
EXTR_ROLE_SUPPORTMATERIAL_INTERFACE = erSupportMaterialInterface
|
|
||||||
EXTR_ROLE_MIXED = erMixed
|
|
||||||
PROTOTYPE:
|
|
||||||
CODE:
|
|
||||||
RETVAL = ix;
|
|
||||||
OUTPUT: RETVAL
|
|
||||||
|
|
||||||
%}
|
|
||||||
|
|
@ -1,72 +0,0 @@
|
|||||||
%module{Slic3r::XS};
|
|
||||||
|
|
||||||
%{
|
|
||||||
#include <xsinit.h>
|
|
||||||
#include "libslic3r/Layer.hpp"
|
|
||||||
%}
|
|
||||||
|
|
||||||
%name{Slic3r::Layer::Region} class LayerRegion {
|
|
||||||
// owned by Layer, no constructor/destructor
|
|
||||||
|
|
||||||
Ref<Layer> layer();
|
|
||||||
Ref<PrintRegion> region()
|
|
||||||
%code%{ RETVAL = &THIS->region(); %};
|
|
||||||
|
|
||||||
Ref<SurfaceCollection> slices()
|
|
||||||
%code%{ RETVAL = const_cast<SurfaceCollection*>(&THIS->slices()); %};
|
|
||||||
Ref<ExtrusionEntityCollection> thin_fills()
|
|
||||||
%code%{ RETVAL = const_cast<ExtrusionEntityCollection*>(&THIS->thin_fills()); %};
|
|
||||||
Ref<SurfaceCollection> fill_surfaces()
|
|
||||||
%code%{ RETVAL = const_cast<SurfaceCollection*>(&THIS->fill_surfaces()); %};
|
|
||||||
Ref<ExtrusionEntityCollection> perimeters()
|
|
||||||
%code%{ RETVAL = const_cast<ExtrusionEntityCollection*>(&THIS->perimeters()); %};
|
|
||||||
Ref<ExtrusionEntityCollection> fills()
|
|
||||||
%code%{ RETVAL = const_cast<ExtrusionEntityCollection*>(&THIS->fills()); %};
|
|
||||||
|
|
||||||
void prepare_fill_surfaces();
|
|
||||||
void make_perimeters(SurfaceCollection* slices, SurfaceCollection* fill_surfaces)
|
|
||||||
%code%{ THIS->make_perimeters(*slices, fill_surfaces); %};
|
|
||||||
double infill_area_threshold();
|
|
||||||
|
|
||||||
void export_region_slices_to_svg(const char *path) const;
|
|
||||||
void export_region_fill_surfaces_to_svg(const char *path) const;
|
|
||||||
void export_region_slices_to_svg_debug(const char *name) const;
|
|
||||||
void export_region_fill_surfaces_to_svg_debug(const char *name) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
%name{Slic3r::Layer} class Layer {
|
|
||||||
// owned by PrintObject, no constructor/destructor
|
|
||||||
|
|
||||||
Ref<Layer> as_layer()
|
|
||||||
%code%{ RETVAL = THIS; %};
|
|
||||||
|
|
||||||
int id();
|
|
||||||
void set_id(int id);
|
|
||||||
Ref<PrintObject> object();
|
|
||||||
bool slicing_errors()
|
|
||||||
%code%{ RETVAL = THIS->slicing_errors; %};
|
|
||||||
coordf_t slice_z()
|
|
||||||
%code%{ RETVAL = THIS->slice_z; %};
|
|
||||||
coordf_t print_z()
|
|
||||||
%code%{ RETVAL = THIS->print_z; %};
|
|
||||||
coordf_t height()
|
|
||||||
%code%{ RETVAL = THIS->height; %};
|
|
||||||
|
|
||||||
size_t region_count();
|
|
||||||
Ref<LayerRegion> get_region(int idx);
|
|
||||||
Ref<LayerRegion> add_region(PrintRegion* print_region);
|
|
||||||
|
|
||||||
int ptr()
|
|
||||||
%code%{ RETVAL = (int)(intptr_t)THIS; %};
|
|
||||||
|
|
||||||
void make_slices();
|
|
||||||
void backup_untyped_slices();
|
|
||||||
void restore_untyped_slices();
|
|
||||||
void make_perimeters();
|
|
||||||
void make_fills();
|
|
||||||
|
|
||||||
void export_region_slices_to_svg(const char *path);
|
|
||||||
void export_region_fill_surfaces_to_svg(const char *path);
|
|
||||||
void export_region_slices_to_svg_debug(const char *name);
|
|
||||||
void export_region_fill_surfaces_to_svg_debug(const char *name);
|
|
||||||
};
|
|
@ -21,9 +21,6 @@
|
|||||||
%code%{ RETVAL = &THIS->config(); %};
|
%code%{ RETVAL = &THIS->config(); %};
|
||||||
Clone<BoundingBox> bounding_box();
|
Clone<BoundingBox> bounding_box();
|
||||||
|
|
||||||
size_t layer_count();
|
|
||||||
Ref<Layer> get_layer(int idx);
|
|
||||||
|
|
||||||
void slice();
|
void slice();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -35,10 +32,6 @@
|
|||||||
%code%{ RETVAL = const_cast<Model*>(&THIS->model()); %};
|
%code%{ RETVAL = const_cast<Model*>(&THIS->model()); %};
|
||||||
Ref<StaticPrintConfig> config()
|
Ref<StaticPrintConfig> config()
|
||||||
%code%{ RETVAL = const_cast<GCodeConfig*>(static_cast<const GCodeConfig*>(&THIS->config())); %};
|
%code%{ RETVAL = const_cast<GCodeConfig*>(static_cast<const GCodeConfig*>(&THIS->config())); %};
|
||||||
Ref<ExtrusionEntityCollection> skirt()
|
|
||||||
%code%{ RETVAL = const_cast<ExtrusionEntityCollection*>(&THIS->skirt()); %};
|
|
||||||
Ref<ExtrusionEntityCollection> brim()
|
|
||||||
%code%{ RETVAL = const_cast<ExtrusionEntityCollection*>(&THIS->brim()); %};
|
|
||||||
double total_used_filament()
|
double total_used_filament()
|
||||||
%code%{ RETVAL = THIS->print_statistics().total_used_filament; %};
|
%code%{ RETVAL = THIS->print_statistics().total_used_filament; %};
|
||||||
double total_extruded_volume()
|
double total_extruded_volume()
|
||||||
|
@ -70,18 +70,6 @@ ExPolygon* O_OBJECT_SLIC3R
|
|||||||
Ref<ExPolygon> O_OBJECT_SLIC3R_T
|
Ref<ExPolygon> O_OBJECT_SLIC3R_T
|
||||||
Clone<ExPolygon> O_OBJECT_SLIC3R_T
|
Clone<ExPolygon> O_OBJECT_SLIC3R_T
|
||||||
|
|
||||||
ExtrusionEntityCollection* O_OBJECT_SLIC3R
|
|
||||||
Ref<ExtrusionEntityCollection> O_OBJECT_SLIC3R_T
|
|
||||||
Clone<ExtrusionEntityCollection> O_OBJECT_SLIC3R_T
|
|
||||||
|
|
||||||
ExtrusionPath* O_OBJECT_SLIC3R
|
|
||||||
Ref<ExtrusionPath> O_OBJECT_SLIC3R_T
|
|
||||||
Clone<ExtrusionPath> O_OBJECT_SLIC3R_T
|
|
||||||
|
|
||||||
ExtrusionLoop* O_OBJECT_SLIC3R
|
|
||||||
Ref<ExtrusionLoop> O_OBJECT_SLIC3R_T
|
|
||||||
Clone<ExtrusionLoop> O_OBJECT_SLIC3R_T
|
|
||||||
|
|
||||||
Surface* O_OBJECT_SLIC3R
|
Surface* O_OBJECT_SLIC3R
|
||||||
Ref<Surface> O_OBJECT_SLIC3R_T
|
Ref<Surface> O_OBJECT_SLIC3R_T
|
||||||
Clone<Surface> O_OBJECT_SLIC3R_T
|
Clone<Surface> O_OBJECT_SLIC3R_T
|
||||||
@ -119,12 +107,6 @@ Print* O_OBJECT_SLIC3R
|
|||||||
Ref<Print> O_OBJECT_SLIC3R_T
|
Ref<Print> O_OBJECT_SLIC3R_T
|
||||||
Clone<Print> O_OBJECT_SLIC3R_T
|
Clone<Print> O_OBJECT_SLIC3R_T
|
||||||
|
|
||||||
LayerRegion* O_OBJECT_SLIC3R
|
|
||||||
Ref<LayerRegion> O_OBJECT_SLIC3R_T
|
|
||||||
|
|
||||||
Layer* O_OBJECT_SLIC3R
|
|
||||||
Ref<Layer> O_OBJECT_SLIC3R_T
|
|
||||||
|
|
||||||
Axis T_UV
|
Axis T_UV
|
||||||
ExtrusionLoopRole T_UV
|
ExtrusionLoopRole T_UV
|
||||||
ExtrusionRole T_UV
|
ExtrusionRole T_UV
|
||||||
@ -137,7 +119,6 @@ Lines T_ARRAYREF
|
|||||||
Polygons T_ARRAYREF
|
Polygons T_ARRAYREF
|
||||||
Polylines T_ARRAYREF
|
Polylines T_ARRAYREF
|
||||||
ExPolygons T_ARRAYREF
|
ExPolygons T_ARRAYREF
|
||||||
ExtrusionPaths T_ARRAYREF
|
|
||||||
Surfaces T_ARRAYREF
|
Surfaces T_ARRAYREF
|
||||||
|
|
||||||
# we return these types whenever we want the items to be returned
|
# we return these types whenever we want the items to be returned
|
||||||
@ -149,7 +130,6 @@ ModelVolumePtrs* T_PTR_ARRAYREF_PTR
|
|||||||
ModelInstancePtrs* T_PTR_ARRAYREF_PTR
|
ModelInstancePtrs* T_PTR_ARRAYREF_PTR
|
||||||
PrintRegionPtrs* T_PTR_ARRAYREF_PTR
|
PrintRegionPtrs* T_PTR_ARRAYREF_PTR
|
||||||
PrintObjectPtrs* T_PTR_ARRAYREF_PTR
|
PrintObjectPtrs* T_PTR_ARRAYREF_PTR
|
||||||
LayerPtrs* T_PTR_ARRAYREF_PTR
|
|
||||||
|
|
||||||
# we return these types whenever we want the items to be returned
|
# we return these types whenever we want the items to be returned
|
||||||
# by reference and not marked ::Ref because they're newly allocated
|
# by reference and not marked ::Ref because they're newly allocated
|
||||||
|
@ -53,15 +53,6 @@
|
|||||||
%typemap{Polygon*};
|
%typemap{Polygon*};
|
||||||
%typemap{Ref<Polygon>}{simple};
|
%typemap{Ref<Polygon>}{simple};
|
||||||
%typemap{Clone<Polygon>}{simple};
|
%typemap{Clone<Polygon>}{simple};
|
||||||
%typemap{ExtrusionEntityCollection*};
|
|
||||||
%typemap{Ref<ExtrusionEntityCollection>}{simple};
|
|
||||||
%typemap{Clone<ExtrusionEntityCollection>}{simple};
|
|
||||||
%typemap{ExtrusionPath*};
|
|
||||||
%typemap{Ref<ExtrusionPath>}{simple};
|
|
||||||
%typemap{Clone<ExtrusionPath>}{simple};
|
|
||||||
%typemap{ExtrusionLoop*};
|
|
||||||
%typemap{Ref<ExtrusionLoop>}{simple};
|
|
||||||
%typemap{Clone<ExtrusionLoop>}{simple};
|
|
||||||
%typemap{TriangleMesh*};
|
%typemap{TriangleMesh*};
|
||||||
%typemap{Ref<TriangleMesh>}{simple};
|
%typemap{Ref<TriangleMesh>}{simple};
|
||||||
%typemap{Clone<TriangleMesh>}{simple};
|
%typemap{Clone<TriangleMesh>}{simple};
|
||||||
@ -86,19 +77,12 @@
|
|||||||
%typemap{Ref<Print>}{simple};
|
%typemap{Ref<Print>}{simple};
|
||||||
%typemap{Clone<Print>}{simple};
|
%typemap{Clone<Print>}{simple};
|
||||||
|
|
||||||
%typemap{LayerRegion*};
|
|
||||||
%typemap{Ref<LayerRegion>}{simple};
|
|
||||||
|
|
||||||
%typemap{Layer*};
|
|
||||||
%typemap{Ref<Layer>}{simple};
|
|
||||||
|
|
||||||
%typemap{Points};
|
%typemap{Points};
|
||||||
%typemap{Pointfs};
|
%typemap{Pointfs};
|
||||||
%typemap{Lines};
|
%typemap{Lines};
|
||||||
%typemap{Polygons};
|
%typemap{Polygons};
|
||||||
%typemap{Polylines};
|
%typemap{Polylines};
|
||||||
%typemap{ExPolygons};
|
%typemap{ExPolygons};
|
||||||
%typemap{ExtrusionPaths};
|
|
||||||
%typemap{Surfaces};
|
%typemap{Surfaces};
|
||||||
%typemap{Polygons*};
|
%typemap{Polygons*};
|
||||||
%typemap{TriangleMesh*};
|
%typemap{TriangleMesh*};
|
||||||
|
Loading…
Reference in New Issue
Block a user