Merge branch 'master' into dynamic-flow
This commit is contained in:
commit
19e77a28a1
2
Build.PL
2
Build.PL
@ -12,7 +12,7 @@ my $build = Module::Build->new(
|
|||||||
'File::Spec' => '0',
|
'File::Spec' => '0',
|
||||||
'Getopt::Long' => '0',
|
'Getopt::Long' => '0',
|
||||||
'Math::Clipper' => '1.09',
|
'Math::Clipper' => '1.09',
|
||||||
'Math::ConvexHull' => '1.0.4',
|
'Math::ConvexHull::MonotoneChain' => '0.01',
|
||||||
'Math::Geometry::Voronoi' => '1.3',
|
'Math::Geometry::Voronoi' => '1.3',
|
||||||
'Math::PlanePath' => '53',
|
'Math::PlanePath' => '53',
|
||||||
'Moo' => '0.091009',
|
'Moo' => '0.091009',
|
||||||
|
@ -66,6 +66,7 @@ use constant SMALL_PERIMETER_LENGTH => (6.5 / SCALING_FACTOR) * 2 * PI;
|
|||||||
# them here because it makes accessing them slightly faster.
|
# them here because it makes accessing them slightly faster.
|
||||||
our $Config;
|
our $Config;
|
||||||
our $flow;
|
our $flow;
|
||||||
|
our $first_layer_flow;
|
||||||
|
|
||||||
sub parallelize {
|
sub parallelize {
|
||||||
my %params = @_;
|
my %params = @_;
|
||||||
|
@ -160,6 +160,7 @@ sub detect_arcs {
|
|||||||
|
|
||||||
$max_angle = deg2rad($max_angle || 15);
|
$max_angle = deg2rad($max_angle || 15);
|
||||||
$len_epsilon ||= 10 / &Slic3r::SCALING_FACTOR;
|
$len_epsilon ||= 10 / &Slic3r::SCALING_FACTOR;
|
||||||
|
my $parallel_degrees_limit = abs(Slic3r::Geometry::deg2rad(3));
|
||||||
|
|
||||||
my @points = @{$self->points};
|
my @points = @{$self->points};
|
||||||
my @paths = ();
|
my @paths = ();
|
||||||
@ -191,8 +192,8 @@ sub detect_arcs {
|
|||||||
$s3_angle += 2*PI if $s3_angle < 0;
|
$s3_angle += 2*PI if $s3_angle < 0;
|
||||||
my $s1s2_angle = $s2_angle - $s1_angle;
|
my $s1s2_angle = $s2_angle - $s1_angle;
|
||||||
my $s2s3_angle = $s3_angle - $s2_angle;
|
my $s2s3_angle = $s3_angle - $s2_angle;
|
||||||
next if abs($s1s2_angle - $s2s3_angle) > $Slic3r::Geometry::parallel_degrees_limit;
|
next if abs($s1s2_angle - $s2s3_angle) > $parallel_degrees_limit;
|
||||||
next if abs($s1s2_angle) < $Slic3r::Geometry::parallel_degrees_limit; # ignore parallel lines
|
next if abs($s1s2_angle) < $parallel_degrees_limit; # ignore parallel lines
|
||||||
next if $s1s2_angle > $max_angle; # ignore too sharp vertices
|
next if $s1s2_angle > $max_angle; # ignore too sharp vertices
|
||||||
my @arc_points = ($points[$i], $points[$i+3]), # first and last points
|
my @arc_points = ($points[$i], $points[$i+3]), # first and last points
|
||||||
|
|
||||||
@ -205,7 +206,7 @@ sub detect_arcs {
|
|||||||
my $line_angle = $line->atan;
|
my $line_angle = $line->atan;
|
||||||
$line_angle += 2*PI if $line_angle < 0;
|
$line_angle += 2*PI if $line_angle < 0;
|
||||||
my $anglediff = $line_angle - $last_line_angle;
|
my $anglediff = $line_angle - $last_line_angle;
|
||||||
last if abs($s1s2_angle - $anglediff) > $Slic3r::Geometry::parallel_degrees_limit;
|
last if abs($s1s2_angle - $anglediff) > $parallel_degrees_limit;
|
||||||
|
|
||||||
# point $j+1 belongs to the arc
|
# point $j+1 belongs to the arc
|
||||||
$arc_points[-1] = $points[$j+1];
|
$arc_points[-1] = $points[$j+1];
|
||||||
|
@ -63,7 +63,7 @@ sub fill_surface {
|
|||||||
my $path = $loop->split_at_index($index);
|
my $path = $loop->split_at_index($index);
|
||||||
|
|
||||||
# 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
|
||||||
$path->clip_end($self->layer ? $self->layer->flow->scaled_width : $Slic3r::flow->scaled_width * 0.15);
|
$path->clip_end(($self->layer ? $self->layer->flow->scaled_width : $Slic3r::flow->scaled_width) * 0.15);
|
||||||
|
|
||||||
push @paths, $path->points if @{$path->points};
|
push @paths, $path->points if @{$path->points};
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ sub fill_surface {
|
|||||||
# infill math
|
# infill math
|
||||||
my $min_spacing = scale $params{flow_spacing};
|
my $min_spacing = scale $params{flow_spacing};
|
||||||
my $distance = $min_spacing / $params{density};
|
my $distance = $min_spacing / $params{density};
|
||||||
my $overlap_distance = $self->layer ? $self->layer->flow->scaled_width : $Slic3r::flow->scaled_width * 0.4;
|
my $overlap_distance = ($self->layer ? $self->layer->flow->scaled_width : $Slic3r::flow->scaled_width) * 0.4;
|
||||||
|
|
||||||
my $cache_id = sprintf "d%s_s%s_a%s",
|
my $cache_id = sprintf "d%s_s%s_a%s",
|
||||||
$params{density}, $params{flow_spacing}, $rotate_vector->[0][0];
|
$params{density}, $params{flow_spacing}, $rotate_vector->[0][0];
|
||||||
|
@ -31,7 +31,7 @@ sub fill_surface {
|
|||||||
$flow_spacing = unscale $distance_between_lines;
|
$flow_spacing = unscale $distance_between_lines;
|
||||||
}
|
}
|
||||||
|
|
||||||
my $overlap_distance = $self->layer ? $self->layer->flow->scaled_width : $Slic3r::flow->scaled_width * 0.4;
|
my $overlap_distance = ($self->layer ? $self->layer->flow->scaled_width : $Slic3r::flow->scaled_width) * 0.4;
|
||||||
|
|
||||||
my $x = $bounding_box->[X1];
|
my $x = $bounding_box->[X1];
|
||||||
my $is_line_pattern = $self->isa('Slic3r::Fill::Line');
|
my $is_line_pattern = $self->isa('Slic3r::Fill::Line');
|
||||||
|
@ -421,7 +421,7 @@ sub set_temperature {
|
|||||||
: ('M104', 'set temperature');
|
: ('M104', 'set temperature');
|
||||||
my $gcode = sprintf "$code %s%d %s; $comment\n",
|
my $gcode = sprintf "$code %s%d %s; $comment\n",
|
||||||
($Slic3r::Config->gcode_flavor eq 'mach3' ? 'P' : 'S'), $temperature,
|
($Slic3r::Config->gcode_flavor eq 'mach3' ? 'P' : 'S'), $temperature,
|
||||||
(defined $tool && $tool != $self->extruder->id) ? "T$tool " : "";
|
(defined $tool && $self->multiple_extruders) ? "T$tool " : "";
|
||||||
|
|
||||||
$gcode .= "M116 ; wait for temperature to be reached\n"
|
$gcode .= "M116 ; wait for temperature to be reached\n"
|
||||||
if $Slic3r::Config->gcode_flavor eq 'teacup' && $wait;
|
if $Slic3r::Config->gcode_flavor eq 'teacup' && $wait;
|
||||||
|
@ -5,7 +5,7 @@ use utf8;
|
|||||||
|
|
||||||
use File::Basename qw(basename dirname);
|
use File::Basename qw(basename dirname);
|
||||||
use List::Util qw(max sum);
|
use List::Util qw(max sum);
|
||||||
use Math::ConvexHull qw(convex_hull);
|
use Math::ConvexHull::MonotoneChain qw(convex_hull);
|
||||||
use Slic3r::Geometry qw(X Y Z X1 Y1 X2 Y2 MIN MAX);
|
use Slic3r::Geometry qw(X Y Z X1 Y1 X2 Y2 MIN MAX);
|
||||||
use Slic3r::Geometry::Clipper qw(JT_ROUND);
|
use Slic3r::Geometry::Clipper qw(JT_ROUND);
|
||||||
use threads::shared qw(shared_clone);
|
use threads::shared qw(shared_clone);
|
||||||
@ -301,7 +301,7 @@ sub load_file {
|
|||||||
name => basename($input_file),
|
name => basename($input_file),
|
||||||
input_file => $input_file,
|
input_file => $input_file,
|
||||||
input_file_object_id => $i,
|
input_file_object_id => $i,
|
||||||
mesh => $model->objects->[$i]->mesh,
|
model_object => $model->objects->[$i],
|
||||||
instances => [
|
instances => [
|
||||||
$model->objects->[$i]->instances
|
$model->objects->[$i]->instances
|
||||||
? (map $_->offset, @{$model->objects->[$i]->instances})
|
? (map $_->offset, @{$model->objects->[$i]->instances})
|
||||||
@ -384,6 +384,7 @@ sub decrease {
|
|||||||
my ($obj_idx, $object) = $self->selected_object;
|
my ($obj_idx, $object) = $self->selected_object;
|
||||||
if ($object->instances_count >= 2) {
|
if ($object->instances_count >= 2) {
|
||||||
pop @{$object->instances};
|
pop @{$object->instances};
|
||||||
|
$self->{list}->SetItem($obj_idx, 1, $object->instances_count);
|
||||||
} else {
|
} else {
|
||||||
$self->remove;
|
$self->remove;
|
||||||
}
|
}
|
||||||
@ -454,7 +455,14 @@ sub split_object {
|
|||||||
|
|
||||||
my ($obj_idx, $current_object) = $self->selected_object;
|
my ($obj_idx, $current_object) = $self->selected_object;
|
||||||
my $current_copies_num = $current_object->instances_count;
|
my $current_copies_num = $current_object->instances_count;
|
||||||
my $mesh = $current_object->get_mesh;
|
my $model_object = $current_object->get_model_object;
|
||||||
|
|
||||||
|
if (@{$model_object->volumes} > 1) {
|
||||||
|
Slic3r::GUI::warning_catcher($self)->("The selected object couldn't be splitted because it contains more than one volume/material.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
my $mesh = $model_object->mesh;
|
||||||
$mesh->align_to_origin;
|
$mesh->align_to_origin;
|
||||||
|
|
||||||
my @new_meshes = $mesh->split_mesh;
|
my @new_meshes = $mesh->split_mesh;
|
||||||
@ -668,20 +676,24 @@ sub make_model {
|
|||||||
my $self = shift;
|
my $self = shift;
|
||||||
|
|
||||||
my $model = Slic3r::Model->new;
|
my $model = Slic3r::Model->new;
|
||||||
foreach my $object (@{$self->{objects}}) {
|
foreach my $plater_object (@{$self->{objects}}) {
|
||||||
my $mesh = $object->get_mesh;
|
my $model_object = $plater_object->get_model_object;
|
||||||
$mesh->scale($object->scale);
|
my $new_model_object = $model->add_object(
|
||||||
my $model_object = $model->add_object(
|
vertices => $model_object->vertices,
|
||||||
vertices => $mesh->vertices,
|
input_file => $plater_object->input_file,
|
||||||
input_file => $object->input_file,
|
|
||||||
);
|
);
|
||||||
$model_object->add_volume(
|
foreach my $volume (@{$model_object->volumes}) {
|
||||||
facets => $mesh->facets,
|
$new_model_object->add_volume(
|
||||||
);
|
material_id => $volume->material_id,
|
||||||
$model_object->add_instance(
|
facets => $volume->facets,
|
||||||
rotation => $object->rotate,
|
);
|
||||||
|
$model->materials->{$volume->material_id || 0} ||= {};
|
||||||
|
}
|
||||||
|
$new_model_object->scale($plater_object->scale);
|
||||||
|
$new_model_object->add_instance(
|
||||||
|
rotation => $plater_object->rotate,
|
||||||
offset => [ @$_ ],
|
offset => [ @$_ ],
|
||||||
) for @{$object->instances};
|
) for @{$plater_object->instances};
|
||||||
}
|
}
|
||||||
|
|
||||||
return $model;
|
return $model;
|
||||||
@ -710,7 +722,7 @@ sub on_thumbnail_made {
|
|||||||
my $self = shift;
|
my $self = shift;
|
||||||
my ($obj_idx) = @_;
|
my ($obj_idx) = @_;
|
||||||
|
|
||||||
$self->{objects}[$obj_idx]->free_mesh;
|
$self->{objects}[$obj_idx]->free_model_object;
|
||||||
$self->recenter;
|
$self->recenter;
|
||||||
$self->{canvas}->Refresh;
|
$self->{canvas}->Refresh;
|
||||||
}
|
}
|
||||||
@ -1000,38 +1012,38 @@ sub OnDropFiles {
|
|||||||
package Slic3r::GUI::Plater::Object;
|
package Slic3r::GUI::Plater::Object;
|
||||||
use Moo;
|
use Moo;
|
||||||
|
|
||||||
use Math::ConvexHull qw(convex_hull);
|
use Math::ConvexHull::MonotoneChain qw(convex_hull);
|
||||||
use Slic3r::Geometry qw(X Y);
|
use Slic3r::Geometry qw(X Y);
|
||||||
|
|
||||||
has 'name' => (is => 'rw', required => 1);
|
has 'name' => (is => 'rw', required => 1);
|
||||||
has 'input_file' => (is => 'rw', required => 1);
|
has 'input_file' => (is => 'rw', required => 1);
|
||||||
has 'input_file_object_id' => (is => 'rw'); # undef means keep mesh
|
has 'input_file_object_id' => (is => 'rw'); # undef means keep model object
|
||||||
has 'mesh' => (is => 'rw', required => 1, trigger => 1);
|
has 'model_object' => (is => 'rw', required => 1, trigger => 1);
|
||||||
has 'size' => (is => 'rw');
|
has 'size' => (is => 'rw');
|
||||||
has 'scale' => (is => 'rw', default => sub { 1 });
|
has 'scale' => (is => 'rw', default => sub { 1 });
|
||||||
has 'rotate' => (is => 'rw', default => sub { 0 });
|
has 'rotate' => (is => 'rw', default => sub { 0 });
|
||||||
has 'instances' => (is => 'rw', default => sub { [] }); # upward Y axis
|
has 'instances' => (is => 'rw', default => sub { [] }); # upward Y axis
|
||||||
has 'thumbnail' => (is => 'rw');
|
has 'thumbnail' => (is => 'rw');
|
||||||
|
|
||||||
sub _trigger_mesh {
|
sub _trigger_model_object {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
$self->size([$self->mesh->size]) if $self->mesh;
|
$self->size([$self->model_object->mesh->size]) if $self->model_object;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub free_mesh {
|
sub free_model_object {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
|
|
||||||
# only delete mesh from memory if we can retrieve it from the original file
|
# only delete mesh from memory if we can retrieve it from the original file
|
||||||
return unless $self->input_file && $self->input_file_object_id;
|
return unless $self->input_file && $self->input_file_object_id;
|
||||||
$self->mesh(undef);
|
$self->model_object(undef);
|
||||||
}
|
}
|
||||||
|
|
||||||
sub get_mesh {
|
sub get_model_object {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
|
|
||||||
return $self->mesh->clone if $self->mesh;
|
return $self->model_object if $self->model_object;
|
||||||
my $model = Slic3r::Model->read_from_file($self->input_file);
|
my $model = Slic3r::Model->read_from_file($self->input_file);
|
||||||
return $model->objects->[$self->input_file_object_id]->mesh;
|
return $model->objects->[$self->input_file_object_id];
|
||||||
}
|
}
|
||||||
|
|
||||||
sub instances_count {
|
sub instances_count {
|
||||||
@ -1043,7 +1055,7 @@ sub make_thumbnail {
|
|||||||
my $self = shift;
|
my $self = shift;
|
||||||
my %params = @_;
|
my %params = @_;
|
||||||
|
|
||||||
my @points = map [ @$_[X,Y] ], @{$self->mesh->vertices};
|
my @points = map [ @$_[X,Y] ], @{$self->model_object->mesh->vertices};
|
||||||
my $convex_hull = Slic3r::Polygon->new(convex_hull(\@points));
|
my $convex_hull = Slic3r::Polygon->new(convex_hull(\@points));
|
||||||
for (@$convex_hull) {
|
for (@$convex_hull) {
|
||||||
@$_ = map $_ * $params{scaling_factor}, @$_;
|
@$_ = map $_ * $params{scaling_factor}, @$_;
|
||||||
@ -1054,7 +1066,7 @@ sub make_thumbnail {
|
|||||||
$convex_hull->align_to_origin;
|
$convex_hull->align_to_origin;
|
||||||
|
|
||||||
$self->thumbnail($convex_hull); # ignored in multi-threaded environments
|
$self->thumbnail($convex_hull); # ignored in multi-threaded environments
|
||||||
$self->mesh(undef) if defined $self->input_file_object_id;
|
$self->free_model_object;
|
||||||
|
|
||||||
return $convex_hull;
|
return $convex_hull;
|
||||||
}
|
}
|
||||||
|
@ -85,6 +85,12 @@ sub new {
|
|||||||
});
|
});
|
||||||
|
|
||||||
EVT_BUTTON($self, $self->{btn_save_preset}, sub {
|
EVT_BUTTON($self, $self->{btn_save_preset}, sub {
|
||||||
|
|
||||||
|
# since buttons (and choices too) don't get focus on Mac, we set focus manually
|
||||||
|
# to the treectrl so that the EVT_* events are fired for the input field having
|
||||||
|
# focus currently. is there anything better than this?
|
||||||
|
$self->{treectrl}->SetFocus;
|
||||||
|
|
||||||
my $preset = $self->current_preset;
|
my $preset = $self->current_preset;
|
||||||
my $default_name = $preset->{default} ? 'Untitled' : basename($preset->{name});
|
my $default_name = $preset->{default} ? 'Untitled' : basename($preset->{name});
|
||||||
$default_name =~ s/\.ini$//i;
|
$default_name =~ s/\.ini$//i;
|
||||||
|
@ -36,7 +36,7 @@ use constant X2 => 2;
|
|||||||
use constant Y2 => 3;
|
use constant Y2 => 3;
|
||||||
use constant MIN => 0;
|
use constant MIN => 0;
|
||||||
use constant MAX => 1;
|
use constant MAX => 1;
|
||||||
our $parallel_degrees_limit = abs(deg2rad(3));
|
our $parallel_degrees_limit = abs(deg2rad(0.1));
|
||||||
|
|
||||||
sub epsilon () { 1E-4 }
|
sub epsilon () { 1E-4 }
|
||||||
sub scaled_epsilon () { epsilon / &Slic3r::SCALING_FACTOR }
|
sub scaled_epsilon () { epsilon / &Slic3r::SCALING_FACTOR }
|
||||||
|
@ -14,12 +14,12 @@ our $clipper = Math::Clipper->new;
|
|||||||
|
|
||||||
sub safety_offset {
|
sub safety_offset {
|
||||||
my ($polygons, $factor) = @_;
|
my ($polygons, $factor) = @_;
|
||||||
return Math::Clipper::offset($polygons, $factor || (scale 1e-05), 100, JT_MITER, 2);
|
return Math::Clipper::offset($polygons, $factor || (scale 1e-05), 100000, JT_MITER, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
sub offset {
|
sub offset {
|
||||||
my ($polygons, $distance, $scale, $joinType, $miterLimit) = @_;
|
my ($polygons, $distance, $scale, $joinType, $miterLimit) = @_;
|
||||||
$scale ||= &Slic3r::SCALING_FACTOR * 1000000;
|
$scale ||= 100000;
|
||||||
$joinType = JT_MITER if !defined $joinType;
|
$joinType = JT_MITER if !defined $joinType;
|
||||||
$miterLimit ||= 2;
|
$miterLimit ||= 2;
|
||||||
|
|
||||||
|
@ -358,7 +358,7 @@ sub prepare_fill_surfaces {
|
|||||||
|
|
||||||
# offset inwards
|
# offset inwards
|
||||||
my @offsets = $surface->expolygon->offset_ex(-$distance);
|
my @offsets = $surface->expolygon->offset_ex(-$distance);
|
||||||
@offsets = @{union_ex(Math::Clipper::offset([ map @$_, @offsets ], $distance, 100, JT_MITER))};
|
@offsets = @{union_ex(Math::Clipper::offset([ map @$_, @offsets ], $distance, 100000, JT_MITER))};
|
||||||
map Slic3r::Surface->new(
|
map Slic3r::Surface->new(
|
||||||
expolygon => $_,
|
expolygon => $_,
|
||||||
surface_type => $surface->surface_type,
|
surface_type => $surface->surface_type,
|
||||||
|
@ -37,6 +37,12 @@ sub set_material {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub scale {
|
||||||
|
my $self = shift;
|
||||||
|
|
||||||
|
$_->scale(@_) for @{$self->objects};
|
||||||
|
}
|
||||||
|
|
||||||
# flattens everything to a single mesh
|
# flattens everything to a single mesh
|
||||||
sub mesh {
|
sub mesh {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
@ -112,6 +118,17 @@ sub mesh {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub scale {
|
||||||
|
my $self = shift;
|
||||||
|
my ($factor) = @_;
|
||||||
|
return if $factor == 1;
|
||||||
|
|
||||||
|
# transform vertex coordinates
|
||||||
|
foreach my $vertex (@{$self->vertices}) {
|
||||||
|
$vertex->[$_] *= $factor for X,Y,Z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
package Slic3r::Model::Volume;
|
package Slic3r::Model::Volume;
|
||||||
use Moo;
|
use Moo;
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ use Moo;
|
|||||||
use File::Basename qw(basename fileparse);
|
use File::Basename qw(basename fileparse);
|
||||||
use File::Spec;
|
use File::Spec;
|
||||||
use List::Util qw(max);
|
use List::Util qw(max);
|
||||||
use Math::ConvexHull 1.0.4 qw(convex_hull);
|
use Math::ConvexHull::MonotoneChain qw(convex_hull);
|
||||||
use Slic3r::ExtrusionPath ':roles';
|
use Slic3r::ExtrusionPath ':roles';
|
||||||
use Slic3r::Geometry qw(X Y Z X1 Y1 X2 Y2 MIN PI scale unscale move_points nearest_point);
|
use Slic3r::Geometry qw(X Y Z X1 Y1 X2 Y2 MIN PI scale unscale move_points nearest_point);
|
||||||
use Slic3r::Geometry::Clipper qw(diff_ex union_ex intersection_ex offset JT_ROUND JT_SQUARE);
|
use Slic3r::Geometry::Clipper qw(diff_ex union_ex intersection_ex offset JT_ROUND JT_SQUARE);
|
||||||
@ -185,8 +185,16 @@ sub init_extruders {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# calculate default flows
|
||||||
|
$Slic3r::flow = $self->extruders->[0]->make_flow(
|
||||||
|
width => $self->config->extrusion_width,
|
||||||
|
);
|
||||||
|
$Slic3r::first_layer_flow = $self->extruders->[0]->make_flow(
|
||||||
|
layer_height => $self->config->get_value('first_layer_height'),
|
||||||
|
width => $self->config->first_layer_extrusion_width,
|
||||||
|
);
|
||||||
|
|
||||||
# calculate regions' flows
|
# calculate regions' flows
|
||||||
$Slic3r::flow = $self->extruders->[0]->make_flow(width => $self->config->extrusion_width);
|
|
||||||
for my $region_id (0 .. $#{$self->regions}) {
|
for my $region_id (0 .. $#{$self->regions}) {
|
||||||
my $region = $self->regions->[$region_id];
|
my $region = $self->regions->[$region_id];
|
||||||
|
|
||||||
@ -421,7 +429,7 @@ sub export_gcode {
|
|||||||
# make skirt
|
# make skirt
|
||||||
$status_cb->(88, "Generating skirt");
|
$status_cb->(88, "Generating skirt");
|
||||||
$self->make_skirt;
|
$self->make_skirt;
|
||||||
$self->make_brim;
|
$self->make_brim; # must come after make_skirt
|
||||||
|
|
||||||
# output everything to a G-code file
|
# output everything to a G-code file
|
||||||
my $output_file = $self->expanded_output_filepath($params{output_file});
|
my $output_file = $self->expanded_output_filepath($params{output_file});
|
||||||
@ -559,25 +567,22 @@ sub make_skirt {
|
|||||||
my $convex_hull = convex_hull(\@points);
|
my $convex_hull = convex_hull(\@points);
|
||||||
|
|
||||||
# draw outlines from outside to inside
|
# draw outlines from outside to inside
|
||||||
my $flow = $Slic3r::first_layer_flow || $Slic3r::flow;
|
|
||||||
my @skirt = ();
|
|
||||||
for (my $i = $Slic3r::Config->skirts; $i > 0; $i--) {
|
for (my $i = $Slic3r::Config->skirts; $i > 0; $i--) {
|
||||||
my $distance = scale ($Slic3r::Config->skirt_distance + ($flow->spacing * $i));
|
my $distance = scale ($Slic3r::Config->skirt_distance + ($Slic3r::first_layer_flow->spacing * $i));
|
||||||
my $outline = Math::Clipper::offset([$convex_hull], $distance, &Slic3r::SCALING_FACTOR * 100, JT_ROUND);
|
my $outline = Math::Clipper::offset([$convex_hull], $distance, &Slic3r::SCALING_FACTOR * 100, JT_ROUND);
|
||||||
push @skirt, Slic3r::ExtrusionLoop->pack(
|
push @{$self->skirt}, Slic3r::ExtrusionLoop->pack(
|
||||||
polygon => Slic3r::Polygon->new(@{$outline->[0]}),
|
polygon => Slic3r::Polygon->new(@{$outline->[0]}),
|
||||||
role => EXTR_ROLE_SKIRT,
|
role => EXTR_ROLE_SKIRT,
|
||||||
|
flow_spacing => $Slic3r::first_layer_flow->spacing,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
unshift @{$self->skirt}, @skirt;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub make_brim {
|
sub make_brim {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
return unless $Slic3r::Config->brim_width > 0;
|
return unless $Slic3r::Config->brim_width > 0;
|
||||||
|
|
||||||
my $flow = $Slic3r::first_layer_flow || $Slic3r::flow;
|
my $grow_distance = $Slic3r::first_layer_flow->scaled_width / 2;
|
||||||
my $grow_distance = $flow->scaled_width / 2;
|
|
||||||
my @islands = (); # array of polygons
|
my @islands = (); # array of polygons
|
||||||
foreach my $obj_idx (0 .. $#{$self->objects}) {
|
foreach my $obj_idx (0 .. $#{$self->objects}) {
|
||||||
my $layer0 = $self->objects->[$obj_idx]->layers->[0];
|
my $layer0 = $self->objects->[$obj_idx]->layers->[0];
|
||||||
@ -591,13 +596,19 @@ sub make_brim {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
my $num_loops = sprintf "%.0f", $Slic3r::Config->brim_width / $flow->width;
|
# if brim touches skirt, make it around skirt too
|
||||||
|
if ($Slic3r::Config->skirt_distance + (($Slic3r::Config->skirts - 1) * $Slic3r::first_layer_flow->spacing) <= $Slic3r::Config->brim_width) {
|
||||||
|
push @islands, map $_->unpack->split_at_first_point->polyline->grow($grow_distance), @{$self->skirt};
|
||||||
|
}
|
||||||
|
|
||||||
|
my $num_loops = sprintf "%.0f", $Slic3r::Config->brim_width / $Slic3r::first_layer_flow->width;
|
||||||
for my $i (reverse 1 .. $num_loops) {
|
for my $i (reverse 1 .. $num_loops) {
|
||||||
# JT_SQUARE ensures no vertex is outside the given offset distance
|
# JT_SQUARE ensures no vertex is outside the given offset distance
|
||||||
push @{$self->brim}, Slic3r::ExtrusionLoop->pack(
|
push @{$self->brim}, Slic3r::ExtrusionLoop->pack(
|
||||||
polygon => Slic3r::Polygon->new($_),
|
polygon => Slic3r::Polygon->new($_),
|
||||||
role => EXTR_ROLE_SKIRT,
|
role => EXTR_ROLE_SKIRT,
|
||||||
) for @{Math::Clipper::offset(\@islands, $i * $flow->scaled_spacing, 100, JT_SQUARE)};
|
flow_spacing => $Slic3r::first_layer_flow->spacing,
|
||||||
|
) for @{Math::Clipper::offset(\@islands, $i * $Slic3r::first_layer_flow->scaled_spacing, 100, JT_SQUARE)};
|
||||||
# TODO: we need the offset inwards/offset outwards logic to avoid overlapping extrusions
|
# TODO: we need the offset inwards/offset outwards logic to avoid overlapping extrusions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -699,7 +710,7 @@ sub write_gcode {
|
|||||||
$gcodegen->shift_y($shift[Y]);
|
$gcodegen->shift_y($shift[Y]);
|
||||||
$gcode .= $gcodegen->set_acceleration($Slic3r::Config->perimeter_acceleration);
|
$gcode .= $gcodegen->set_acceleration($Slic3r::Config->perimeter_acceleration);
|
||||||
# skip skirt if we have a large brim
|
# skip skirt if we have a large brim
|
||||||
if ($layer_id < $Slic3r::Config->skirt_height && ($layer_id != 0 || $Slic3r::Config->skirt_distance + (($Slic3r::Config->skirts - 1) * $Slic3r::flow->spacing) > $Slic3r::Config->brim_width)) {
|
if ($layer_id < $Slic3r::Config->skirt_height) {
|
||||||
$gcode .= $gcodegen->extrude_loop($_, 'skirt') for @{$self->skirt};
|
$gcode .= $gcodegen->extrude_loop($_, 'skirt') for @{$self->skirt};
|
||||||
}
|
}
|
||||||
$skirt_done++;
|
$skirt_done++;
|
||||||
|
@ -2,7 +2,7 @@ package Slic3r::Print::Object;
|
|||||||
use Moo;
|
use Moo;
|
||||||
|
|
||||||
use Slic3r::ExtrusionPath ':roles';
|
use Slic3r::ExtrusionPath ':roles';
|
||||||
use Slic3r::Geometry qw(scale unscale deg2rad);
|
use Slic3r::Geometry qw(scale unscale deg2rad scaled_epsilon);
|
||||||
use Slic3r::Geometry::Clipper qw(diff_ex intersection_ex union_ex);
|
use Slic3r::Geometry::Clipper qw(diff_ex intersection_ex union_ex);
|
||||||
use Slic3r::Surface ':types';
|
use Slic3r::Surface ':types';
|
||||||
|
|
||||||
@ -211,7 +211,7 @@ sub make_perimeters {
|
|||||||
# of our slice
|
# of our slice
|
||||||
my $hypothetical_perimeter;
|
my $hypothetical_perimeter;
|
||||||
{
|
{
|
||||||
my $outer = [ map @$_, $slice->expolygon->offset_ex(- ($hypothetical_perimeter_num-1.5) * $perimeter_flow->scaled_spacing) ];
|
my $outer = [ map @$_, $slice->expolygon->offset_ex(- ($hypothetical_perimeter_num-1.5) * $perimeter_flow->scaled_spacing - scaled_epsilon) ];
|
||||||
last CYCLE if !@$outer;
|
last CYCLE if !@$outer;
|
||||||
my $inner = [ map @$_, $slice->expolygon->offset_ex(- ($hypothetical_perimeter_num-0.5) * $perimeter_flow->scaled_spacing) ];
|
my $inner = [ map @$_, $slice->expolygon->offset_ex(- ($hypothetical_perimeter_num-0.5) * $perimeter_flow->scaled_spacing) ];
|
||||||
last CYCLE if !@$inner;
|
last CYCLE if !@$inner;
|
||||||
|
@ -25,12 +25,14 @@ my %opt = ();
|
|||||||
|
|
||||||
{
|
{
|
||||||
my $input_file = $ARGV[0];
|
my $input_file = $ARGV[0];
|
||||||
my $mesh;
|
|
||||||
$mesh = Slic3r::Format::STL->read_file($input_file) if $input_file =~ /\.stl$/i;
|
|
||||||
die "This script doesn't support AMF yet\n" if $input_file =~ /\.amf$/i;
|
die "This script doesn't support AMF yet\n" if $input_file =~ /\.amf$/i;
|
||||||
die "Unable to read file\n" if !$mesh;
|
|
||||||
|
my $model;
|
||||||
|
$model = Slic3r::Format::STL->read_file($input_file) if $input_file =~ /\.stl$/i;
|
||||||
|
die "Unable to read file\n" if !$model;
|
||||||
|
|
||||||
printf "Info about %s:\n", basename($input_file);
|
printf "Info about %s:\n", basename($input_file);
|
||||||
|
my $mesh = $model->mesh;
|
||||||
$mesh->check_manifoldness;
|
$mesh->check_manifoldness;
|
||||||
printf " number of facets: %d\n", scalar @{$mesh->facets};
|
printf " number of facets: %d\n", scalar @{$mesh->facets};
|
||||||
printf " size: x=%s y=%s z=%s\n", $mesh->size;
|
printf " size: x=%s y=%s z=%s\n", $mesh->size;
|
||||||
|
Loading…
Reference in New Issue
Block a user