Fixes for hi-res STL models

This commit is contained in:
Alessandro Ranellucci 2011-10-04 17:55:55 +02:00
parent 6444c3d7a9
commit 794b7a99d2
8 changed files with 139 additions and 63 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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;
$layer->add_line($_) for $self->intersect_facet(\@vertices, $layer->z);
}
}
my @intersection_points = ();
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
$layer->add_line([$a->[X], $a->[Y]], [$b->[X], $b->[Y]]);
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, Slic3r::Point->cast([
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] ];
}
}
if (@intersection_points) {
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 at layer %d; removing\n", $layer_id;
next;
}
#if ($intersection_points[0]->coincides_with($intersection_points[1])) {
# Slic3r::debugf "Points coincide; removing\n";
# return;
#}
# connect points:
$layer->add_line(@intersection_points);
}
push @lines, [ @intersection_points ];
}
return @lines;
}
1;

View File

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