Fixes for hi-res STL models
This commit is contained in:
parent
6444c3d7a9
commit
794b7a99d2
@ -44,7 +44,7 @@ our $perimeter_feed_rate = 30; # mm/sec
|
||||
our $bottom_layer_speed_ratio = 0.3;
|
||||
|
||||
# accuracy options
|
||||
our $resolution = 0.001;
|
||||
our $resolution = 0.00000001;
|
||||
our $layer_height = 0.4;
|
||||
our $thickness_ratio = 1;
|
||||
our $flow_width;
|
||||
|
@ -8,6 +8,7 @@ has 'z' => (is => 'rw', default => sub {0} );
|
||||
has 'extrusion_distance' => (is => 'rw', default => sub {0} );
|
||||
has 'retracted' => (is => 'rw', default => sub {1} ); # this spits out some plastic at start
|
||||
has 'last_pos' => (is => 'rw', default => sub { [0,0] } );
|
||||
has 'dec' => (is => 'ro', default => sub { 3 } );
|
||||
|
||||
# calculate speeds
|
||||
has 'travel_feed_rate' => (
|
||||
@ -27,12 +28,6 @@ has 'retract_speed' => (
|
||||
default => sub { $Slic3r::retract_speed * 60 }, # mm/min
|
||||
);
|
||||
|
||||
# calculate number of decimals
|
||||
has 'dec' => (
|
||||
is => 'ro',
|
||||
default => sub { length((1 / $Slic3r::resolution) - 1) + 1 },
|
||||
);
|
||||
|
||||
use XXX;
|
||||
|
||||
use constant PI => 4 * atan2(1, 1);
|
||||
|
@ -10,7 +10,7 @@ use constant A => 0;
|
||||
use constant B => 1;
|
||||
use constant X => 0;
|
||||
use constant Y => 1;
|
||||
use constant epsilon => 1E-8;
|
||||
use constant epsilon => 1E-6;
|
||||
use constant epsilon2 => epsilon**2;
|
||||
our $parallel_degrees_limit = abs(deg2rad(3));
|
||||
|
||||
@ -170,4 +170,13 @@ sub move_points {
|
||||
return map [ $shift->[X] + $_->[X], $shift->[Y] + $_->[Y] ], @points;
|
||||
}
|
||||
|
||||
# preserves order
|
||||
sub remove_coinciding_points {
|
||||
my ($points) = @_;
|
||||
|
||||
my %p = map { sprintf('%f,%f', @$_) => "$_" } @$points;
|
||||
%p = reverse %p;
|
||||
@$points = grep $p{"$_"}, @$points;
|
||||
}
|
||||
|
||||
1;
|
||||
|
@ -81,10 +81,9 @@ sub add_surface {
|
||||
|
||||
sub add_line {
|
||||
my $self = shift;
|
||||
my ($a, $b) = @_;
|
||||
my ($line) = @_;
|
||||
|
||||
# we accept either a Line object or a couple of points
|
||||
my $line = Slic3r::Line->cast([ $a, $b ]);
|
||||
$line = Slic3r::Line->cast($line);
|
||||
|
||||
push @{ $self->lines }, $line;
|
||||
return $line;
|
||||
@ -106,6 +105,13 @@ sub remove_surface {
|
||||
sub make_polylines {
|
||||
my $self = shift;
|
||||
|
||||
# remove line duplicates
|
||||
{
|
||||
my %lines_map = map { join(',', sort map $_->id, @{$_->points} ) => "$_" } @{ $self->lines };
|
||||
%lines_map = reverse %lines_map;
|
||||
@{ $self->lines } = grep $lines_map{"$_"}, @{ $self->lines };
|
||||
}
|
||||
|
||||
# make a cache of line endpoints
|
||||
my %pointmap = ();
|
||||
foreach my $line (@{ $self->lines }) {
|
||||
@ -116,8 +122,8 @@ sub make_polylines {
|
||||
}
|
||||
|
||||
# defensive programming
|
||||
die "No point should be endpoint of less or more than 2 lines!"
|
||||
if grep @$_ != 2, values %pointmap;
|
||||
#die "No point should be endpoint of less or more than 2 lines!"
|
||||
# if grep @$_ != 2, values %pointmap;
|
||||
|
||||
if (0) {
|
||||
# defensive programming
|
||||
@ -126,8 +132,11 @@ sub make_polylines {
|
||||
|
||||
#use Slic3r::SVG;
|
||||
#Slic3r::SVG::output_points($main::print, "points.svg", [ map [split /,/], keys %pointmap ], [ [split /,/, $_ ] ]);
|
||||
#Slic3r::SVG::output_lines($main::print, "lines.svg", [ map $_->p, @{$self->lines} ]);
|
||||
|
||||
die sprintf "No point should be endpoint of less or more than 2 lines (%d)!", scalar(@{$pointmap{$_}});
|
||||
YYY $pointmap{$_};
|
||||
|
||||
die sprintf "No point should be endpoint of less or more than 2 lines ($_ => %d)!", scalar(@{$pointmap{$_}});
|
||||
}
|
||||
|
||||
while (my @single_line_points = grep @{$pointmap{$_}} == 1, keys %pointmap) {
|
||||
@ -172,7 +181,7 @@ sub make_polylines {
|
||||
# remove last point as it coincides with first one
|
||||
pop @$points;
|
||||
|
||||
die "Invalid polyline with only 2 points\n" if @$points == 2;
|
||||
die sprintf "Invalid polyline with only %d points\n", scalar(@$points) if @$points < 3;
|
||||
|
||||
Slic3r::debugf "Discovered polyline of %d points (%s)\n", scalar @$points,
|
||||
join ' - ', map $_->id, @$points;
|
||||
@ -341,7 +350,7 @@ sub remove_small_features {
|
||||
foreach my $loop (@{$self->perimeters}) {
|
||||
my $p = $loop->p;
|
||||
@$p = reverse @$p if !is_counter_clockwise($p);
|
||||
my $offsets = offset([$p], -($Slic3r::flow_width / 2 / $Slic3r::resolution), 100, JT_MITER, 2);
|
||||
my $offsets = offset([$p], -($Slic3r::flow_width / 2 / $Slic3r::resolution), $Slic3r::resolution * 100000, JT_MITER, 2);
|
||||
push @good_perimeters, $loop if @$offsets;
|
||||
}
|
||||
Slic3r::debugf "removed %d unprintable perimeters\n", (@{$self->perimeters} - @good_perimeters)
|
||||
|
@ -75,7 +75,7 @@ sub make_perimeter {
|
||||
}
|
||||
|
||||
# generate skirt on bottom layer
|
||||
if ($layer->id == 0 && $Slic3r::skirts > 0) {
|
||||
if ($layer->id == 0 && $Slic3r::skirts > 0 && @{ $layer->surfaces }) {
|
||||
# find out convex hull
|
||||
my $points = [ map { @{ $_->mgp_polygon->polygons->[0] } } @{ $layer->surfaces } ];
|
||||
my $convex_hull = $self->_mgp_from_points_ref($points)->convexhull2; # maybe Math::ConvexHull is faster?
|
||||
@ -84,7 +84,7 @@ sub make_perimeter {
|
||||
# draw outlines from outside to inside
|
||||
for (my $i = $Slic3r::skirts - 1; $i >= 0; $i--) {
|
||||
my $distance = ($Slic3r::skirt_distance + ($Slic3r::flow_width * $i)) / $Slic3r::resolution;
|
||||
my $outline = offset([$convex_hull_points], $distance, 0.1, JT_ROUND);
|
||||
my $outline = offset([$convex_hull_points], $distance, $Slic3r::resolution * 100000, JT_ROUND);
|
||||
push @{ $layer->skirts }, Slic3r::ExtrusionLoop->cast([ @{$outline->[0]} ]);
|
||||
}
|
||||
}
|
||||
@ -101,7 +101,7 @@ sub offset_polygon {
|
||||
my ($contour_p, @holes_p) = ($polygon->{outer}, @{$polygon->{holes}});
|
||||
|
||||
# generate offsets
|
||||
my $offsets = offset([ $contour_p, @holes_p ], -$distance, 100, JT_MITER, 2);
|
||||
my $offsets = offset([ $contour_p, @holes_p ], -$distance, $Slic3r::resolution * 100000, JT_MITER, 2);
|
||||
|
||||
# defensive programming
|
||||
my (@contour_offsets, @hole_offsets) = ();
|
||||
|
@ -30,7 +30,7 @@ sub parse_file {
|
||||
|
||||
# we only want to work with positive coordinates, so let's
|
||||
# find our object extents to calculate coordinate displacements
|
||||
my @extents = (map [99999999, -99999999], X,Y,Z);
|
||||
my @extents = (map [99999999999, -99999999999], X,Y,Z);
|
||||
foreach my $facet ($stl->part->facets) {
|
||||
my ($normal, @vertices) = @$facet;
|
||||
foreach my $vertex (@vertices) {
|
||||
@ -103,7 +103,7 @@ sub _facet {
|
||||
if $Slic3r::debug;
|
||||
|
||||
# find the vertical extents of the facet
|
||||
my ($min_z, $max_z) = (99999999, -99999999);
|
||||
my ($min_z, $max_z) = (99999999999, -99999999999);
|
||||
foreach my $vertex (@vertices) {
|
||||
$min_z = $vertex->[Z] if $vertex->[Z] < $min_z;
|
||||
$max_z = $vertex->[Z] if $vertex->[Z] > $max_z;
|
||||
@ -111,8 +111,10 @@ sub _facet {
|
||||
Slic3r::debugf "z: min = %.0f, max = %.0f\n", $min_z, $max_z;
|
||||
|
||||
# calculate the layer extents
|
||||
my ($min_layer, $max_layer) = map { sprintf '%.0f', $_ * $Slic3r::resolution / $Slic3r::layer_height } $min_z, $max_z;
|
||||
Slic3r::debugf "layers: min = %.0f, max = %.0f\n", $min_layer, $max_layer;
|
||||
my $min_layer = int($min_z * $Slic3r::resolution / $Slic3r::layer_height);
|
||||
my $max_layer = int(0.99999 + ($max_z * $Slic3r::resolution / $Slic3r::layer_height));
|
||||
|
||||
Slic3r::debugf "layers: min = %s, max = %s\n", $min_layer, $max_layer;
|
||||
|
||||
# is the facet horizontal?
|
||||
if ($min_layer == $max_layer) {
|
||||
@ -149,48 +151,72 @@ sub _facet {
|
||||
return;
|
||||
}
|
||||
|
||||
# build the three segments of the triangle facet
|
||||
my @edges = (
|
||||
[ $vertices[0], $vertices[1] ],
|
||||
[ $vertices[1], $vertices[2] ],
|
||||
[ $vertices[2], $vertices[0] ],
|
||||
);
|
||||
|
||||
for (my $layer_id = $min_layer; $layer_id <= $max_layer; $layer_id++) {
|
||||
my $layer = $print->layer($layer_id);
|
||||
my $z = $layer->z;
|
||||
|
||||
my @intersection_points = ();
|
||||
|
||||
foreach my $edge (@edges) {
|
||||
my ($a, $b) = @$edge;
|
||||
if ($a->[Z] == $b->[Z] && $a->[Z] == $z) {
|
||||
# edge is horizontal and belongs to the current layer
|
||||
$layer->add_line([$a->[X], $a->[Y]], [$b->[X], $b->[Y]]);
|
||||
|
||||
} elsif (($a->[Z] < $z && $b->[Z] > $z) || ($b->[Z] < $z && $a->[Z] > $z)) {
|
||||
# edge intersects the current layer; calculate intersection
|
||||
push @intersection_points, Slic3r::Point->cast([
|
||||
$b->[X] + ($a->[X] - $b->[X]) * ($z - $b->[Z]) / ($a->[Z] - $b->[Z]),
|
||||
$b->[Y] + ($a->[Y] - $b->[Y]) * ($z - $b->[Z]) / ($a->[Z] - $b->[Z]),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
if (@intersection_points) {
|
||||
# defensive programming:
|
||||
die "Facets must intersect each plane 0 or 2 times" if @intersection_points != 2;
|
||||
|
||||
# check whether the two points coincide due to resolution rounding
|
||||
if ($intersection_points[0]->coincides_with($intersection_points[1])) {
|
||||
Slic3r::debugf "Points coincide at layer %d; removing\n", $layer_id;
|
||||
next;
|
||||
}
|
||||
|
||||
# connect points:
|
||||
$layer->add_line(@intersection_points);
|
||||
}
|
||||
$layer->add_line($_) for $self->intersect_facet(\@vertices, $layer->z);
|
||||
}
|
||||
}
|
||||
|
||||
sub intersect_facet {
|
||||
my $self = shift;
|
||||
my ($vertices, $z) = @_;
|
||||
|
||||
# build the three segments of the triangle facet
|
||||
my @edges = (
|
||||
[ $vertices->[0], $vertices->[1] ],
|
||||
[ $vertices->[1], $vertices->[2] ],
|
||||
[ $vertices->[2], $vertices->[0] ],
|
||||
);
|
||||
|
||||
my (@lines, @intersection_points) = ();
|
||||
|
||||
foreach my $edge (@edges) {
|
||||
my ($a, $b) = @$edge;
|
||||
#printf "Az = %d, Bz = %d, z = %d\n", $a->[Z], $b->[Z], $z;
|
||||
|
||||
if ($a->[Z] == $b->[Z] && $a->[Z] == $z) {
|
||||
# edge is horizontal and belongs to the current layer
|
||||
push @lines, [ [$a->[X], $a->[Y]], [$b->[X], $b->[Y]] ];
|
||||
#print "Horizontal!\n";
|
||||
|
||||
} elsif (($a->[Z] < $z && $b->[Z] > $z) || ($b->[Z] < $z && $a->[Z] > $z)) {
|
||||
# edge intersects the current layer; calculate intersection
|
||||
push @intersection_points, [
|
||||
$b->[X] + ($a->[X] - $b->[X]) * ($z - $b->[Z]) / ($a->[Z] - $b->[Z]),
|
||||
$b->[Y] + ($a->[Y] - $b->[Y]) * ($z - $b->[Z]) / ($a->[Z] - $b->[Z]),
|
||||
];
|
||||
#print "Intersects!\n";
|
||||
|
||||
} elsif ($a->[Z] == $z) {
|
||||
#print "A point on plane!\n";
|
||||
push @intersection_points, [ $a->[X], $a->[Y] ];
|
||||
|
||||
} elsif ($b->[Z] == $z) {
|
||||
#print "B point on plane!\n";
|
||||
push @intersection_points, [ $b->[X], $b->[Y] ];
|
||||
}
|
||||
}
|
||||
|
||||
Slic3r::Geometry::remove_coinciding_points(\@intersection_points);
|
||||
|
||||
if (@intersection_points > 1 && !@lines) {
|
||||
|
||||
# remove coinciding points
|
||||
|
||||
# defensive programming:
|
||||
die "Facets must intersect each plane 0 or 2 times" if @intersection_points != 2;
|
||||
|
||||
# check whether the two points coincide due to resolution rounding
|
||||
#if ($intersection_points[0]->coincides_with($intersection_points[1])) {
|
||||
# Slic3r::debugf "Points coincide; removing\n";
|
||||
# return;
|
||||
#}
|
||||
|
||||
# connect points:
|
||||
push @lines, [ @intersection_points ];
|
||||
}
|
||||
|
||||
return @lines;
|
||||
}
|
||||
|
||||
1;
|
||||
|
@ -8,7 +8,7 @@ use constant X => 0;
|
||||
use constant Y => 1;
|
||||
|
||||
sub factor {
|
||||
return $Slic3r::resolution * 100;
|
||||
return $Slic3r::resolution * 10;
|
||||
}
|
||||
|
||||
sub svg {
|
||||
|
37
t/stl.t
Normal file
37
t/stl.t
Normal file
@ -0,0 +1,37 @@
|
||||
use Test::More;
|
||||
|
||||
plan tests => 7;
|
||||
|
||||
BEGIN {
|
||||
use FindBin;
|
||||
use lib "$FindBin::Bin/../lib";
|
||||
}
|
||||
|
||||
use Slic3r;
|
||||
|
||||
my $stl = Slic3r::STL->new;
|
||||
|
||||
my @lines;
|
||||
my $z = 20;
|
||||
my @points = ([3, 4], [8, 5], [1, 9]);
|
||||
|
||||
is_deeply lines(20, 20, 20), [
|
||||
[ $points[0], $points[1] ],
|
||||
[ $points[1], $points[2] ],
|
||||
[ $points[2], $points[0] ],
|
||||
], 'horizontal';
|
||||
|
||||
is_deeply lines(22, 20, 20), [ [ $points[1], $points[2] ] ], 'lower edge on layer';
|
||||
is_deeply lines(20, 20, 10), [ [ $points[0], $points[1] ] ], 'upper edge on layer';
|
||||
is_deeply lines(20, 15, 10), [ ], 'upper vertex on layer';
|
||||
is_deeply lines(28, 20, 30), [ ], 'lower vertex on layer';
|
||||
is_deeply lines(24, 10, 16), [ [ [4, 4], [2, 6] ] ], 'two edges intersect';
|
||||
is_deeply lines(24, 10, 20), [ [ [4, 4], [1, 9] ] ], 'one vertex on plane and one edge intersects';
|
||||
|
||||
sub vertices {
|
||||
[ map [ @{$points[$_]}, $_[$_] ], 0..2 ]
|
||||
}
|
||||
|
||||
sub lines {
|
||||
[ map [ map ref $_ eq 'Slic3r::Point' ? $_->p : [ map sprintf('%.0f', $_), @$_ ], @$_ ], $stl->intersect_facet(vertices(@_), $z, $dz) ];
|
||||
}
|
Loading…
Reference in New Issue
Block a user