From 7da68c91a5c5544a3cb20a4d00b7a370c2af32fe Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 11 Apr 2016 17:05:58 +0200 Subject: [PATCH] Vojtech likes to use Sublime on Windows to get the wheels rolling. --- lib/Slic3r.pm | 2 + lib/Slic3r/Fill.pm | 50 ++--- lib/Slic3r/Fill/3DHoneycomb.pm | 230 --------------------- lib/Slic3r/Fill/Base.pm | 91 -------- lib/Slic3r/Fill/Concentric.pm | 57 ------ lib/Slic3r/Fill/Honeycomb.pm | 129 ------------ lib/Slic3r/Fill/PlanePath.pm | 118 ----------- lib/Slic3r/Fill/Rectilinear.pm | 168 --------------- lib/Slic3r/GUI/3DScene.pm | 1 + lib/Slic3r/GUI/Plater.pm | 1 + lib/Slic3r/GUI/Plater/2DToolpaths.pm | 262 ++++++++++++++++++++++-- lib/Slic3r/GUI/Plater/3DPreview.pm | 2 + lib/Slic3r/GUI/Tab.pm | 1 + lib/Slic3r/Print/SupportMaterial.pm | 12 +- slic3r.pl | 7 + slic3r.sublime-project | 40 ++++ xs/Build.PL | 5 +- xs/MANIFEST | 16 ++ xs/lib/Slic3r/XS.pm | 22 ++ xs/src/libslic3r/ClipperUtils.cpp | 4 + xs/src/libslic3r/MultiPoint.cpp | 1 - xs/src/libslic3r/PolylineCollection.cpp | 7 +- xs/src/libslic3r/TriangleMesh.cpp | 21 +- xs/src/perlglue.cpp | 4 + xs/xsp/my.map | 9 + xs/xsp/typemap.xspt | 12 ++ 26 files changed, 408 insertions(+), 864 deletions(-) delete mode 100644 lib/Slic3r/Fill/3DHoneycomb.pm delete mode 100644 lib/Slic3r/Fill/Base.pm delete mode 100644 lib/Slic3r/Fill/Concentric.pm delete mode 100644 lib/Slic3r/Fill/Honeycomb.pm delete mode 100644 lib/Slic3r/Fill/PlanePath.pm delete mode 100644 lib/Slic3r/Fill/Rectilinear.pm create mode 100644 slic3r.sublime-project diff --git a/lib/Slic3r.pm b/lib/Slic3r.pm index d093c609f..c194c1dd3 100644 --- a/lib/Slic3r.pm +++ b/lib/Slic3r.pm @@ -193,7 +193,9 @@ sub thread_cleanup { *Slic3r::ExtrusionLoop::DESTROY = sub {}; *Slic3r::ExtrusionPath::DESTROY = sub {}; *Slic3r::ExtrusionPath::Collection::DESTROY = sub {}; + *Slic3r::ExtrusionSimulator::DESTROY = sub {}; *Slic3r::Flow::DESTROY = sub {}; + *Slic3r::Filler::Destroy = sub {}; *Slic3r::GCode::DESTROY = sub {}; *Slic3r::GCode::AvoidCrossingPerimeters::DESTROY = sub {}; *Slic3r::GCode::OozePrevention::DESTROY = sub {}; diff --git a/lib/Slic3r/Fill.pm b/lib/Slic3r/Fill.pm index 8c63fde59..86c59df2d 100644 --- a/lib/Slic3r/Fill.pm +++ b/lib/Slic3r/Fill.pm @@ -3,45 +3,28 @@ use Moo; use List::Util qw(max); use Slic3r::ExtrusionPath ':roles'; -use Slic3r::Fill::3DHoneycomb; -use Slic3r::Fill::Base; -use Slic3r::Fill::Concentric; -use Slic3r::Fill::Honeycomb; -use Slic3r::Fill::PlanePath; -use Slic3r::Fill::Rectilinear; + use Slic3r::Flow ':roles'; use Slic3r::Geometry qw(X Y PI scale chained_path deg2rad); use Slic3r::Geometry::Clipper qw(union union_ex diff diff_ex intersection_ex offset offset2); use Slic3r::Surface ':types'; +use Data::Dumper qw(Dumper); + has 'bounding_box' => (is => 'ro', required => 0); has 'fillers' => (is => 'rw', default => sub { {} }); -our %FillTypes = ( - archimedeanchords => 'Slic3r::Fill::ArchimedeanChords', - rectilinear => 'Slic3r::Fill::Rectilinear', - grid => 'Slic3r::Fill::Grid', - flowsnake => 'Slic3r::Fill::Flowsnake', - octagramspiral => 'Slic3r::Fill::OctagramSpiral', - hilbertcurve => 'Slic3r::Fill::HilbertCurve', - line => 'Slic3r::Fill::Line', - concentric => 'Slic3r::Fill::Concentric', - honeycomb => 'Slic3r::Fill::Honeycomb', - '3dhoneycomb' => 'Slic3r::Fill::3DHoneycomb', -); - sub filler { my $self = shift; my ($filler) = @_; if (!ref $self) { - return $FillTypes{$filler}->new; + return Slic3r::Filler->new_from_type($filler); } - - $self->fillers->{$filler} ||= $FillTypes{$filler}->new( - bounding_box => $self->bounding_box, - ); + + $self->fillers->{$filler} ||= Slic3r::Filler->new_from_type($filler); + $self->fillers->{$filler}->set_bounding_box($self->bounding_box); return $self->fillers->{$filler}; } @@ -227,16 +210,16 @@ sub make_fill { -1, # auto width $layerm->layer->object, ); - $f->spacing($internal_flow->spacing); + $f->set_spacing($internal_flow->spacing); $using_internal_flow = 1; } else { - $f->spacing($flow->spacing); + $f->set_spacing($flow->spacing); } - $f->layer_id($layerm->layer->id); - $f->z($layerm->layer->print_z); - $f->angle(deg2rad($layerm->region->config->fill_angle)); - $f->loop_clipping(scale($flow->nozzle_diameter) * &Slic3r::LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER); + $f->set_layer_id($layerm->layer->id); + $f->set_z($layerm->layer->print_z); + $f->set_angle(deg2rad($layerm->region->config->fill_angle)); + $f->set_loop_clipping(scale($flow->nozzle_diameter) * &Slic3r::LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER); # apply half spacing using this flow's own spacing and generate infill my @polylines = map $f->fill_surface( @@ -244,8 +227,10 @@ sub make_fill { density => $density/100, layer_height => $h, ), @{ $surface->offset(-scale($f->spacing)/2) }; - + next unless @polylines; + + print "Polylines after fill_surface: ", Dumper(\@polylines); # calculate actual flow from spacing (which might have been adjusted by the infill # pattern generator) @@ -271,6 +256,7 @@ sub make_fill { push @fills, my $collection = Slic3r::ExtrusionPath::Collection->new; $collection->no_sort($f->no_sort); + print "collecton->append\n"; $collection->append( map Slic3r::ExtrusionPath->new( polyline => $_, @@ -278,7 +264,7 @@ sub make_fill { mm3_per_mm => $mm3_per_mm, width => $flow->width, height => $flow->height, - ), @polylines, + ), map @$_, @polylines, ); } } diff --git a/lib/Slic3r/Fill/3DHoneycomb.pm b/lib/Slic3r/Fill/3DHoneycomb.pm deleted file mode 100644 index 3bf7e547f..000000000 --- a/lib/Slic3r/Fill/3DHoneycomb.pm +++ /dev/null @@ -1,230 +0,0 @@ -package Slic3r::Fill::3DHoneycomb; -use Moo; - -extends 'Slic3r::Fill::Base'; - -use POSIX qw(ceil fmod); -use Slic3r::Geometry qw(scale scaled_epsilon); -use Slic3r::Geometry::Clipper qw(intersection_pl); - -# require bridge flow since most of this pattern hangs in air -sub use_bridge_flow { 1 } - -sub fill_surface { - my ($self, $surface, %params) = @_; - - my $expolygon = $surface->expolygon; - my $bb = $expolygon->bounding_box; - my $size = $bb->size; - - my $distance = scale($self->spacing) / $params{density}; - - # align bounding box to a multiple of our honeycomb grid module - # (a module is 2*$distance since one $distance half-module is - # growing while the other $distance half-module is shrinking) - { - my $min = $bb->min_point; - $min->translate( - -($bb->x_min % (2*$distance)), - -($bb->y_min % (2*$distance)), - ); - $bb->merge_point($min); - } - - # generate pattern - my @polylines = map Slic3r::Polyline->new(@$_), - makeGrid( - scale($self->z), - $distance, - ceil($size->x / $distance) + 1, - ceil($size->y / $distance) + 1, #// - (($self->layer_id / $surface->thickness_layers) % 2) + 1, - ); - - # move pattern in place - $_->translate($bb->x_min, $bb->y_min) for @polylines; - - # clip pattern to boundaries - @polylines = @{intersection_pl(\@polylines, \@$expolygon)}; - - # connect lines - unless ($params{dont_connect} || !@polylines) { # prevent calling leftmost_point() on empty collections - my ($expolygon_off) = @{$expolygon->offset_ex(scaled_epsilon)}; - my $collection = Slic3r::Polyline::Collection->new(@polylines); - @polylines = (); - foreach my $polyline (@{$collection->chained_path_from($collection->leftmost_point, 0)}) { - # try to append this polyline to previous one if any - if (@polylines) { - my $line = Slic3r::Line->new($polylines[-1]->last_point, $polyline->first_point); - if ($line->length <= 1.5*$distance && $expolygon_off->contains_line($line)) { - $polylines[-1]->append_polyline($polyline); - next; - } - } - - # make a clone before $collection goes out of scope - push @polylines, $polyline->clone; - } - } - - # TODO: return ExtrusionLoop objects to get better chained paths - return @polylines; -} - - -=head1 DESCRIPTION - -Creates a contiguous sequence of points at a specified height that make -up a horizontal slice of the edges of a space filling truncated -octahedron tesselation. The octahedrons are oriented so that the -square faces are in the horizontal plane with edges parallel to the X -and Y axes. - -Credits: David Eccles (gringer). - -=head2 makeGrid(z, gridSize, gridWidth, gridHeight, curveType) - -Generate a set of curves (array of array of 2d points) that describe a -horizontal slice of a truncated regular octahedron with a specified -grid square size. - -=cut - -sub makeGrid { - my ($z, $gridSize, $gridWidth, $gridHeight, $curveType) = @_; - my $scaleFactor = $gridSize; - my $normalisedZ = $z / $scaleFactor; - my @points = makeNormalisedGrid($normalisedZ, $gridWidth, $gridHeight, $curveType); - foreach my $lineRef (@points) { - foreach my $pointRef (@$lineRef) { - $pointRef->[0] *= $scaleFactor; - $pointRef->[1] *= $scaleFactor; - } - } - return @points; -} - -=head1 FUNCTIONS -=cut - -=head2 colinearPoints(offset, gridLength) - -Generate an array of points that are in the same direction as the -basic printing line (i.e. Y points for columns, X points for rows) - -Note: a negative offset only causes a change in the perpendicular -direction - -=cut - -sub colinearPoints { - my ($offset, $baseLocation, $gridLength) = @_; - - my @points = (); - push @points, $baseLocation - abs($offset/2); - for (my $i = 0; $i < $gridLength; $i++) { - push @points, $baseLocation + $i + abs($offset/2); - push @points, $baseLocation + ($i+1) - abs($offset/2); - } - push @points, $baseLocation + $gridLength + abs($offset/2); - return @points; -} - -=head2 colinearPoints(offset, baseLocation, gridLength) - -Generate an array of points for the dimension that is perpendicular to -the basic printing line (i.e. X points for columns, Y points for rows) - -=cut - -sub perpendPoints { - my ($offset, $baseLocation, $gridLength) = @_; - - my @points = (); - my $side = 2*(($baseLocation) % 2) - 1; - push @points, $baseLocation - $offset/2 * $side; - for (my $i = 0; $i < $gridLength; $i++) { - $side = 2*(($i+$baseLocation) % 2) - 1; - push @points, $baseLocation + $offset/2 * $side; - push @points, $baseLocation + $offset/2 * $side; - } - push @points, $baseLocation - $offset/2 * $side; - - return @points; -} - -=head2 trim(pointArrayRef, minX, minY, maxX, maxY) - -Trims an array of points to specified rectangular limits. Point -components that are outside these limits are set to the limits. - -=cut - -sub trim { - my ($pointArrayRef, $minX, $minY, $maxX, $maxY) = @_; - - foreach (@$pointArrayRef) { - $_->[0] = ($_->[0] < $minX) ? $minX : (($_->[0] > $maxX) ? $maxX : $_->[0]); - $_->[1] = ($_->[1] < $minY) ? $minY : (($_->[1] > $maxY) ? $maxY : $_->[1]); - } -} - -=head2 makeNormalisedGrid(z, gridWidth, gridHeight, curveType) - -Generate a set of curves (array of array of 2d points) that describe a -horizontal slice of a truncated regular octahedron with edge length 1. - -curveType specifies which lines to print, 1 for vertical lines -(columns), 2 for horizontal lines (rows), and 3 for both. - -=cut - -sub makeNormalisedGrid { - my ($z, $gridWidth, $gridHeight, $curveType) = @_; - - ## offset required to create a regular octagram - my $octagramGap = 0.5; - - # sawtooth wave function for range f($z) = [-$octagramGap .. $octagramGap] - my $a = sqrt(2); # period - my $wave = abs(fmod($z, $a) - $a/2)/$a*4 - 1; - my $offset = $wave * $octagramGap; - - my @points = (); - if (($curveType & 1) != 0) { - for (my $x = 0; $x <= $gridWidth; $x++) { - my @xPoints = perpendPoints($offset, $x, $gridHeight); - my @yPoints = colinearPoints($offset, 0, $gridHeight); - # This is essentially @newPoints = zip(@xPoints, @yPoints) - my @newPoints = map [ $xPoints[$_], $yPoints[$_] ], 0..$#xPoints; - - # trim points to grid edges - #trim(\@newPoints, 0, 0, $gridWidth, $gridHeight); - - if ($x % 2 == 0){ - push @points, [ @newPoints ]; - } else { - push @points, [ reverse @newPoints ]; - } - } - } - if (($curveType & 2) != 0) { - for (my $y = 0; $y <= $gridHeight; $y++) { - my @xPoints = colinearPoints($offset, 0, $gridWidth); - my @yPoints = perpendPoints($offset, $y, $gridWidth); - my @newPoints = map [ $xPoints[$_], $yPoints[$_] ], 0..$#xPoints; - - # trim points to grid edges - #trim(\@newPoints, 0, 0, $gridWidth, $gridHeight); - - if ($y % 2 == 0) { - push @points, [ @newPoints ]; - } else { - push @points, [ reverse @newPoints ]; - } - } - } - return @points; -} - -1; diff --git a/lib/Slic3r/Fill/Base.pm b/lib/Slic3r/Fill/Base.pm deleted file mode 100644 index 75c8e03e6..000000000 --- a/lib/Slic3r/Fill/Base.pm +++ /dev/null @@ -1,91 +0,0 @@ -package Slic3r::Fill::Base; -use Moo; - -has 'layer_id' => (is => 'rw'); -has 'z' => (is => 'rw'); # in unscaled coordinates -has 'angle' => (is => 'rw'); # in radians, ccw, 0 = East -has 'spacing' => (is => 'rw'); # in unscaled coordinates -has 'loop_clipping' => (is => 'rw', default => sub { 0 }); # in scaled coordinates -has 'bounding_box' => (is => 'ro', required => 0); # Slic3r::Geometry::BoundingBox object - -sub adjust_solid_spacing { - my $self = shift; - my %params = @_; - - my $number_of_lines = int($params{width} / $params{distance}) + 1; - return $params{distance} if $number_of_lines <= 1; - - my $extra_space = $params{width} % $params{distance}; - return $params{distance} + $extra_space / ($number_of_lines - 1); -} - -sub no_sort { 0 } -sub use_bridge_flow { 0 } - - -package Slic3r::Fill::WithDirection; -use Moo::Role; - -use Slic3r::Geometry qw(PI rad2deg); - -sub angles () { [0, PI/2] } - -sub infill_direction { - my $self = shift; - my ($surface) = @_; - - if (!defined $self->angle) { - warn "Using undefined infill angle"; - $self->angle(0); - } - - # set infill angle - my (@rotate); - $rotate[0] = $self->angle; - $rotate[1] = $self->bounding_box - ? $self->bounding_box->center - : $surface->expolygon->bounding_box->center; - my $shift = $rotate[1]->clone; - - if (defined $self->layer_id) { - # alternate fill direction - my $layer_num = $self->layer_id / $surface->thickness_layers; - my $angle = $self->angles->[$layer_num % @{$self->angles}]; - $rotate[0] = $self->angle + $angle if $angle; - } - - # use bridge angle - if ($surface->bridge_angle >= 0) { - Slic3r::debugf "Filling bridge with angle %d\n", rad2deg($surface->bridge_angle); - $rotate[0] = $surface->bridge_angle; - } - - $rotate[0] += PI/2; - $shift->rotate(@rotate); - return [\@rotate, $shift]; -} - -# this method accepts any object that implements rotate() and translate() -sub rotate_points { - my $self = shift; - my ($expolygon, $rotate_vector) = @_; - - # rotate points - my ($rotate, $shift) = @$rotate_vector; - $rotate = [ -$rotate->[0], $rotate->[1] ]; - $expolygon->rotate(@$rotate); - $expolygon->translate(@$shift); -} - -sub rotate_points_back { - my $self = shift; - my ($paths, $rotate_vector) = @_; - - my ($rotate, $shift) = @$rotate_vector; - $shift = [ map -$_, @$shift ]; - - $_->translate(@$shift) for @$paths; - $_->rotate(@$rotate) for @$paths; -} - -1; diff --git a/lib/Slic3r/Fill/Concentric.pm b/lib/Slic3r/Fill/Concentric.pm deleted file mode 100644 index ca1837c4e..000000000 --- a/lib/Slic3r/Fill/Concentric.pm +++ /dev/null @@ -1,57 +0,0 @@ -package Slic3r::Fill::Concentric; -use Moo; - -extends 'Slic3r::Fill::Base'; - -use Slic3r::Geometry qw(scale unscale X); -use Slic3r::Geometry::Clipper qw(offset offset2 union_pt_chained); - -sub no_sort { 1 } - -sub fill_surface { - my $self = shift; - my ($surface, %params) = @_; - - # no rotation is supported for this infill pattern - - my $expolygon = $surface->expolygon; - my $bounding_box = $expolygon->bounding_box; - - my $min_spacing = scale($self->spacing); - my $distance = $min_spacing / $params{density}; - - if ($params{density} == 1 && !$params{dont_adjust}) { - $distance = $self->adjust_solid_spacing( - width => $bounding_box->size->[X], - distance => $distance, - ); - $self->spacing(unscale $distance); - } - - my @loops = my @last = map $_->clone, @$expolygon; - while (@last) { - push @loops, @last = @{offset2(\@last, -($distance + 0.5*$min_spacing), +0.5*$min_spacing)}; - } - - # generate paths from the outermost to the innermost, to avoid - # adhesion problems of the first central tiny loops - @loops = map Slic3r::Polygon->new(@$_), - reverse @{union_pt_chained(\@loops)}; - - # split paths using a nearest neighbor search - my @paths = (); - my $last_pos = Slic3r::Point->new(0,0); - foreach my $loop (@loops) { - push @paths, $loop->split_at_index($last_pos->nearest_point_index(\@$loop)); - $last_pos = $paths[-1]->last_point; - } - - # clip the paths to prevent the extruder from getting exactly on the first point of the loop - $_->clip_end($self->loop_clipping) for @paths; - @paths = grep $_->is_valid, @paths; # remove empty paths (too short, thus eaten by clipping) - - # TODO: return ExtrusionLoop objects to get better chained paths - return @paths; -} - -1; diff --git a/lib/Slic3r/Fill/Honeycomb.pm b/lib/Slic3r/Fill/Honeycomb.pm deleted file mode 100644 index b0fbd65ff..000000000 --- a/lib/Slic3r/Fill/Honeycomb.pm +++ /dev/null @@ -1,129 +0,0 @@ -package Slic3r::Fill::Honeycomb; -use Moo; - -extends 'Slic3r::Fill::Base'; -with qw(Slic3r::Fill::WithDirection); - -has 'cache' => (is => 'rw', default => sub {{}}); - -use Slic3r::Geometry qw(PI X Y MIN MAX scale scaled_epsilon); -use Slic3r::Geometry::Clipper qw(intersection intersection_pl); - -sub angles () { [0, PI/3, PI/3*2] } - -sub fill_surface { - my $self = shift; - my ($surface, %params) = @_; - - my $rotate_vector = $self->infill_direction($surface); - - # cache hexagons math - my $cache_id = sprintf "d%s_s%s", $params{density}, $self->spacing; - my $m; - if (!($m = $self->cache->{$cache_id})) { - $m = $self->cache->{$cache_id} = {}; - my $min_spacing = scale($self->spacing); - $m->{distance} = $min_spacing / $params{density}; - $m->{hex_side} = $m->{distance} / (sqrt(3)/2); - $m->{hex_width} = $m->{distance} * 2; # $m->{hex_width} == $m->{hex_side} * sqrt(3); - my $hex_height = $m->{hex_side} * 2; - $m->{pattern_height} = $hex_height + $m->{hex_side}; - $m->{y_short} = $m->{distance} * sqrt(3)/3; - $m->{x_offset} = $min_spacing / 2; - $m->{y_offset} = $m->{x_offset} * sqrt(3)/3; - $m->{hex_center} = Slic3r::Point->new($m->{hex_width}/2, $m->{hex_side}); - } - - my @polygons = (); - { - # adjust actual bounding box to the nearest multiple of our hex pattern - # and align it so that it matches across layers - - my $bounding_box = $surface->expolygon->bounding_box; - { - # rotate bounding box according to infill direction - my $bb_polygon = $bounding_box->polygon; - $bb_polygon->rotate($rotate_vector->[0][0], $m->{hex_center}); - $bounding_box = $bb_polygon->bounding_box; - - # extend bounding box so that our pattern will be aligned with other layers - # $bounding_box->[X1] and [Y1] represent the displacement between new bounding box offset and old one - $bounding_box->merge_point(Slic3r::Point->new( - $bounding_box->x_min - ($bounding_box->x_min % $m->{hex_width}), - $bounding_box->y_min - ($bounding_box->y_min % $m->{pattern_height}), - )); - } - - my $x = $bounding_box->x_min; - while ($x <= $bounding_box->x_max) { - my $p = []; - - my @x = ($x + $m->{x_offset}, $x + $m->{distance} - $m->{x_offset}); - for (1..2) { - @$p = reverse @$p; # turn first half upside down - my @p = (); - for (my $y = $bounding_box->y_min; $y <= $bounding_box->y_max; $y += $m->{y_short} + $m->{hex_side} + $m->{y_short} + $m->{hex_side}) { - push @$p, - [ $x[1], $y + $m->{y_offset} ], - [ $x[0], $y + $m->{y_short} - $m->{y_offset} ], - [ $x[0], $y + $m->{y_short} + $m->{hex_side} + $m->{y_offset} ], - [ $x[1], $y + $m->{y_short} + $m->{hex_side} + $m->{y_short} - $m->{y_offset} ], - [ $x[1], $y + $m->{y_short} + $m->{hex_side} + $m->{y_short} + $m->{hex_side} + $m->{y_offset} ]; - } - @x = map $_ + $m->{distance}, reverse @x; # draw symmetrical pattern - $x += $m->{distance}; - } - - push @polygons, Slic3r::Polygon->new(@$p); - } - - $_->rotate(-$rotate_vector->[0][0], $m->{hex_center}) for @polygons; - } - - my @paths; - if ($params{complete} || 1) { - # we were requested to complete each loop; - # in this case we don't try to make more continuous paths - @paths = map $_->split_at_first_point, - @{intersection([ $surface->p ], \@polygons)}; - - } else { - # consider polygons as polylines without re-appending the initial point: - # this cuts the last segment on purpose, so that the jump to the next - # path is more straight - @paths = @{intersection_pl( - [ map Slic3r::Polyline->new(@$_), @polygons ], - [ @{$surface->expolygon} ], - )}; - - # connect paths - if (@paths) { # prevent calling leftmost_point() on empty collections - my $collection = Slic3r::Polyline::Collection->new(@paths); - @paths = (); - foreach my $path (@{$collection->chained_path_from($collection->leftmost_point, 0)}) { - if (@paths) { - # distance between first point of this path and last point of last path - my $distance = $paths[-1]->last_point->distance_to($path->first_point); - - if ($distance <= $m->{hex_width}) { - $paths[-1]->append_polyline($path); - next; - } - } - - # make a clone before $collection goes out of scope - push @paths, $path->clone; - } - } - - # clip paths again to prevent connection segments from crossing the expolygon boundaries - @paths = @{intersection_pl( - \@paths, - [ map @$_, @{$surface->expolygon->offset_ex(scaled_epsilon)} ], - )}; - } - - return @paths; -} - -1; diff --git a/lib/Slic3r/Fill/PlanePath.pm b/lib/Slic3r/Fill/PlanePath.pm deleted file mode 100644 index 556835ec4..000000000 --- a/lib/Slic3r/Fill/PlanePath.pm +++ /dev/null @@ -1,118 +0,0 @@ -package Slic3r::Fill::PlanePath; -use Moo; - -extends 'Slic3r::Fill::Base'; -with qw(Slic3r::Fill::WithDirection); - -use Slic3r::Geometry qw(scale X1 Y1 X2 Y2); -use Slic3r::Geometry::Clipper qw(intersection_pl); - -sub angles () { [0] } -sub multiplier () { 1 } - -sub process_polyline {} - -sub fill_surface { - my $self = shift; - my ($surface, %params) = @_; - - # rotate polygons - my $expolygon = $surface->expolygon->clone; - my $rotate_vector = $self->infill_direction($surface); - $self->rotate_points($expolygon, $rotate_vector); - - my $distance_between_lines = scale($self->spacing) / $params{density} * $self->multiplier; - - # align infill across layers using the object's bounding box - my $bb_polygon = $self->bounding_box->polygon; - $self->rotate_points($bb_polygon, $rotate_vector); - my $bounding_box = $bb_polygon->bounding_box; - - (ref $self) =~ /::([^:]+)$/; - my $path = "Math::PlanePath::$1"->new; - - my $translate = Slic3r::Point->new(0,0); # vector - if ($path->x_negative || $path->y_negative) { - # if the curve extends on both positive and negative coordinate space, - # center our expolygon around origin - $translate = $bounding_box->center->negative; - } else { - # if the curve does not extend in negative coordinate space, - # move expolygon entirely in positive coordinate space - $translate = $bounding_box->min_point->negative; - } - $expolygon->translate(@$translate); - $bounding_box->translate(@$translate); - - my ($n_lo, $n_hi) = $path->rect_to_n_range( - map { $_ / $distance_between_lines } - @{$bounding_box->min_point}, - @{$bounding_box->max_point}, - ); - - my $polyline = Slic3r::Polyline->new( - map [ map { $_ * $distance_between_lines } $path->n_to_xy($_) ], ($n_lo..$n_hi) - ); - return {} if @$polyline <= 1; - - $self->process_polyline($polyline, $bounding_box); - - my @paths = @{intersection_pl([$polyline], \@$expolygon)}; - - if (0) { - require "Slic3r/SVG.pm"; - Slic3r::SVG::output("fill.svg", - no_arrows => 1, - polygons => \@$expolygon, - green_polygons => [ $bounding_box->polygon ], - polylines => [ $polyline ], - red_polylines => \@paths, - ); - } - - # paths must be repositioned and rotated back - $_->translate(@{$translate->negative}) for @paths; - $self->rotate_points_back(\@paths, $rotate_vector); - - return @paths; -} - - -package Slic3r::Fill::ArchimedeanChords; -use Moo; -extends 'Slic3r::Fill::PlanePath'; -use Math::PlanePath::ArchimedeanChords; - - -package Slic3r::Fill::Flowsnake; -use Moo; -extends 'Slic3r::Fill::PlanePath'; -use Math::PlanePath::Flowsnake; -use Slic3r::Geometry qw(X); - -# Sorry, this fill is currently broken. - -sub process_polyline { - my $self = shift; - my ($polyline, $bounding_box) = @_; - - $_->[X] += $bounding_box->center->[X] for @$polyline; -} - - -package Slic3r::Fill::HilbertCurve; -use Moo; -extends 'Slic3r::Fill::PlanePath'; -use Math::PlanePath::HilbertCurve; - - -package Slic3r::Fill::OctagramSpiral; -use Moo; -extends 'Slic3r::Fill::PlanePath'; -use Math::PlanePath::OctagramSpiral; - -sub multiplier () { sqrt(2) } - - - -1; diff --git a/lib/Slic3r/Fill/Rectilinear.pm b/lib/Slic3r/Fill/Rectilinear.pm deleted file mode 100644 index 0922ff771..000000000 --- a/lib/Slic3r/Fill/Rectilinear.pm +++ /dev/null @@ -1,168 +0,0 @@ -package Slic3r::Fill::Rectilinear; -use Moo; - -extends 'Slic3r::Fill::Base'; -with qw(Slic3r::Fill::WithDirection); - -has '_min_spacing' => (is => 'rw'); -has '_line_spacing' => (is => 'rw'); -has '_diagonal_distance' => (is => 'rw'); -has '_line_oscillation' => (is => 'rw'); - -use Slic3r::Geometry qw(scale unscale scaled_epsilon); -use Slic3r::Geometry::Clipper qw(intersection_pl); - -sub horizontal_lines { 0 } - -sub fill_surface { - my $self = shift; - my ($surface, %params) = @_; - - # rotate polygons so that we can work with vertical lines here - my $expolygon = $surface->expolygon->clone; - my $rotate_vector = $self->infill_direction($surface); - $self->rotate_points($expolygon, $rotate_vector); - - $self->_min_spacing(scale $self->spacing); - $self->_line_spacing($self->_min_spacing / $params{density}); - $self->_diagonal_distance($self->_line_spacing * 2); - $self->_line_oscillation($self->_line_spacing - $self->_min_spacing); # only for Line infill - my $bounding_box = $expolygon->bounding_box; - - # define flow spacing according to requested density - if ($params{density} == 1 && !$params{dont_adjust}) { - $self->_line_spacing($self->adjust_solid_spacing( - width => $bounding_box->size->x, - distance => $self->_line_spacing, - )); - $self->spacing(unscale $self->_line_spacing); - } else { - # extend bounding box so that our pattern will be aligned with other layers - $bounding_box->merge_point(Slic3r::Point->new( - $bounding_box->x_min - ($bounding_box->x_min % $self->_line_spacing), - $bounding_box->y_min - ($bounding_box->y_min % $self->_line_spacing), - )); - } - - # generate the basic pattern - my $x_max = $bounding_box->x_max + scaled_epsilon; - my @lines = (); - for (my $x = $bounding_box->x_min; $x <= $x_max; $x += $self->_line_spacing) { - push @lines, $self->_line($#lines, $x, $bounding_box->y_min, $bounding_box->y_max); - } - if ($self->horizontal_lines) { - my $y_max = $bounding_box->y_max + scaled_epsilon; - for (my $y = $bounding_box->y_min; $y <= $y_max; $y += $self->_line_spacing) { - push @lines, Slic3r::Polyline->new( - [$bounding_box->x_min, $y], - [$bounding_box->x_max, $y], - ); - } - } - - # clip paths against a slightly larger expolygon, so that the first and last paths - # are kept even if the expolygon has vertical sides - # the minimum offset for preventing edge lines from being clipped is scaled_epsilon; - # however we use a larger offset to support expolygons with slightly skewed sides and - # not perfectly straight - my @polylines = @{intersection_pl(\@lines, $expolygon->offset(+scale 0.02))}; - - my $extra = $self->_min_spacing * &Slic3r::INFILL_OVERLAP_OVER_SPACING; - foreach my $polyline (@polylines) { - my ($first_point, $last_point) = @$polyline[0,-1]; - if ($first_point->y > $last_point->y) { #> - ($first_point, $last_point) = ($last_point, $first_point); - } - $first_point->set_y($first_point->y - $extra); #-- - $last_point->set_y($last_point->y + $extra); #++ - } - - # connect lines - unless ($params{dont_connect} || !@polylines) { # prevent calling leftmost_point() on empty collections - # offset the expolygon by max(min_spacing/2, extra) - my ($expolygon_off) = @{$expolygon->offset_ex($self->_min_spacing/2)}; - my $collection = Slic3r::Polyline::Collection->new(@polylines); - @polylines = (); - - foreach my $polyline (@{$collection->chained_path_from($collection->leftmost_point, 0)}) { - if (@polylines) { - my $first_point = $polyline->first_point; - my $last_point = $polylines[-1]->last_point; - my @distance = map abs($first_point->$_ - $last_point->$_), qw(x y); - - # TODO: we should also check that both points are on a fill_boundary to avoid - # connecting paths on the boundaries of internal regions - if ($self->_can_connect(@distance) && $expolygon_off->contains_line(Slic3r::Line->new($last_point, $first_point))) { - $polylines[-1]->append_polyline($polyline); - next; - } - } - - # make a clone before $collection goes out of scope - push @polylines, $polyline->clone; - } - } - - # paths must be rotated back - $self->rotate_points_back(\@polylines, $rotate_vector); - - return @polylines; -} - -sub _line { - my ($self, $i, $x, $y_min, $y_max) = @_; - - return Slic3r::Polyline->new( - [$x, $y_min], - [$x, $y_max], - ); -} - -sub _can_connect { - my ($self, $dist_X, $dist_Y) = @_; - - return $dist_X <= $self->_diagonal_distance - && $dist_Y <= $self->_diagonal_distance; -} - - -package Slic3r::Fill::Line; -use Moo; -extends 'Slic3r::Fill::Rectilinear'; - -use Slic3r::Geometry qw(scaled_epsilon); - -sub _line { - my ($self, $i, $x, $y_min, $y_max) = @_; - - if ($i % 2) { - return Slic3r::Polyline->new( - [$x - $self->_line_oscillation, $y_min], - [$x + $self->_line_oscillation, $y_max], - ); - } else { - return Slic3r::Polyline->new( - [$x, $y_min], - [$x, $y_max], - ); - } -} - -sub _can_connect { - my ($self, $dist_X, $dist_Y) = @_; - - my $TOLERANCE = 10 * scaled_epsilon; - return ($dist_X >= ($self->_line_spacing - $self->_line_oscillation) - $TOLERANCE) - && ($dist_X <= ($self->_line_spacing + $self->_line_oscillation) + $TOLERANCE) - && $dist_Y <= $self->_diagonal_distance; -} - - -package Slic3r::Fill::Grid; -use Moo; -extends 'Slic3r::Fill::Rectilinear'; - -sub angles () { [0] } -sub horizontal_lines { 1 } - -1; diff --git a/lib/Slic3r/GUI/3DScene.pm b/lib/Slic3r/GUI/3DScene.pm index 162c385f1..c00e2a01c 100644 --- a/lib/Slic3r/GUI/3DScene.pm +++ b/lib/Slic3r/GUI/3DScene.pm @@ -124,6 +124,7 @@ sub mouse_event { if ($e->Entering && &Wx::wxMSW) { # wxMSW needs focus in order to catch mouse wheel events $self->SetFocus; + print "Slic3r::GUI::3DScene::Base; SetFocus\n"; } elsif ($e->LeftDClick) { $self->on_double_click->() if $self->on_double_click; diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index 5758ea83a..ddca8df2a 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -182,6 +182,7 @@ sub new { EVT_LIST_ITEM_ACTIVATED($self, $self->{list}, \&list_item_activated); EVT_KEY_DOWN($self->{list}, sub { my ($list, $event) = @_; + print "Plater.pm: Getting key $event\n"; if ($event->GetKeyCode == WXK_TAB) { $list->Navigate($event->ShiftDown ? &Wx::wxNavigateBackward : &Wx::wxNavigateForward); } else { diff --git a/lib/Slic3r/GUI/Plater/2DToolpaths.pm b/lib/Slic3r/GUI/Plater/2DToolpaths.pm index 56912888d..dc3b3fd48 100644 --- a/lib/Slic3r/GUI/Plater/2DToolpaths.pm +++ b/lib/Slic3r/GUI/Plater/2DToolpaths.pm @@ -1,10 +1,16 @@ +# 2D preview of the tool paths of a single layer, using a thin line. +# OpenGL is used to render the paths. + package Slic3r::GUI::Plater::2DToolpaths; use strict; use warnings; use utf8; +use Data::Dumper qw(Dumper); +#use Carp qw(confess); +use Carp; use Slic3r::Print::State ':steps'; -use Wx qw(:misc :sizer :slider :statictext wxWHITE); +use Wx qw(:misc :sizer :slider :statictext :keycode wxWHITE wxWANTS_CHARS); use Wx::Event qw(EVT_SLIDER EVT_KEY_DOWN); use base qw(Wx::Panel Class::Accessor); @@ -14,7 +20,7 @@ sub new { my $class = shift; my ($parent, $print) = @_; - my $self = $class->SUPER::new($parent, -1, wxDefaultPosition); + my $self = $class->SUPER::new($parent, -1, wxDefaultPosition, wxDefaultSize, wxWANTS_CHARS); $self->SetBackgroundColour(wxWHITE); # init GUI elements @@ -48,17 +54,25 @@ sub new { }); EVT_KEY_DOWN($canvas, sub { my ($s, $event) = @_; + + print "Slic3r::GUI::Plater::2DToolpaths: Getting key ", $event->GetKeyCode, "\n"; +# print Dumper(\$event); my $key = $event->GetKeyCode; - if ($key == 85 || $key == 315) { + if ($key == 85 || $key == WXK_LEFT) { + # Keys: 'D' or WXK_LEFT $slider->SetValue($slider->GetValue + 1); $self->set_z($self->{layers_z}[$slider->GetValue]); - } elsif ($key == 68 || $key == 317) { + } elsif ($key == 68 || $key == WXK_RIGHT) { + # Keys: 'U' or WXK_RIGHT $slider->SetValue($slider->GetValue - 1); $self->set_z($self->{layers_z}[$slider->GetValue]); + } elsif ($key >= 49 && $key <= 55) { + # Keys: '1' to '3' + $canvas->set_simulation_mode($key - 49); } }); - + $self->SetSizer($sizer); $self->SetMinSize($self->GetSize); $sizer->SetSizeHints($self); @@ -116,8 +130,10 @@ sub set_z { package Slic3r::GUI::Plater::2DToolpaths::Canvas; -use Wx::Event qw(EVT_PAINT EVT_SIZE EVT_IDLE EVT_MOUSEWHEEL EVT_MOUSE_EVENTS); +use Wx qw(:misc wxWANTS_CHARS); +use Wx::Event qw(EVT_PAINT EVT_SIZE EVT_IDLE EVT_MOUSEWHEEL EVT_MOUSE_EVENTS EVT_KEY_DOWN); use OpenGL qw(:glconstants :glfunctions :glufunctions :gluconstants); +use OpenGL::Shader; use base qw(Wx::GLCanvas Class::Accessor); use Wx::GLCanvas qw(:all); use List::Util qw(min max first); @@ -132,6 +148,10 @@ __PACKAGE__->mk_accessors(qw( _zoom _camera_target _drag_start_xy + _texture_name + _texture_size + _extrusion_simulator + _simulation_mode )); # make OpenGL::Array thread-safe @@ -143,13 +163,21 @@ __PACKAGE__->mk_accessors(qw( sub new { my ($class, $parent, $print) = @_; - my $self = $class->SUPER::new($parent); + my $self = $class->SUPER::new($parent, -1, wxDefaultPosition, wxDefaultSize, wxWANTS_CHARS); $self->print($print); $self->_zoom(1); - + # 2D point in model space $self->_camera_target(Slic3r::Pointf->new(0,0)); - + + # Texture for the extrusion simulator. The texture will be allocated / reallocated on Resize. + # print "new\n"; + $self->_texture_name(0); + $self->_texture_size(Slic3r::Point->new(0,0)); + $self->_extrusion_simulator(Slic3r::ExtrusionSimulator->new()); + $self->_simulation_mode(0); + # print "new end\n"; + EVT_PAINT($self, sub { my $dc = Wx::PaintDC->new($self); $self->Render($dc); @@ -200,10 +228,36 @@ sub new { $self->Refresh; }); EVT_MOUSE_EVENTS($self, \&mouse_event); + EVT_KEY_DOWN($self, sub { + my ($s, $event) = @_; + + print "Slic3r::GUI::Plater::2DToolpaths::Canvas: Getting key $event\n"; + + my $key = $event->GetKeyCode; + if ($key > 45 && $key <= 50) { + # Keys: '1' to '3' + $self->set_simulation_mode($key - 45); + } + }); return $self; } +sub Destroy { + my ($self) = @_; + + # Deallocate the OpenGL resources. + my $context = $self->GetContext; + if ($context and $self->texture_id) { + $self->SetCurrent($context); + glDeleteTextures(1, ($self->texture_id)); + $self->SetCurrent(0); + $self->texture_id(0); + $self->texture_size(new Slic3r::Point(0, 0)); + } + return $self->SUPER::Destroy; +} + sub mouse_event { my ($self, $e) = @_; @@ -213,6 +267,7 @@ sub mouse_event { if ($e->Entering && &Wx::wxMSW) { # wxMSW needs focus in order to catch mouse wheel events $self->SetFocus; + print "Slic3r::GUI::Plater::2DToolpaths::Canvas SetFocus\n"; } elsif ($e->Dragging) { if ($e->LeftIsDown || $e->MiddleIsDown || $e->RightIsDown) { # if dragging, translate view @@ -272,6 +327,14 @@ sub set_z { $self->Refresh; } +sub set_simulation_mode +{ + my ($self, $mode) = @_; + $self->_simulation_mode($mode); + $self->_dirty(1); + $self->Refresh; +} + sub Render { my ($self, $dc) = @_; @@ -280,6 +343,14 @@ sub Render { return unless my $context = $self->GetContext; $self->SetCurrent($context); $self->InitGL; + + #print glGetString(GL_VERSION), "\n"; + #print glGetString(GL_VENDOR), "\n"; + #print glGetString(GL_RENDERER), "\n"; + # my $nExtensions = glGetInteger(GL_NUM_EXTENSIONS); + # for (my $i = 0; $i < $nExtensions; ++ $i) { + # print glGetStringi(GL_EXTENSIONS, $i); + # } glClearColor(1, 1, 1, 0); glClear(GL_COLOR_BUFFER_BIT); @@ -293,7 +364,46 @@ sub Render { glDisable(GL_DEPTH_TEST); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); - + + if ($self->_simulation_mode and $self->_texture_name and $self->_texture_size->x() > 0 and $self->_texture_size->y() > 0) { + #print "draw\n"; + $self->_simulate_extrusion(); + my ($x, $y) = $self->GetSizeWH; + glEnable(GL_TEXTURE_2D); + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,GL_REPLACE); + #print "Texture name ", $self->_texture_name, "\n"; + glBindTexture(GL_TEXTURE_2D, $self->_texture_name); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexImage2D_c(GL_TEXTURE_2D, + 0, # level (0 normal, heighr is form mip-mapping) + GL_RGBA, # internal format + $self->_texture_size->x(), $self->_texture_size->y(), + 0, # border + GL_RGBA, # format RGBA color data + GL_UNSIGNED_BYTE, # unsigned byte data + $self->_extrusion_simulator->image_ptr()); # ptr to texture data + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + glOrtho(0, 1, 0, 1, 0, 1); + glBegin(GL_QUADS); + glTexCoord2f(0, 0); + glVertex2f(0, 0); + glTexCoord2f($x/$self->_texture_size->x(), 0); + glVertex2f(1, 0); + glTexCoord2f($x/$self->_texture_size->x(), $y/$self->_texture_size->y()); + glVertex2f(1, 1); + glTexCoord2f(0, $y/$self->_texture_size->y()); + glVertex2f(0, 1); + glEnd(); + glPopMatrix(); + glBindTexture(GL_TEXTURE_2D, 0); + #print "draw end\n"; + } + # anti-alias if (0) { glEnable(GL_LINE_SMOOTH); @@ -302,8 +412,9 @@ sub Render { glHint(GL_POLYGON_SMOOTH_HINT, GL_DONT_CARE); } + # Tesselator triangulates polygons with holes on the fly for the rendering purposes only. my $tess; - if (!(&Wx::wxMSW && $OpenGL::VERSION < 0.6704)) { + if ($self->_simulation_mode() == 0 and !(&Wx::wxMSW && $OpenGL::VERSION < 0.6704)) { # We can't use the GLU tesselator on MSW with older OpenGL versions # because of an upstream bug: # http://sourceforge.net/p/pogl/bugs/16/ @@ -329,7 +440,7 @@ sub Render { glTranslatef(@$copy, 0); foreach my $slice (@{$layer->slices}) { - glColor3f(0.95, 0.95, 0.95); + glColor3f(0.75, 0.75, 0.75); if ($tess) { gluTessBeginPolygon($tess); @@ -429,28 +540,93 @@ sub _draw_path { glPushMatrix(); glTranslatef(@$copy, 0); foreach my $line (@{$path->polyline->lines}) { - glBegin(GL_LINES); - glVertex2f(@{$line->a}); - glVertex2f(@{$line->b}); - glEnd(); + if (1) { + glBegin(GL_LINES); + glVertex2f(@{$line->a}); + glVertex2f(@{$line->b}); + glEnd(); + } else { + my @c = $self->color; + $self->line($line->a->x, $line->a->y, $line->b->x, $line->b->y, $path->width, $c[0], $c[1], $c[2], 0.5, 0, 0, 1); + } } glPopMatrix(); } } else { foreach my $line (@{$path->polyline->lines}) { - glBegin(GL_LINES); - glVertex2f(@{$line->a}); - glVertex2f(@{$line->b}); - glEnd(); + if (1) { + glBegin(GL_LINES); + glVertex2f(@{$line->a}); + glVertex2f(@{$line->b}); + glEnd(); + } else { + my @c = $self->color; + $self->line($line->a->x, $line->a->y, $line->b->x, $line->b->y, $path->width, $c[0], $c[1], $c[2], 0.5, 0, 0, 1); + } } } } +sub _simulate_extrusion { + #print "_simulate_extrusion"; + my ($self) = @_; + $self->_extrusion_simulator->reset_accumulator(); + foreach my $layer (@{$self->layers}) { + if (abs($layer->print_z - $self->z) < epsilon) { + #print "_simulate_extrusion - print_z ", $layer->print_z, "\n"; + my $object = $layer->object; +# print Dumper($object); + my @shifts = (defined $object) ? @{$object->_shifted_copies} : (Slic3r::Point->new(0, 0)); + foreach my $layerm (@{$layer->regions}) { +# print Dumper($layerm); + my @extrusions = (); + if ($object->step_done(STEP_PERIMETERS)) { + #print "Perimeters: ", @{$layerm->perimeters}, "\n"; +# print Dumper(\@{$layerm->perimeters}); + push @extrusions, @$_ for @{$layerm->perimeters}; + } + if ($object->step_done(STEP_INFILL)) { + #print "Fills: ", @{$layerm->fills}, "\n"; +# print Dumper(\@{$layerm->fills}); + push @extrusions, @$_ for @{$layerm->fills}; + } +# print Dumper(\@extrusions); + foreach my $extrusion_entity (@extrusions) { + #print "simulating an extrusion entity\n"; + my @paths = $extrusion_entity->isa('Slic3r::ExtrusionLoop') + ? @$extrusion_entity + : ($extrusion_entity); + foreach my $path (@paths) { + #print "simulating a path\n"; + #print Data::Dumper->Dump([$path, @paths], [qw(foo *ary)]); +# print Data::Dumper(\$path); + print "width: ", $path->width, + " height: ", $path->height, + " mm3_per_mm: ", $path->mm3_per_mm, + " height2: ", $path->mm3_per_mm / $path->height, + "\n"; + $self->_extrusion_simulator->extrude_to_accumulator($path, $_, $self->_simulation_mode()) for @shifts; + } + } + } + } + } + $self->_extrusion_simulator->evaluate_accumulator($self->_simulation_mode()); +} + sub InitGL { my $self = shift; return if $self->init; return unless $self->GetContext; + + #Vojtech: Create an OpenGL texture? + #print "initgl\n"; + my $texture_id = 0; + ($texture_id) = glGenTextures_p(1); + $self->_texture_name($texture_id); + #print "initgl end\n"; + $self->init(1); } @@ -483,7 +659,39 @@ sub Resize { $self->SetCurrent($self->GetContext); my ($x, $y) = $self->GetSizeWH; + + #print "resize\n"; + if ($self->_texture_size->x() < $x or $self->_texture_size->y() < $y) { + # Allocate a large enough OpenGL texture with power of 2 dimensions. + $self->_texture_size->set_x(1) if ($self->_texture_size->x() == 0); + $self->_texture_size->set_y(1) if ($self->_texture_size->y() == 0); + $self->_texture_size->set_x($self->_texture_size->x() * 2) while ($self->_texture_size->x() < $x); + $self->_texture_size->set_y($self->_texture_size->y() * 2) while ($self->_texture_size->y() < $y); + #print "screen size ", $x, "x", $y; + #print "texture size ", $self->_texture_size->x(), "x", $self->_texture_size->y(); + # Initialize an empty texture. + glBindTexture(GL_TEXTURE_2D, $self->_texture_name); + if (1) { + glTexImage2D_c(GL_TEXTURE_2D, + 0, # level (0 normal, heighr is form mip-mapping) + GL_RGBA, # internal format + $self->_texture_size->x(), $self->_texture_size->y(), + 0, # border + GL_RGBA, # format RGBA color data + GL_UNSIGNED_BYTE, # unsigned byte data + 0); # ptr to texture data + } + glBindTexture(GL_TEXTURE_2D, 0); + #print "resize - setimagesize\n"; + $self->_extrusion_simulator->set_image_size($self->_texture_size); + } + $self->_extrusion_simulator->set_viewport(Slic3r::Geometry::BoundingBox->new_from_points( + [Slic3r::Point->new(0, 0), Slic3r::Point->new($x, $y)])); + #print "resize end\n"; + glViewport(0, 0, $x, $y); + + Slic3r::Point->new(0,0); glMatrixMode(GL_PROJECTION); glLoadIdentity(); @@ -538,10 +746,18 @@ sub Resize { $x2 = $x1 + $new_x; } glOrtho($x1, $x2, $y1, $y2, 0, 1); - + + # Set the adjusted bounding box at the extrusion simulator. + #print "Scene bbox ", $bb->x_min, ",", $bb->y_min, " ", $bb->x_max, ",", $bb->y_max, "\n"; + #print "Setting simulator bbox ", $x1, ",", $y1, " ", $x2, ",", $y2, "\n"; + $self->_extrusion_simulator->set_bounding_box( + Slic3r::Geometry::BoundingBox->new_from_points( + [Slic3r::Point->new($x1, $y1), Slic3r::Point->new($x2, $y2)])); + glMatrixMode(GL_MODELVIEW); } +# Thick line drawing is not used anywhere. Probably not tested? sub line { my ( $x1, $y1, $x2, $y2, # coordinates of the line @@ -551,6 +767,8 @@ sub line { # Br=alpha of color when alphablend=true $alphablend, # use alpha blend or not ) = @_; + + #die 'Inside 2DToolpaths::line(). This was not expected to be called.'; my $t; my $R; @@ -719,6 +937,8 @@ sub line { } +# What is the purpose of this dialog? Testing? A stand-alone application? +# Currently this dialog is not instantiated. package Slic3r::GUI::Plater::2DToolpaths::Dialog; use Wx qw(:dialog :id :misc :sizer); diff --git a/lib/Slic3r/GUI/Plater/3DPreview.pm b/lib/Slic3r/GUI/Plater/3DPreview.pm index fa71fcb1d..f85c27d2a 100644 --- a/lib/Slic3r/GUI/Plater/3DPreview.pm +++ b/lib/Slic3r/GUI/Plater/3DPreview.pm @@ -50,6 +50,8 @@ sub new { }); EVT_KEY_DOWN($canvas, sub { my ($s, $event) = @_; + + print "3DPreview.pm: Getting key $event\n"; my $key = $event->GetKeyCode; if ($key == 85 || $key == 315) { diff --git a/lib/Slic3r/GUI/Tab.pm b/lib/Slic3r/GUI/Tab.pm index 11707d332..e958e7677 100644 --- a/lib/Slic3r/GUI/Tab.pm +++ b/lib/Slic3r/GUI/Tab.pm @@ -77,6 +77,7 @@ sub new { }); EVT_KEY_DOWN($self->{treectrl}, sub { my ($treectrl, $event) = @_; + print "Tab.pm: Getting key $event\n"; if ($event->GetKeyCode == WXK_TAB) { $treectrl->Navigate($event->ShiftDown ? &Wx::wxNavigateBackward : &Wx::wxNavigateForward); } else { diff --git a/lib/Slic3r/Print/SupportMaterial.pm b/lib/Slic3r/Print/SupportMaterial.pm index eea6397af..a85c2cd46 100644 --- a/lib/Slic3r/Print/SupportMaterial.pm +++ b/lib/Slic3r/Print/SupportMaterial.pm @@ -675,8 +675,8 @@ sub generate_toolpaths { # interface and contact infill if (@$interface || @$contact_infill) { - $fillers{interface}->angle($interface_angle); - $fillers{interface}->spacing($_interface_flow->spacing); + $fillers{interface}->set_angle($interface_angle); + $fillers{interface}->set_spacing($_interface_flow->spacing); # find centerline of the external loop $interface = offset2($interface, +scaled_epsilon, -(scaled_epsilon + $_interface_flow->scaled_width/2)); @@ -725,11 +725,11 @@ sub generate_toolpaths { # support or flange if (@$base) { my $filler = $fillers{support}; - $filler->angle($angles[ ($layer_id) % @angles ]); + $filler->set_angle($angles[ ($layer_id) % @angles ]); # We don't use $base_flow->spacing because we need a constant spacing # value that guarantees that all layers are correctly aligned. - $filler->spacing($flow->spacing); + $filler->set_spacing($flow->spacing); my $density = $support_density; my $base_flow = $_flow; @@ -742,13 +742,13 @@ sub generate_toolpaths { # base flange if ($layer_id == 0) { $filler = $fillers{interface}; - $filler->angle($self->object_config->support_material_angle + 90); + $filler->set_angle($self->object_config->support_material_angle + 90); $density = 0.5; $base_flow = $self->first_layer_flow; # use the proper spacing for first layer as we don't need to align # its pattern to the other layers - $filler->spacing($base_flow->spacing); + $filler->set_spacing($base_flow->spacing); } else { # draw a perimeter all around support infill # TODO: use brim ordering algorithm diff --git a/slic3r.pl b/slic3r.pl index b1f40847d..715f7194b 100755 --- a/slic3r.pl +++ b/slic3r.pl @@ -13,10 +13,17 @@ use Getopt::Long qw(:config no_auto_abbrev); use List::Util qw(first); use POSIX qw(setlocale LC_NUMERIC); use Slic3r; +use Slic3r::GUI; use Time::HiRes qw(gettimeofday tv_interval); +#use Slic3r::XS; +#use Data::Dumper; $|++; binmode STDOUT, ':utf8'; +# my $extrusionsim = Slic3r::ExtrusionSimulator->new(width=>0, height=>0, nozzle_diameter=>0); +#print Dumper($extrusionsim); +#print Dumper($extrusionsim->image_ptr); + our %opt = (); my %cli_options = (); { diff --git a/slic3r.sublime-project b/slic3r.sublime-project new file mode 100644 index 000000000..9f2586dc8 --- /dev/null +++ b/slic3r.sublime-project @@ -0,0 +1,40 @@ +{ + "build_systems": + [ + { + "name": "List", + //"file_regex": " at ([^-\\s]*) line ([0-9]*)", +// "file_regex": " at (D\\:\\/src\\/Slic3r\\/.*?) line ([0-9]*)", + "shell_cmd": "ls -l" + }, + { + "name": "Run", + "working_dir": "$project_path", + "file_regex": " at (.*?) line ([0-9]*)", + "shell_cmd": "perl slic3r.pl --gui \"..\\Slic3r-tests\\gap fill torture 20 -rt.stl\"" + }, + { + "name": "full", + "file_regex": "^(..[^:]*):([0-9]+):?([0-9]+)?:? (.*)$", + "shell_cmd": "perl Build.pl" + }, + { + "name": "xs", + "working_dir": "$project_path/xs", + "file_regex": "^(..[^:]*):([0-9]+):?([0-9]+)?:? (.*)$", + "shell_cmd": "perl Build install" + }, + { + "name": "xs & run", + "working_dir": "$project_path/xs", + "file_regex": "^(..[^:]*):([0-9]+):?([0-9]+)?:? (.*)$", + "shell_cmd": "perl Build install & perl ..\\slic3r.pl --gui \"..\\..\\Slic3r-tests\\star3-big2.stl\"" + } + ], + "folders": + [ + { + "path": "." + } + ] +} diff --git a/xs/Build.PL b/xs/Build.PL index 3254dbeae..c8577c382 100644 --- a/xs/Build.PL +++ b/xs/Build.PL @@ -38,7 +38,7 @@ if (defined $ENV{BOOST_DIR}) { qw(C:\Boost\lib /lib); if ($^O eq 'MSWin32') { - for my $path (glob('C:\dev\boost*'), glob ('C:\boost*')) { + for my $path (glob('C:\dev\boost*'), glob ('C:\boost*'), glob ('d:\src\boost*')) { push @boost_include, $path; push @boost_libs, $path . "/stage/lib"; } @@ -89,6 +89,9 @@ path through the BOOST_DIR environment variable: EOF +# Enable C++ 0x features of the language. +#push @cflags, qw(-std=c++0x); + if ($ENV{SLIC3R_DEBUG}) { # only on newer GCCs: -ftemplate-backtrace-limit=0 push @cflags, qw(-DSLIC3R_DEBUG -g); diff --git a/xs/MANIFEST b/xs/MANIFEST index 0f541515d..b838290c7 100644 --- a/xs/MANIFEST +++ b/xs/MANIFEST @@ -28,6 +28,20 @@ src/libslic3r/ExtrusionEntity.cpp src/libslic3r/ExtrusionEntity.hpp src/libslic3r/ExtrusionEntityCollection.cpp src/libslic3r/ExtrusionEntityCollection.hpp +src/libslic3r/ExtrusionSimulator.cpp +src/libslic3r/ExtrusionSimulator.hpp +src/libslic3r/Fill/FillBase.cpp +src/libslic3r/Fill/FillBase.hpp +src/libslic3r/Fill/FillConcentric.cpp +src/libslic3r/Fill/FillConcentric.hpp +src/libslic3r/Fill/FillHoneycomb.cpp +src/libslic3r/Fill/FillHoneycomb.hpp +src/libslic3r/Fill/Fill3DHoneycomb.cpp +src/libslic3r/Fill/Fill3DHoneycomb.hpp +src/libslic3r/Fill/FillPlanePath.cpp +src/libslic3r/Fill/FillPlanePath.hpp +src/libslic3r/Fill/FillRectilinear.cpp +src/libslic3r/Fill/FillRectilinear.hpp src/libslic3r/Flow.cpp src/libslic3r/Flow.hpp src/libslic3r/GCode.cpp @@ -129,6 +143,8 @@ xsp/Extruder.xsp xsp/ExtrusionEntityCollection.xsp xsp/ExtrusionLoop.xsp xsp/ExtrusionPath.xsp +xsp/ExtrusionSimulator.xsp +xsp/Filler.xsp xsp/Flow.xsp xsp/GCode.xsp xsp/GCodeSender.xsp diff --git a/xs/lib/Slic3r/XS.pm b/xs/lib/Slic3r/XS.pm index 4f53966de..44ac57cdb 100644 --- a/xs/lib/Slic3r/XS.pm +++ b/xs/lib/Slic3r/XS.pm @@ -123,6 +123,26 @@ sub clone { ); } +package Slic3r::ExtrusionSimulator; + +sub new { + my ($class, %args) = @_; + return $class->_new(); +} + +package Slic3r::Filler; + +sub fill_surface { + my ($self, $surface, %args) = @_; + $self->set_width($args{width}) if defined($args{width}); + $self->set_density($args{density}) if defined($args{density}); + $self->set_distance($args{distance}) if defined($args{distance}); + $self->set_dont_connect($args{dont_connect}) if defined($args{dont_connect}); + $self->set_dont_adjust($args{dont_adjust}) if defined($args{dont_adjust}); + $self->set_complete($args{complete}) if defined($args{complete}); + return $self->_fill_surface($surface); +} + package Slic3r::Flow; sub new { @@ -215,6 +235,8 @@ for my $class (qw( Slic3r::ExtrusionLoop Slic3r::ExtrusionPath Slic3r::ExtrusionPath::Collection + Slic3r::ExtrusionSimulator + Slic3r::Filler Slic3r::Flow Slic3r::GCode Slic3r::GCode::AvoidCrossingPerimeters diff --git a/xs/src/libslic3r/ClipperUtils.cpp b/xs/src/libslic3r/ClipperUtils.cpp index aea0ef595..a1297e574 100644 --- a/xs/src/libslic3r/ClipperUtils.cpp +++ b/xs/src/libslic3r/ClipperUtils.cpp @@ -594,6 +594,10 @@ void union_pt_chained(const Slic3r::Polygons &subject, Slic3r::Polygons* retval, { ClipperLib::PolyTree pt; union_pt(subject, &pt, safety_offset_); + if (&subject == retval) + // It is safe to use the same variable for input and output, because this function makes + // a temporary copy of the results. + retval->clear(); traverse_pt(pt.Childs, retval); } diff --git a/xs/src/libslic3r/MultiPoint.cpp b/xs/src/libslic3r/MultiPoint.cpp index 1e1895634..49aceacaf 100644 --- a/xs/src/libslic3r/MultiPoint.cpp +++ b/xs/src/libslic3r/MultiPoint.cpp @@ -36,7 +36,6 @@ MultiPoint::rotate(double angle) double s = sin(angle); double c = cos(angle); for (Points::iterator it = points.begin(); it != points.end(); ++it) { - (*it).rotate(angle); double cur_x = (double)it->x; double cur_y = (double)it->y; it->x = (coord_t)round(c * cur_x - s * cur_y); diff --git a/xs/src/libslic3r/PolylineCollection.cpp b/xs/src/libslic3r/PolylineCollection.cpp index 136065127..fcf95e6c1 100644 --- a/xs/src/libslic3r/PolylineCollection.cpp +++ b/xs/src/libslic3r/PolylineCollection.cpp @@ -11,7 +11,7 @@ struct Chaining #ifndef sqr template -inline sqr(T x) { return x * x; } +inline T sqr(T x) { return x * x; } #endif /* sqr */ template @@ -43,7 +43,6 @@ inline int nearest_point_index(const std::vector &pairs, const Point & } } } - return idx; } @@ -64,12 +63,13 @@ Polylines PolylineCollection::chained_path_from( if (! no_reverse) c.last = src[i].last_point(); c.idx = i; + endpoints.push_back(c); } - Polylines retval; while (! endpoints.empty()) { // find nearest point int endpoint_index = nearest_point_index(endpoints, start_near, no_reverse); + assert(endpoint_index >= 0 && endpoint_index < endpoints.size() * 2); #if SLIC3R_CPPVER > 11 retval.push_back(std::move(src[endpoints[endpoint_index/2].idx])); #else @@ -80,6 +80,7 @@ Polylines PolylineCollection::chained_path_from( endpoints.erase(endpoints.begin() + endpoint_index/2); start_near = retval.back().last_point(); } + return retval; } #if SLIC3R_CPPVER > 11 diff --git a/xs/src/libslic3r/TriangleMesh.cpp b/xs/src/libslic3r/TriangleMesh.cpp index 484fee9fc..e4ff86640 100644 --- a/xs/src/libslic3r/TriangleMesh.cpp +++ b/xs/src/libslic3r/TriangleMesh.cpp @@ -445,7 +445,8 @@ TriangleMeshSlicer::slice(const std::vector &z, std::vector* la float min_z = fminf(facet->vertex[0].z, fminf(facet->vertex[1].z, facet->vertex[2].z)); float max_z = fmaxf(facet->vertex[0].z, fmaxf(facet->vertex[1].z, facet->vertex[2].z)); - #ifdef SLIC3R_DEBUG + #if 0 + // #ifdef SLIC3R_DEBUG printf("\n==> FACET %d (%f,%f,%f - %f,%f,%f - %f,%f,%f):\n", facet_idx, facet->vertex[0].x, facet->vertex[0].y, facet->vertex[0].z, facet->vertex[1].x, facet->vertex[1].y, facet->vertex[1].z, @@ -457,7 +458,8 @@ TriangleMeshSlicer::slice(const std::vector &z, std::vector* la std::vector::const_iterator min_layer, max_layer; min_layer = std::lower_bound(z.begin(), z.end(), min_z); // first layer whose slice_z is >= min_z max_layer = std::upper_bound(z.begin() + (min_layer - z.begin()), z.end(), max_z) - 1; // last layer whose slice_z is <= max_z - #ifdef SLIC3R_DEBUG + #if 0 + // #ifdef SLIC3R_DEBUG printf("layers: min = %d, max = %d\n", (int)(min_layer - z.begin()), (int)(max_layer - z.begin())); #endif @@ -473,7 +475,8 @@ TriangleMeshSlicer::slice(const std::vector &z, std::vector* la layers->resize(z.size()); for (std::vector::iterator it = lines.begin(); it != lines.end(); ++it) { size_t layer_idx = it - lines.begin(); - #ifdef SLIC3R_DEBUG + #if 0 + // #ifdef SLIC3R_DEBUG printf("Layer %zu:\n", layer_idx); #endif this->make_loops(*it, &(*layers)[layer_idx]); @@ -488,7 +491,8 @@ TriangleMeshSlicer::slice(const std::vector &z, std::vector* layers->resize(z.size()); for (std::vector::const_iterator loops = layers_p.begin(); loops != layers_p.end(); ++loops) { - #ifdef SLIC3R_DEBUG + #if 0 + // #ifdef SLIC3R_DEBUG size_t layer_id = loops - layers_p.begin(); printf("Layer %zu (slice_z = %.2f):\n", layer_id, z[layer_id]); #endif @@ -712,7 +716,8 @@ TriangleMeshSlicer::make_loops(std::vector &lines, Polygons* l } loops->push_back(p); - #ifdef SLIC3R_DEBUG + #if 0 + // #ifdef SLIC3R_DEBUG printf(" Discovered %s polygon of %d points\n", (p.is_counter_clockwise() ? "ccw" : "cw"), (int)p.points.size()); #endif @@ -833,7 +838,8 @@ TriangleMeshSlicer::make_expolygons(const Polygons &loops, ExPolygons* slices) ExPolygons ex_slices; offset2(p_slices, &ex_slices, +safety_offset, -safety_offset); - #ifdef SLIC3R_DEBUG + #if 0 + // #ifdef SLIC3R_DEBUG size_t holes_count = 0; for (ExPolygons::const_iterator e = ex_slices.begin(); e != ex_slices.end(); ++e) { holes_count += e->holes.size(); @@ -1052,7 +1058,8 @@ TriangleMeshSlicer::TriangleMeshSlicer(TriangleMesh* _mesh) : mesh(_mesh), v_sca } this->facets_edges[facet_idx][i] = edge_idx; - #ifdef SLIC3R_DEBUG + #if 0 + // #ifdef SLIC3R_DEBUG printf(" [facet %d, edge %d] a_id = %d, b_id = %d --> edge %d\n", facet_idx, i, a_id, b_id, edge_idx); #endif } diff --git a/xs/src/perlglue.cpp b/xs/src/perlglue.cpp index 55e00bc3a..6dda82a1b 100644 --- a/xs/src/perlglue.cpp +++ b/xs/src/perlglue.cpp @@ -1,5 +1,6 @@ #ifdef SLIC3RXS #include +#include namespace Slic3r { @@ -10,6 +11,8 @@ REGISTER_CLASS(ExtrusionPath, "ExtrusionPath"); REGISTER_CLASS(ExtrusionLoop, "ExtrusionLoop"); // there is no ExtrusionLoop::Collection or ExtrusionEntity::Collection REGISTER_CLASS(ExtrusionEntityCollection, "ExtrusionPath::Collection"); +REGISTER_CLASS(ExtrusionSimulator, "ExtrusionSimulator"); +REGISTER_CLASS(Filler, "Filler"); REGISTER_CLASS(Flow, "Flow"); REGISTER_CLASS(AvoidCrossingPerimeters, "GCode::AvoidCrossingPerimeters"); REGISTER_CLASS(OozePrevention, "GCode::OozePrevention"); @@ -391,6 +394,7 @@ void from_SV(SV* poly_sv, MultiPoint* THIS) void from_SV_check(SV* poly_sv, MultiPoint* THIS) { if (sv_isobject(poly_sv) && (SvTYPE(SvRV(poly_sv)) == SVt_PVMG)) { +// (MultiPoint*)SvIV((SV*)SvRV( poly_sv )) *THIS = *(MultiPoint*)SvIV((SV*)SvRV( poly_sv )); } else { from_SV(poly_sv, THIS); diff --git a/xs/xsp/my.map b/xs/xsp/my.map index 5f87f51c2..4d4d5d997 100644 --- a/xs/xsp/my.map +++ b/xs/xsp/my.map @@ -112,6 +112,14 @@ ExtrusionLoop* O_OBJECT_SLIC3R Ref O_OBJECT_SLIC3R_T Clone O_OBJECT_SLIC3R_T +ExtrusionSimulator* O_OBJECT_SLIC3R +Ref O_OBJECT_SLIC3R_T +Clone O_OBJECT_SLIC3R_T + +Filler* O_OBJECT_SLIC3R +Ref O_OBJECT_SLIC3R_T +Clone O_OBJECT_SLIC3R_T + Flow* O_OBJECT_SLIC3R Ref O_OBJECT_SLIC3R_T Clone O_OBJECT_SLIC3R_T @@ -214,6 +222,7 @@ GLVertexArray* O_OBJECT_SLIC3R Axis T_UV ExtrusionLoopRole T_UV ExtrusionRole T_UV +ExtrusionSimulationType T_UV FlowRole T_UV PrintStep T_UV PrintObjectStep T_UV diff --git a/xs/xsp/typemap.xspt b/xs/xsp/typemap.xspt index 37d7a9620..3453f0067 100644 --- a/xs/xsp/typemap.xspt +++ b/xs/xsp/typemap.xspt @@ -57,6 +57,9 @@ %typemap{ExPolygonCollection*}; %typemap{Ref}{simple}; %typemap{Clone}{simple}; +%typemap{Filler*}; +%typemap{Ref}{simple}; +%typemap{Clone}{simple}; %typemap{Flow*}; %typemap{Ref}{simple}; %typemap{Clone}{simple}; @@ -81,6 +84,9 @@ %typemap{ExtrusionLoop*}; %typemap{Ref}{simple}; %typemap{Clone}{simple}; +%typemap{ExtrusionSimulator*}; +%typemap{Ref}{simple}; +%typemap{Clone}{simple}; %typemap{TriangleMesh*}; %typemap{Ref}{simple}; %typemap{Clone}{simple}; @@ -223,6 +229,12 @@ $CVar = (ExtrusionRole)SvUV($PerlVar); %}; }; +%typemap{ExtrusionSimulationType}{parsed}{ + %cpp_type{ExtrusionSimulationType}; + %precall_code{% + $CVar = (ExtrusionSimulationType)SvUV($PerlVar); + %}; +}; %typemap{FlowRole}{parsed}{ %cpp_type{FlowRole}; %precall_code{%