New seal_position option that replaces randomize_start, start_perimeters_at_concave_points and start_perimeters_at_non_overhang. The two latter options are now always on by default. A new "Aligned" seal position value has been added, that forces starting points to be aligned when not randomized. #1741 #925
This commit is contained in:
parent
c63bd8165d
commit
a3bd1b5302
@ -219,7 +219,7 @@ The author of the Silk icon set is Mark James.
|
|||||||
home X axis [G28 X], disable motors [M84]).
|
home X axis [G28 X], disable motors [M84]).
|
||||||
--layer-gcode Load layer-change G-code from the supplied file (default: nothing).
|
--layer-gcode Load layer-change G-code from the supplied file (default: nothing).
|
||||||
--toolchange-gcode Load tool-change G-code from the supplied file (default: nothing).
|
--toolchange-gcode Load tool-change G-code from the supplied file (default: nothing).
|
||||||
--randomize-start Randomize starting point across layers (default: yes)
|
--seal-position Position of loop starting points (random/nearest/aligned, default: aligned).
|
||||||
--external-perimeters-first Reverse perimeter order. (default: no)
|
--external-perimeters-first Reverse perimeter order. (default: no)
|
||||||
--spiral-vase Experimental option to raise Z gradually when printing single-walled vases
|
--spiral-vase Experimental option to raise Z gradually when printing single-walled vases
|
||||||
(default: no)
|
(default: no)
|
||||||
@ -236,10 +236,6 @@ The author of the Silk icon set is Mark James.
|
|||||||
Quality options (slower slicing):
|
Quality options (slower slicing):
|
||||||
--extra-perimeters Add more perimeters when needed (default: yes)
|
--extra-perimeters Add more perimeters when needed (default: yes)
|
||||||
--avoid-crossing-perimeters Optimize travel moves so that no perimeters are crossed (default: no)
|
--avoid-crossing-perimeters Optimize travel moves so that no perimeters are crossed (default: no)
|
||||||
--start-perimeters-at-concave-points
|
|
||||||
Try to start perimeters at concave points if any (default: no)
|
|
||||||
--start-perimeters-at-non-overhang
|
|
||||||
Try to start perimeters at non-overhang points if any (default: no)
|
|
||||||
--thin-walls Detect single-width walls (default: yes)
|
--thin-walls Detect single-width walls (default: yes)
|
||||||
--overhangs Experimental option to use bridge flow, speed and fan for overhangs
|
--overhangs Experimental option to use bridge flow, speed and fan for overhangs
|
||||||
(default: yes)
|
(default: yes)
|
||||||
|
@ -8,7 +8,8 @@ use List::Util qw(first max);
|
|||||||
# cemetery of old config settings
|
# cemetery of old config settings
|
||||||
our @Ignore = qw(duplicate_x duplicate_y multiply_x multiply_y support_material_tool acceleration
|
our @Ignore = qw(duplicate_x duplicate_y multiply_x multiply_y support_material_tool acceleration
|
||||||
adjust_overhang_flow standby_temperature scale rotate duplicate duplicate_grid
|
adjust_overhang_flow standby_temperature scale rotate duplicate duplicate_grid
|
||||||
rotate scale duplicate_grid);
|
rotate scale duplicate_grid start_perimeters_at_concave_points start_perimeters_at_non_overhang
|
||||||
|
randomize_start);
|
||||||
|
|
||||||
our $Options = print_config_def();
|
our $Options = print_config_def();
|
||||||
|
|
||||||
@ -140,6 +141,10 @@ sub _handle_legacy {
|
|||||||
$value *= 100;
|
$value *= 100;
|
||||||
$value = "$value"; # force update of the PV value, workaround for bug https://rt.cpan.org/Ticket/Display.html?id=94110
|
$value = "$value"; # force update of the PV value, workaround for bug https://rt.cpan.org/Ticket/Display.html?id=94110
|
||||||
}
|
}
|
||||||
|
if ($opt_key eq 'randomize_start' && $value) {
|
||||||
|
$opt_key = 'seal_position';
|
||||||
|
$value = 'random';
|
||||||
|
}
|
||||||
|
|
||||||
# For historical reasons, the world's full of configs having these very low values;
|
# For historical reasons, the world's full of configs having these very low values;
|
||||||
# to avoid unexpected behavior we need to ignore them. Banning these two hard-coded
|
# to avoid unexpected behavior we need to ignore them. Banning these two hard-coded
|
||||||
|
@ -19,6 +19,7 @@ has '_layer_index' => (is => 'rw', default => sub {-1}); # just a counter
|
|||||||
has 'layer' => (is => 'rw');
|
has 'layer' => (is => 'rw');
|
||||||
has '_layer_islands' => (is => 'rw');
|
has '_layer_islands' => (is => 'rw');
|
||||||
has '_upper_layer_islands' => (is => 'rw');
|
has '_upper_layer_islands' => (is => 'rw');
|
||||||
|
has '_seal_position' => (is => 'ro', default => sub { {} }); # $object => pos
|
||||||
has 'shift_x' => (is => 'rw', default => sub {0} );
|
has 'shift_x' => (is => 'rw', default => sub {0} );
|
||||||
has 'shift_y' => (is => 'rw', default => sub {0} );
|
has 'shift_y' => (is => 'rw', default => sub {0} );
|
||||||
has 'z' => (is => 'rw');
|
has 'z' => (is => 'rw');
|
||||||
@ -150,45 +151,37 @@ sub extrude_loop {
|
|||||||
# extrude all loops ccw
|
# extrude all loops ccw
|
||||||
my $was_clockwise = $loop->make_counter_clockwise;
|
my $was_clockwise = $loop->make_counter_clockwise;
|
||||||
|
|
||||||
# find candidate starting points
|
|
||||||
# start looking for concave vertices not being overhangs
|
|
||||||
my $polygon = $loop->polygon;
|
|
||||||
my @concave = ();
|
|
||||||
if ($self->config->start_perimeters_at_concave_points) {
|
|
||||||
@concave = $polygon->concave_points;
|
|
||||||
}
|
|
||||||
my @candidates = ();
|
|
||||||
if ($self->config->start_perimeters_at_non_overhang) {
|
|
||||||
@candidates = grep !$loop->has_overhang_point($_), @concave;
|
|
||||||
}
|
|
||||||
if (!@candidates) {
|
|
||||||
# if none, look for any concave vertex
|
|
||||||
@candidates = @concave;
|
|
||||||
if (!@candidates) {
|
|
||||||
# if none, look for any non-overhang vertex
|
|
||||||
if ($self->config->start_perimeters_at_non_overhang) {
|
|
||||||
@candidates = grep !$loop->has_overhang_point($_), @$polygon;
|
|
||||||
}
|
|
||||||
if (!@candidates) {
|
|
||||||
# if none, all points are valid candidates
|
|
||||||
@candidates = @$polygon;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# find the point of the loop that is closest to the current extruder position
|
# find the point of the loop that is closest to the current extruder position
|
||||||
# or randomize if requested
|
# or randomize if requested
|
||||||
my $last_pos = $self->last_pos;
|
my $last_pos = $self->last_pos;
|
||||||
if ($self->config->randomize_start && $loop->role == EXTRL_ROLE_CONTOUR_INTERNAL_PERIMETER) {
|
|
||||||
$last_pos = Slic3r::Point->new(scale $self->config->print_center->[X], scale $self->config->bed_size->[Y]);
|
|
||||||
$last_pos->rotate(rand(2*PI), $self->config->print_center);
|
|
||||||
}
|
|
||||||
|
|
||||||
# split the loop at the starting point
|
|
||||||
if ($self->config->spiral_vase) {
|
if ($self->config->spiral_vase) {
|
||||||
$loop->split_at($last_pos);
|
$loop->split_at($last_pos);
|
||||||
} else {
|
} elsif ($self->config->seal_position eq 'nearest' || $self->config->seal_position eq 'aligned') {
|
||||||
$loop->split_at_vertex($last_pos->nearest_point(\@candidates));
|
my $polygon = $loop->polygon;
|
||||||
|
my @candidates = @{$polygon->concave_points(PI*4/3)};
|
||||||
|
@candidates = @{$polygon->convex_points(PI*2/3)} if !@candidates;
|
||||||
|
@candidates = @{$polygon} if !@candidates;
|
||||||
|
|
||||||
|
my @non_overhang = grep !$loop->has_overhang_point($_), @candidates;
|
||||||
|
@candidates = @non_overhang if @non_overhang;
|
||||||
|
|
||||||
|
if ($self->config->seal_position eq 'nearest') {
|
||||||
|
$loop->split_at_vertex($last_pos->nearest_point(\@candidates));
|
||||||
|
} elsif ($self->config->seal_position eq 'aligned') {
|
||||||
|
if (defined $self->layer && defined $self->_seal_position->{$self->layer->object}) {
|
||||||
|
$last_pos = $self->_seal_position->{$self->layer->object};
|
||||||
|
}
|
||||||
|
my $point = $self->_seal_position->{$self->layer->object} = $last_pos->nearest_point(\@candidates);
|
||||||
|
$loop->split_at_vertex($point);
|
||||||
|
}
|
||||||
|
} elsif ($self->config->seal_position eq 'random') {
|
||||||
|
if ($loop->role == EXTRL_ROLE_CONTOUR_INTERNAL_PERIMETER) {
|
||||||
|
my $polygon = $loop->polygon;
|
||||||
|
my $centroid = $polygon->centroid;
|
||||||
|
$last_pos = Slic3r::Point->new($polygon->bounding_box->x_max, $centroid->y); #))
|
||||||
|
$last_pos->rotate(rand(2*PI), $centroid);
|
||||||
|
}
|
||||||
|
$loop->split_at($last_pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
# clip the path to avoid the extruder to get exactly on the first point of the loop;
|
# clip the path to avoid the extruder to get exactly on the first point of the loop;
|
||||||
|
@ -417,21 +417,17 @@ sub build {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
title => 'Quality (slower slicing)',
|
title => 'Quality (slower slicing)',
|
||||||
options => [qw(extra_perimeters avoid_crossing_perimeters start_perimeters_at_concave_points start_perimeters_at_non_overhang thin_walls overhangs)],
|
options => [qw(extra_perimeters avoid_crossing_perimeters thin_walls overhangs)],
|
||||||
lines => [
|
lines => [
|
||||||
Slic3r::GUI::OptionsGroup->single_option_line('extra_perimeters'),
|
Slic3r::GUI::OptionsGroup->single_option_line('extra_perimeters'),
|
||||||
Slic3r::GUI::OptionsGroup->single_option_line('avoid_crossing_perimeters'),
|
Slic3r::GUI::OptionsGroup->single_option_line('avoid_crossing_perimeters'),
|
||||||
{
|
|
||||||
label => 'Start perimeters at',
|
|
||||||
options => [qw(start_perimeters_at_concave_points start_perimeters_at_non_overhang)],
|
|
||||||
},
|
|
||||||
Slic3r::GUI::OptionsGroup->single_option_line('thin_walls'),
|
Slic3r::GUI::OptionsGroup->single_option_line('thin_walls'),
|
||||||
Slic3r::GUI::OptionsGroup->single_option_line('overhangs'),
|
Slic3r::GUI::OptionsGroup->single_option_line('overhangs'),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title => 'Advanced',
|
title => 'Advanced',
|
||||||
options => [qw(randomize_start external_perimeters_first)],
|
options => [qw(seal_position external_perimeters_first)],
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
@ -260,12 +260,19 @@ sub make_perimeters {
|
|||||||
|
|
||||||
my $role = EXTR_ROLE_PERIMETER;
|
my $role = EXTR_ROLE_PERIMETER;
|
||||||
my $loop_role = EXTRL_ROLE_DEFAULT;
|
my $loop_role = EXTRL_ROLE_DEFAULT;
|
||||||
if ($is_contour ? $depth == 0 : !@{ $polynode->{children} }) {
|
|
||||||
|
my $root_level = $depth == 0;
|
||||||
|
my $no_children = !@{ $polynode->{children} };
|
||||||
|
my $is_external = $is_contour ? $root_level : $no_children;
|
||||||
|
my $is_internal = $is_contour ? $no_children : $root_level;
|
||||||
|
if ($is_external) {
|
||||||
# external perimeters are root level in case of contours
|
# external perimeters are root level in case of contours
|
||||||
# and items with no children in case of holes
|
# and items with no children in case of holes
|
||||||
$role = EXTR_ROLE_EXTERNAL_PERIMETER;
|
$role = EXTR_ROLE_EXTERNAL_PERIMETER;
|
||||||
$loop_role = EXTRL_ROLE_EXTERNAL_PERIMETER;
|
$loop_role = EXTRL_ROLE_EXTERNAL_PERIMETER;
|
||||||
} elsif ($depth == 1 && $is_contour) {
|
} elsif ($is_contour && $is_internal) {
|
||||||
|
# internal perimeters are root level in case of holes
|
||||||
|
# and items with no children in case of contours
|
||||||
$loop_role = EXTRL_ROLE_CONTOUR_INTERNAL_PERIMETER;
|
$loop_role = EXTRL_ROLE_CONTOUR_INTERNAL_PERIMETER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,15 +40,34 @@ sub subdivide {
|
|||||||
return Slic3r::Polygon->new(@new_points);
|
return Slic3r::Polygon->new(@new_points);
|
||||||
}
|
}
|
||||||
|
|
||||||
# for cw polygons this will return convex points!
|
# angle is checked on the internal side of the polygon
|
||||||
sub concave_points {
|
sub concave_points {
|
||||||
my $self = shift;
|
my ($self, $angle) = @_;
|
||||||
|
|
||||||
|
$angle //= PI;
|
||||||
|
|
||||||
my @points = @$self;
|
my @points = @$self;
|
||||||
my @points_pp = @{$self->pp};
|
my @points_pp = @{$self->pp};
|
||||||
return map $points[$_],
|
return [
|
||||||
grep Slic3r::Geometry::angle3points(@points_pp[$_, $_-1, $_+1]) < PI - epsilon,
|
map $points[$_],
|
||||||
-1 .. ($#points-1);
|
grep Slic3r::Geometry::angle3points(@points_pp[$_, $_-1, $_+1]) < $angle,
|
||||||
|
-1 .. ($#points-1)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
# angle is checked on the internal side of the polygon
|
||||||
|
sub convex_points {
|
||||||
|
my ($self, $angle) = @_;
|
||||||
|
|
||||||
|
$angle //= PI;
|
||||||
|
|
||||||
|
my @points = @$self;
|
||||||
|
my @points_pp = @{$self->pp};
|
||||||
|
return [
|
||||||
|
map $points[$_],
|
||||||
|
grep Slic3r::Geometry::angle3points(@points_pp[$_, $_-1, $_+1]) > $angle,
|
||||||
|
-1 .. ($#points-1)
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
@ -3,7 +3,7 @@ use strict;
|
|||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
use List::Util qw(first);
|
use List::Util qw(first);
|
||||||
use Slic3r::Geometry qw(X Y epsilon);
|
use Slic3r::Geometry qw(X Y PI epsilon);
|
||||||
use Slic3r::Geometry::Clipper qw(JT_SQUARE);
|
use Slic3r::Geometry::Clipper qw(JT_SQUARE);
|
||||||
|
|
||||||
sub new_scale {
|
sub new_scale {
|
||||||
|
@ -342,7 +342,7 @@ $j
|
|||||||
home X axis [G28 X], disable motors [M84]).
|
home X axis [G28 X], disable motors [M84]).
|
||||||
--layer-gcode Load layer-change G-code from the supplied file (default: nothing).
|
--layer-gcode Load layer-change G-code from the supplied file (default: nothing).
|
||||||
--toolchange-gcode Load tool-change G-code from the supplied file (default: nothing).
|
--toolchange-gcode Load tool-change G-code from the supplied file (default: nothing).
|
||||||
--randomize-start Randomize starting point across layers (default: yes)
|
--seal-position Position of loop starting points (random/nearest/aligned, default: $config->{seal_position}).
|
||||||
--external-perimeters-first Reverse perimeter order. (default: no)
|
--external-perimeters-first Reverse perimeter order. (default: no)
|
||||||
--spiral-vase Experimental option to raise Z gradually when printing single-walled vases
|
--spiral-vase Experimental option to raise Z gradually when printing single-walled vases
|
||||||
(default: no)
|
(default: no)
|
||||||
@ -359,10 +359,6 @@ $j
|
|||||||
Quality options (slower slicing):
|
Quality options (slower slicing):
|
||||||
--extra-perimeters Add more perimeters when needed (default: yes)
|
--extra-perimeters Add more perimeters when needed (default: yes)
|
||||||
--avoid-crossing-perimeters Optimize travel moves so that no perimeters are crossed (default: no)
|
--avoid-crossing-perimeters Optimize travel moves so that no perimeters are crossed (default: no)
|
||||||
--start-perimeters-at-concave-points
|
|
||||||
Try to start perimeters at concave points if any (default: no)
|
|
||||||
--start-perimeters-at-non-overhang
|
|
||||||
Try to start perimeters at non-overhang points if any (default: no)
|
|
||||||
--thin-walls Detect single-width walls (default: yes)
|
--thin-walls Detect single-width walls (default: yes)
|
||||||
--overhangs Experimental option to use bridge flow, speed and fan for overhangs
|
--overhangs Experimental option to use bridge flow, speed and fan for overhangs
|
||||||
(default: yes)
|
(default: yes)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use Test::More tests => 10;
|
use Test::More tests => 9;
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
@ -85,28 +85,6 @@ use Slic3r::Test;
|
|||||||
ok !$has_outwards_move, 'move inwards after completing external loop';
|
ok !$has_outwards_move, 'move inwards after completing external loop';
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
|
||||||
$config->set('start_perimeters_at_concave_points', 1);
|
|
||||||
my $print = Slic3r::Test::init_print('L', config => $config);
|
|
||||||
my $loop_starts_from_convex_point = 0;
|
|
||||||
my $cur_loop;
|
|
||||||
Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub {
|
|
||||||
my ($self, $cmd, $args, $info) = @_;
|
|
||||||
|
|
||||||
if ($info->{extruding} && $info->{dist_XY} > 0) {
|
|
||||||
$cur_loop ||= [ [$self->X, $self->Y] ];
|
|
||||||
push @$cur_loop, [ @$info{qw(new_X new_Y)} ];
|
|
||||||
} else {
|
|
||||||
if ($cur_loop) {
|
|
||||||
$loop_starts_from_convex_point = 1
|
|
||||||
if Slic3r::Geometry::angle3points(@$cur_loop[0,-1,1]) >= PI;
|
|
||||||
$cur_loop = undef;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
ok !$loop_starts_from_convex_point, 'avoid starting from convex points';
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
$config->set('perimeters', 1);
|
$config->set('perimeters', 1);
|
||||||
$config->set('perimeter_speed', 77);
|
$config->set('perimeter_speed', 77);
|
||||||
@ -267,9 +245,9 @@ use Slic3r::Test;
|
|||||||
|
|
||||||
{
|
{
|
||||||
my $config = Slic3r::Config->new_from_defaults;
|
my $config = Slic3r::Config->new_from_defaults;
|
||||||
$config->set('randomize_start', 1);
|
$config->set('seal_position', 'random');
|
||||||
my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
|
my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
|
||||||
ok Slic3r::Test::gcode($print), 'successful generation of G-code with randomize_start option';
|
ok Slic3r::Test::gcode($print), 'successful generation of G-code with seal_position = random';
|
||||||
}
|
}
|
||||||
|
|
||||||
__END__
|
__END__
|
||||||
|
@ -1,7 +1,13 @@
|
|||||||
#include "MultiPoint.hpp"
|
#include "MultiPoint.hpp"
|
||||||
|
#include "BoundingBox.hpp"
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
|
MultiPoint::operator Points() const
|
||||||
|
{
|
||||||
|
return this->points;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MultiPoint::scale(double factor)
|
MultiPoint::scale(double factor)
|
||||||
{
|
{
|
||||||
@ -64,6 +70,12 @@ MultiPoint::find_point(const Point &point) const
|
|||||||
return -1; // not found
|
return -1; // not found
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MultiPoint::bounding_box(BoundingBox* bb) const
|
||||||
|
{
|
||||||
|
*bb = BoundingBox(this->points);
|
||||||
|
}
|
||||||
|
|
||||||
Points
|
Points
|
||||||
MultiPoint::_douglas_peucker(const Points &points, const double tolerance)
|
MultiPoint::_douglas_peucker(const Points &points, const double tolerance)
|
||||||
{
|
{
|
||||||
|
@ -2,17 +2,21 @@
|
|||||||
#define slic3r_MultiPoint_hpp_
|
#define slic3r_MultiPoint_hpp_
|
||||||
|
|
||||||
#include <myinit.h>
|
#include <myinit.h>
|
||||||
#include "Line.hpp"
|
|
||||||
#include "Point.hpp"
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include "Line.hpp"
|
||||||
|
#include "Point.hpp"
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
|
class BoundingBox;
|
||||||
|
|
||||||
class MultiPoint
|
class MultiPoint
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Points points;
|
Points points;
|
||||||
|
|
||||||
|
operator Points() const;
|
||||||
void scale(double factor);
|
void scale(double factor);
|
||||||
void translate(double x, double y);
|
void translate(double x, double y);
|
||||||
void rotate(double angle, const Point ¢er);
|
void rotate(double angle, const Point ¢er);
|
||||||
@ -23,6 +27,8 @@ class MultiPoint
|
|||||||
double length() const;
|
double length() const;
|
||||||
bool is_valid() const;
|
bool is_valid() const;
|
||||||
int find_point(const Point &point) const;
|
int find_point(const Point &point) const;
|
||||||
|
void bounding_box(BoundingBox* bb) const;
|
||||||
|
|
||||||
static Points _douglas_peucker(const Points &points, const double tolerance);
|
static Points _douglas_peucker(const Points &points, const double tolerance);
|
||||||
|
|
||||||
#ifdef SLIC3RXS
|
#ifdef SLIC3RXS
|
||||||
|
@ -191,6 +191,24 @@ Polygon::triangulate_convex(Polygons* polygons) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// center of mass
|
||||||
|
Point
|
||||||
|
Polygon::centroid() const
|
||||||
|
{
|
||||||
|
double area_temp = this->area();
|
||||||
|
double x_temp = 0;
|
||||||
|
double y_temp = 0;
|
||||||
|
|
||||||
|
Polyline polyline;
|
||||||
|
this->split_at_first_point(&polyline);
|
||||||
|
for (Points::const_iterator point = polyline.points.begin(); point != polyline.points.end() - 1; ++point) {
|
||||||
|
x_temp += (double)( point->x + (point+1)->x ) * ( (double)point->x*(point+1)->y - (double)(point+1)->x*point->y );
|
||||||
|
y_temp += (double)( point->y + (point+1)->y ) * ( (double)point->x*(point+1)->y - (double)(point+1)->x*point->y );
|
||||||
|
}
|
||||||
|
|
||||||
|
return Point(x_temp/(6*area_temp), y_temp/(6*area_temp));
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef SLIC3RXS
|
#ifdef SLIC3RXS
|
||||||
REGISTER_CLASS(Polygon, "Polygon");
|
REGISTER_CLASS(Polygon, "Polygon");
|
||||||
|
|
||||||
|
@ -35,6 +35,7 @@ class Polygon : public MultiPoint {
|
|||||||
Polygons simplify(double tolerance) const;
|
Polygons simplify(double tolerance) const;
|
||||||
void simplify(double tolerance, Polygons &polygons) const;
|
void simplify(double tolerance, Polygons &polygons) const;
|
||||||
void triangulate_convex(Polygons* polygons) const;
|
void triangulate_convex(Polygons* polygons) const;
|
||||||
|
Point centroid() const;
|
||||||
|
|
||||||
#ifdef SLIC3RXS
|
#ifdef SLIC3RXS
|
||||||
void from_SV_check(SV* poly_sv);
|
void from_SV_check(SV* poly_sv);
|
||||||
|
@ -18,6 +18,10 @@ enum SupportMaterialPattern {
|
|||||||
smpRectilinear, smpRectilinearGrid, smpHoneycomb, smpPillars,
|
smpRectilinear, smpRectilinearGrid, smpHoneycomb, smpPillars,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum SealPosition {
|
||||||
|
spRandom, spNearest, spAligned
|
||||||
|
};
|
||||||
|
|
||||||
template<> inline t_config_enum_values ConfigOptionEnum<GCodeFlavor>::get_enum_values() {
|
template<> inline t_config_enum_values ConfigOptionEnum<GCodeFlavor>::get_enum_values() {
|
||||||
t_config_enum_values keys_map;
|
t_config_enum_values keys_map;
|
||||||
keys_map["reprap"] = gcfRepRap;
|
keys_map["reprap"] = gcfRepRap;
|
||||||
@ -50,6 +54,14 @@ template<> inline t_config_enum_values ConfigOptionEnum<SupportMaterialPattern>:
|
|||||||
return keys_map;
|
return keys_map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<> inline t_config_enum_values ConfigOptionEnum<SealPosition>::get_enum_values() {
|
||||||
|
t_config_enum_values keys_map;
|
||||||
|
keys_map["random"] = spRandom;
|
||||||
|
keys_map["nearest"] = spNearest;
|
||||||
|
keys_map["aligned"] = spAligned;
|
||||||
|
return keys_map;
|
||||||
|
}
|
||||||
|
|
||||||
class PrintConfigDef
|
class PrintConfigDef
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -584,11 +596,6 @@ class PrintConfigDef
|
|||||||
Options["raft_layers"].sidetext = "layers";
|
Options["raft_layers"].sidetext = "layers";
|
||||||
Options["raft_layers"].cli = "raft-layers=i";
|
Options["raft_layers"].cli = "raft-layers=i";
|
||||||
|
|
||||||
Options["randomize_start"].type = coBool;
|
|
||||||
Options["randomize_start"].label = "Randomize starting points";
|
|
||||||
Options["randomize_start"].tooltip = "Start each layer from a different vertex to prevent plastic build-up on the same corner.";
|
|
||||||
Options["randomize_start"].cli = "randomize-start!";
|
|
||||||
|
|
||||||
Options["resolution"].type = coFloat;
|
Options["resolution"].type = coFloat;
|
||||||
Options["resolution"].label = "Resolution";
|
Options["resolution"].label = "Resolution";
|
||||||
Options["resolution"].tooltip = "Minimum detail resolution, used to simplify the input file for speeding up the slicing job and reducing memory usage. High-resolution models often carry more detail than printers can render. Set to zero to disable any simplification and use full resolution from input.";
|
Options["resolution"].tooltip = "Minimum detail resolution, used to simplify the input file for speeding up the slicing job and reducing memory usage. High-resolution models often carry more detail than printers can render. Set to zero to disable any simplification and use full resolution from input.";
|
||||||
@ -644,6 +651,19 @@ class PrintConfigDef
|
|||||||
Options["retract_speed"].cli = "retract-speed=f@";
|
Options["retract_speed"].cli = "retract-speed=f@";
|
||||||
Options["retract_speed"].max = 1000;
|
Options["retract_speed"].max = 1000;
|
||||||
|
|
||||||
|
Options["seal_position"].type = coEnum;
|
||||||
|
Options["seal_position"].label = "Seal position";
|
||||||
|
Options["seal_position"].category = "Layers and perimeters";
|
||||||
|
Options["seal_position"].tooltip = "Position of perimeters starting points.";
|
||||||
|
Options["seal_position"].cli = "seal-position=s";
|
||||||
|
Options["seal_position"].enum_keys_map = ConfigOptionEnum<SealPosition>::get_enum_values();
|
||||||
|
Options["seal_position"].enum_values.push_back("random");
|
||||||
|
Options["seal_position"].enum_values.push_back("nearest");
|
||||||
|
Options["seal_position"].enum_values.push_back("aligned");
|
||||||
|
Options["seal_position"].enum_labels.push_back("Random");
|
||||||
|
Options["seal_position"].enum_labels.push_back("Nearest");
|
||||||
|
Options["seal_position"].enum_labels.push_back("Aligned");
|
||||||
|
|
||||||
Options["skirt_distance"].type = coFloat;
|
Options["skirt_distance"].type = coFloat;
|
||||||
Options["skirt_distance"].label = "Distance from object";
|
Options["skirt_distance"].label = "Distance from object";
|
||||||
Options["skirt_distance"].tooltip = "Distance between skirt and object(s). Set this to zero to attach the skirt to the object(s) and get a brim for better adhesion.";
|
Options["skirt_distance"].tooltip = "Distance between skirt and object(s). Set this to zero to attach the skirt to the object(s) and get a brim for better adhesion.";
|
||||||
@ -753,16 +773,6 @@ class PrintConfigDef
|
|||||||
Options["start_gcode"].full_width = true;
|
Options["start_gcode"].full_width = true;
|
||||||
Options["start_gcode"].height = 120;
|
Options["start_gcode"].height = 120;
|
||||||
|
|
||||||
Options["start_perimeters_at_concave_points"].type = coBool;
|
|
||||||
Options["start_perimeters_at_concave_points"].label = "Concave points";
|
|
||||||
Options["start_perimeters_at_concave_points"].tooltip = "Prefer to start perimeters at a concave point.";
|
|
||||||
Options["start_perimeters_at_concave_points"].cli = "start-perimeters-at-concave-points!";
|
|
||||||
|
|
||||||
Options["start_perimeters_at_non_overhang"].type = coBool;
|
|
||||||
Options["start_perimeters_at_non_overhang"].label = "Non-overhang points";
|
|
||||||
Options["start_perimeters_at_non_overhang"].tooltip = "Prefer to start perimeters at non-overhanging points.";
|
|
||||||
Options["start_perimeters_at_non_overhang"].cli = "start-perimeters-at-non-overhang!";
|
|
||||||
|
|
||||||
Options["support_material"].type = coBool;
|
Options["support_material"].type = coBool;
|
||||||
Options["support_material"].label = "Generate support material";
|
Options["support_material"].label = "Generate support material";
|
||||||
Options["support_material"].category = "Support material";
|
Options["support_material"].category = "Support material";
|
||||||
@ -996,6 +1006,7 @@ class PrintObjectConfig : public virtual StaticPrintConfig
|
|||||||
ConfigOptionBool interface_shells;
|
ConfigOptionBool interface_shells;
|
||||||
ConfigOptionFloat layer_height;
|
ConfigOptionFloat layer_height;
|
||||||
ConfigOptionInt raft_layers;
|
ConfigOptionInt raft_layers;
|
||||||
|
ConfigOptionEnum<SealPosition> seal_position;
|
||||||
ConfigOptionBool support_material;
|
ConfigOptionBool support_material;
|
||||||
ConfigOptionInt support_material_angle;
|
ConfigOptionInt support_material_angle;
|
||||||
ConfigOptionInt support_material_enforce_layers;
|
ConfigOptionInt support_material_enforce_layers;
|
||||||
@ -1020,6 +1031,7 @@ class PrintObjectConfig : public virtual StaticPrintConfig
|
|||||||
this->interface_shells.value = false;
|
this->interface_shells.value = false;
|
||||||
this->layer_height.value = 0.4;
|
this->layer_height.value = 0.4;
|
||||||
this->raft_layers.value = 0;
|
this->raft_layers.value = 0;
|
||||||
|
this->seal_position.value = spAligned;
|
||||||
this->support_material.value = false;
|
this->support_material.value = false;
|
||||||
this->support_material_angle.value = 0;
|
this->support_material_angle.value = 0;
|
||||||
this->support_material_enforce_layers.value = 0;
|
this->support_material_enforce_layers.value = 0;
|
||||||
@ -1045,6 +1057,7 @@ class PrintObjectConfig : public virtual StaticPrintConfig
|
|||||||
if (opt_key == "interface_shells") return &this->interface_shells;
|
if (opt_key == "interface_shells") return &this->interface_shells;
|
||||||
if (opt_key == "layer_height") return &this->layer_height;
|
if (opt_key == "layer_height") return &this->layer_height;
|
||||||
if (opt_key == "raft_layers") return &this->raft_layers;
|
if (opt_key == "raft_layers") return &this->raft_layers;
|
||||||
|
if (opt_key == "seal_position") return &this->seal_position;
|
||||||
if (opt_key == "support_material") return &this->support_material;
|
if (opt_key == "support_material") return &this->support_material;
|
||||||
if (opt_key == "support_material_angle") return &this->support_material_angle;
|
if (opt_key == "support_material_angle") return &this->support_material_angle;
|
||||||
if (opt_key == "support_material_enforce_layers") return &this->support_material_enforce_layers;
|
if (opt_key == "support_material_enforce_layers") return &this->support_material_enforce_layers;
|
||||||
@ -1214,7 +1227,6 @@ class PrintConfig : public virtual StaticPrintConfig
|
|||||||
ConfigOptionFloat perimeter_acceleration;
|
ConfigOptionFloat perimeter_acceleration;
|
||||||
ConfigOptionStrings post_process;
|
ConfigOptionStrings post_process;
|
||||||
ConfigOptionPoint print_center;
|
ConfigOptionPoint print_center;
|
||||||
ConfigOptionBool randomize_start;
|
|
||||||
ConfigOptionFloat resolution;
|
ConfigOptionFloat resolution;
|
||||||
ConfigOptionFloats retract_before_travel;
|
ConfigOptionFloats retract_before_travel;
|
||||||
ConfigOptionBools retract_layer_change;
|
ConfigOptionBools retract_layer_change;
|
||||||
@ -1231,8 +1243,6 @@ class PrintConfig : public virtual StaticPrintConfig
|
|||||||
ConfigOptionBool spiral_vase;
|
ConfigOptionBool spiral_vase;
|
||||||
ConfigOptionInt standby_temperature_delta;
|
ConfigOptionInt standby_temperature_delta;
|
||||||
ConfigOptionString start_gcode;
|
ConfigOptionString start_gcode;
|
||||||
ConfigOptionBool start_perimeters_at_concave_points;
|
|
||||||
ConfigOptionBool start_perimeters_at_non_overhang;
|
|
||||||
ConfigOptionInts temperature;
|
ConfigOptionInts temperature;
|
||||||
ConfigOptionInt threads;
|
ConfigOptionInt threads;
|
||||||
ConfigOptionString toolchange_gcode;
|
ConfigOptionString toolchange_gcode;
|
||||||
@ -1296,7 +1306,6 @@ class PrintConfig : public virtual StaticPrintConfig
|
|||||||
this->output_filename_format.value = "[input_filename_base].gcode";
|
this->output_filename_format.value = "[input_filename_base].gcode";
|
||||||
this->perimeter_acceleration.value = 0;
|
this->perimeter_acceleration.value = 0;
|
||||||
this->print_center.point = Pointf(100,100);
|
this->print_center.point = Pointf(100,100);
|
||||||
this->randomize_start.value = false;
|
|
||||||
this->resolution.value = 0;
|
this->resolution.value = 0;
|
||||||
this->retract_before_travel.values.resize(1);
|
this->retract_before_travel.values.resize(1);
|
||||||
this->retract_before_travel.values[0] = 2;
|
this->retract_before_travel.values[0] = 2;
|
||||||
@ -1321,8 +1330,6 @@ class PrintConfig : public virtual StaticPrintConfig
|
|||||||
this->spiral_vase.value = false;
|
this->spiral_vase.value = false;
|
||||||
this->standby_temperature_delta.value = -5;
|
this->standby_temperature_delta.value = -5;
|
||||||
this->start_gcode.value = "G28 ; home all axes\nG1 Z5 F5000 ; lift nozzle\n";
|
this->start_gcode.value = "G28 ; home all axes\nG1 Z5 F5000 ; lift nozzle\n";
|
||||||
this->start_perimeters_at_concave_points.value = false;
|
|
||||||
this->start_perimeters_at_non_overhang.value = false;
|
|
||||||
this->temperature.values.resize(1);
|
this->temperature.values.resize(1);
|
||||||
this->temperature.values[0] = 200;
|
this->temperature.values[0] = 200;
|
||||||
this->threads.value = 2;
|
this->threads.value = 2;
|
||||||
@ -1383,7 +1390,6 @@ class PrintConfig : public virtual StaticPrintConfig
|
|||||||
if (opt_key == "perimeter_acceleration") return &this->perimeter_acceleration;
|
if (opt_key == "perimeter_acceleration") return &this->perimeter_acceleration;
|
||||||
if (opt_key == "post_process") return &this->post_process;
|
if (opt_key == "post_process") return &this->post_process;
|
||||||
if (opt_key == "print_center") return &this->print_center;
|
if (opt_key == "print_center") return &this->print_center;
|
||||||
if (opt_key == "randomize_start") return &this->randomize_start;
|
|
||||||
if (opt_key == "resolution") return &this->resolution;
|
if (opt_key == "resolution") return &this->resolution;
|
||||||
if (opt_key == "retract_before_travel") return &this->retract_before_travel;
|
if (opt_key == "retract_before_travel") return &this->retract_before_travel;
|
||||||
if (opt_key == "retract_layer_change") return &this->retract_layer_change;
|
if (opt_key == "retract_layer_change") return &this->retract_layer_change;
|
||||||
@ -1400,8 +1406,6 @@ class PrintConfig : public virtual StaticPrintConfig
|
|||||||
if (opt_key == "spiral_vase") return &this->spiral_vase;
|
if (opt_key == "spiral_vase") return &this->spiral_vase;
|
||||||
if (opt_key == "standby_temperature_delta") return &this->standby_temperature_delta;
|
if (opt_key == "standby_temperature_delta") return &this->standby_temperature_delta;
|
||||||
if (opt_key == "start_gcode") return &this->start_gcode;
|
if (opt_key == "start_gcode") return &this->start_gcode;
|
||||||
if (opt_key == "start_perimeters_at_concave_points") return &this->start_perimeters_at_concave_points;
|
|
||||||
if (opt_key == "start_perimeters_at_non_overhang") return &this->start_perimeters_at_non_overhang;
|
|
||||||
if (opt_key == "temperature") return &this->temperature;
|
if (opt_key == "temperature") return &this->temperature;
|
||||||
if (opt_key == "threads") return &this->threads;
|
if (opt_key == "threads") return &this->threads;
|
||||||
if (opt_key == "toolchange_gcode") return &this->toolchange_gcode;
|
if (opt_key == "toolchange_gcode") return &this->toolchange_gcode;
|
||||||
|
@ -5,7 +5,7 @@ use warnings;
|
|||||||
|
|
||||||
use List::Util qw(first);
|
use List::Util qw(first);
|
||||||
use Slic3r::XS;
|
use Slic3r::XS;
|
||||||
use Test::More tests => 19;
|
use Test::More tests => 20;
|
||||||
|
|
||||||
use constant PI => 4 * atan2(1, 1);
|
use constant PI => 4 * atan2(1, 1);
|
||||||
|
|
||||||
@ -69,6 +69,10 @@ ok $cw_polygon->contains_point(Slic3r::Point->new(150,150)), 'cw contains_point'
|
|||||||
ok !(defined first { $_->is_clockwise } @$triangles), 'all triangles are ccw';
|
ok !(defined first { $_->is_clockwise } @$triangles), 'all triangles are ccw';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
is_deeply $polygon->centroid->pp, [150,150], 'centroid';
|
||||||
|
}
|
||||||
|
|
||||||
# this is not a test: this just demonstrates bad usage, where $polygon->clone gets
|
# this is not a test: this just demonstrates bad usage, where $polygon->clone gets
|
||||||
# DESTROY'ed before the derived object ($point), causing bad memory access
|
# DESTROY'ed before the derived object ($point), causing bad memory access
|
||||||
if (0) {
|
if (0) {
|
||||||
|
@ -64,7 +64,7 @@ _constant()
|
|||||||
ALIAS:
|
ALIAS:
|
||||||
EXTRL_ROLE_DEFAULT = elrDefault
|
EXTRL_ROLE_DEFAULT = elrDefault
|
||||||
EXTRL_ROLE_EXTERNAL_PERIMETER = elrExternalPerimeter
|
EXTRL_ROLE_EXTERNAL_PERIMETER = elrExternalPerimeter
|
||||||
EXTRL_ROLE_CONTOUR_INTERNAL_PERIMETER = erInternalInfill
|
EXTRL_ROLE_CONTOUR_INTERNAL_PERIMETER = elrContourInternalPerimeter
|
||||||
PROTOTYPE:
|
PROTOTYPE:
|
||||||
CODE:
|
CODE:
|
||||||
RETVAL = ix;
|
RETVAL = ix;
|
||||||
|
@ -38,6 +38,12 @@
|
|||||||
Polygons simplify(double tolerance);
|
Polygons simplify(double tolerance);
|
||||||
Polygons triangulate_convex()
|
Polygons triangulate_convex()
|
||||||
%code{% THIS->triangulate_convex(&RETVAL); %};
|
%code{% THIS->triangulate_convex(&RETVAL); %};
|
||||||
|
Clone<Point> centroid();
|
||||||
|
BoundingBox* bounding_box()
|
||||||
|
%code{%
|
||||||
|
RETVAL = new BoundingBox();
|
||||||
|
THIS->bounding_box(RETVAL);
|
||||||
|
%};
|
||||||
%{
|
%{
|
||||||
|
|
||||||
Polygon*
|
Polygon*
|
||||||
|
Loading…
Reference in New Issue
Block a user