Browse Source

New fill types (hilbertcurve, archimedeanchords, octagramspiral) and ability to use different patterns for solid layers. #20

Alessandro Ranellucci 13 years ago
parent
commit
038caddcda

+ 1 - 0
Build.PL

@@ -11,6 +11,7 @@ my $build = Module::Build->new(
         'Getopt::Long'              => '0',
         'Math::Clipper'             => '1.02',
         'Math::ConvexHull'          => '1.0.4',
+        'Math::PlanePath'           => '53',
         'Moo'                       => '0',
         'Time::HiRes'               => '0',
         'XXX'                       => '0',

+ 9 - 2
README.markdown

@@ -94,9 +94,11 @@ The author is Alessandro Ranellucci (me).
                             Use relative distances for extrusion in GCODE output
         --z-offset          Additional height in mm to add to vertical coordinates
                             (+/-, default: 0)
+        --gcode-arcs        Use G2/G3 commands for native arcs (experimental, not supported
+                            by all firmwares)
         
       Filament options:
-        --filament-diameter Diameter of your raw filament (default: 3)
+        --filament-diameter Diameter in mm of your raw filament (default: 3)
         --filament-packing-density
                             Ratio of the extruded volume over volume pushed 
                             into the extruder (default: 1)
@@ -123,7 +125,9 @@ The author is Alessandro Ranellucci (me).
                             (range: 1+, default: 3)
         --fill-density      Infill density (range: 0-1, default: 0.4)
         --fill-angle        Infill angle in degrees (range: 0-90, default: 0)
-        --start-gcode       Load initial gcode from the supplied file. This will overwrite 
+        --fill-pattern      Pattern to use to fill non-solid layers (default: rectilinear)
+        --solid-fill-pattern Pattern to use to fill solid layers (default: rectilinear)
+        --start-gcode       Load initial gcode from the supplied file. This will overwrite
                             the default command (home all axes [G28]).
         --end-gcode         Load final gcode from the supplied file. This will overwrite 
                             the default commands (turn off temperature [M104 S0],
@@ -138,6 +142,7 @@ The author is Alessandro Ranellucci (me).
                             compensating retraction (default: 0)
         --retract-before-travel
                             Only retract before travel moves of this length (default: 2)
+        --retract-lift      Lift Z by the given distance in mm when retracting (default: 0)
        
        Skirt options:
         --skirts            Number of skirts to draw (default: 1)
@@ -152,3 +157,5 @@ The author is Alessandro Ranellucci (me).
         --duplicate-distance Distance in mm between copies (default: 6)
         
 
+        
+

+ 2 - 1
lib/Slic3r.pm

@@ -60,7 +60,8 @@ our $flow_width;
 our $perimeter_offsets  = 3;
 our $solid_layers       = 3;
 our $bridge_overlap     = 3;    # mm
-our $fill_type          = 'rectilinear';
+our $fill_pattern       = 'rectilinear';
+our $solid_fill_pattern = 'rectilinear';
 our $fill_density       = 0.4;  # 1 = 100%
 our $fill_angle         = 0;
 our $start_gcode = "G28 ; home all axes";

+ 17 - 3
lib/Slic3r/Config.pm

@@ -78,6 +78,16 @@ our $Options = {
         label   => 'Solid layers',
         type    => 'i',
     },
+    'fill_pattern' => {
+        label   => 'Fill pattern',
+        type    => 'select',
+        values  => [qw(rectilinear hilbertcurve archimedeanchords octagramspiral)],
+    },
+    'solid_fill_pattern' => {
+        label   => 'Solid fill pattern',
+        type    => 'select',
+        values  => [qw(rectilinear hilbertcurve archimedeanchords octagramspiral)],
+    },
     'fill_density' => {
         label   => 'Fill density',
         type    => 'f',
@@ -266,9 +276,13 @@ sub validate {
     $Slic3r::print_center = [ split /,/, $Slic3r::print_center ]
         if !ref $Slic3r::print_center;
     
-    # --fill-type
-    die "Invalid value for --fill-type\n"
-        if !exists $Slic3r::Fill::FillTypes{$Slic3r::fill_type};
+    # --fill-pattern
+    die "Invalid value for --fill-pattern\n"
+        if !exists $Slic3r::Fill::FillTypes{$Slic3r::fill_pattern};
+    
+    # --solid-fill-pattern
+    die "Invalid value for --solid-fill-pattern\n"
+        if !exists $Slic3r::Fill::FillTypes{$Slic3r::solid_fill_pattern};
     
     # --fill-density
     die "Invalid value for --fill-density\n"

+ 68 - 9
lib/Slic3r/ExPolygon.pm

@@ -5,6 +5,7 @@ use warnings;
 # an ExPolygon is a polygon with holes
 
 use Math::Clipper qw(CT_UNION PFT_NONZERO JT_MITER);
+use Slic3r::Geometry qw(point_in_polygon X Y A B);
 use Slic3r::Geometry::Clipper qw(union_ex);
 
 # the constructor accepts an array of polygons 
@@ -24,14 +25,6 @@ sub new {
     $self;
 }
 
-# this class method accepts an array of polygons and returns
-# an array of expolygons with the right holes applied to the 
-# right contours
-sub make {
-    my $class = shift;
-    return @{ union_ex(\@_) };
-}
-
 sub contour {
     my $self = shift;
     return $self->[0];
@@ -60,7 +53,73 @@ sub offset {
     my $offsets = Math::Clipper::offset($self, $distance, $scale, $joinType, $miterLimit);
     
     # apply holes to the right contours
-    return (ref $self)->make(@$offsets);
+    return @{ union_ex($offsets) };
+}
+
+sub encloses_point {
+    my $self = shift;
+    my ($point) = @_;
+    return $self->contour->encloses_point($point)
+        && (!grep($_->encloses_point($point), $self->holes)
+            || grep($_->point_on_segment($point), $self->holes));
+}
+
+sub point_on_segment {
+    my $self = shift;
+    my ($point) = @_;
+    for (@$self) {
+        my $line = $_->point_on_segment($point);
+        return $line if $line;
+    }
+    return undef;
+}
+
+sub bounding_box {
+    my $self = shift;
+    return Slic3r::Geometry::bounding_box($self->contour);
+}
+
+sub clip_line {
+    my $self = shift;
+    my ($line) = @_;
+    $line = Slic3r::Line->cast($line);
+    
+    my @intersections = grep $_, map $_->intersection($line, 1), map $_->lines, @$self;
+    my @dir = (
+        $line->[B][X] <=> $line->[A][X],
+        $line->[B][Y] <=> $line->[A][Y],
+    );
+    
+    @intersections = sort {
+        (($a->[X] <=> $b->[X]) == $dir[X]) && (($a->[Y] <=> $b->[Y]) == $dir[Y]) ? 1 : -1
+    } @intersections, @$line;
+    
+    shift @intersections if $intersections[0]->coincides_with($intersections[1]);
+    pop @intersections if $intersections[-1]->coincides_with($intersections[-2]);
+    
+    shift @intersections
+        if !$self->encloses_point($intersections[0])
+        && !$self->point_on_segment($intersections[0]);
+    
+    my @lines = ();
+    while (@intersections) {
+        # skip tangent points
+        my @points = splice @intersections, 0, 2;
+        next if !$points[1];
+        next if $points[0]->coincides_with($points[1]);
+        push @lines, [ @points ];
+    }
+    return [@lines];
+}
+
+sub translate {
+    my $self = shift;
+    $_->translate(@_) for @$self;
+}
+
+sub rotate {
+    my $self = shift;
+    $_->rotate(@_) for @$self;
 }
 
 1;

+ 15 - 5
lib/Slic3r/Fill.pm

@@ -1,7 +1,11 @@
 package Slic3r::Fill;
 use Moo;
 
+use Slic3r::Fill::ArchimedeanChords;
 use Slic3r::Fill::Base;
+use Slic3r::Fill::Flowsnake;
+use Slic3r::Fill::HilbertCurve;
+use Slic3r::Fill::OctagramSpiral;
 use Slic3r::Fill::Rectilinear;
 use Slic3r::Fill::Rectilinear2;
 
@@ -11,14 +15,18 @@ has 'print'     => (is => 'ro', required => 1);
 has 'fillers'   => (is => 'rw', default => sub { {} });
 
 our %FillTypes = (
-    rectilinear  => 'Slic3r::Fill::Rectilinear',
-    rectilinear2 => 'Slic3r::Fill::Rectilinear2',
+    archimedeanchords   => 'Slic3r::Fill::ArchimedeanChords',
+    rectilinear         => 'Slic3r::Fill::Rectilinear',
+    rectilinear2        => 'Slic3r::Fill::Rectilinear2',
+    flowsnake           => 'Slic3r::Fill::Flowsnake',
+    octagramspiral      => 'Slic3r::Fill::OctagramSpiral',
+    hilbertcurve        => 'Slic3r::Fill::HilbertCurve',
 );
 
 sub BUILD {
     my $self = shift;
     $self->fillers->{$_} ||= $FillTypes{$_}->new(print => $self->print)
-        for ('rectilinear', $Slic3r::fill_type);
+        for ('rectilinear', $Slic3r::fill_pattern, $Slic3r::solid_fill_pattern);
 }
 
 sub make_fill {
@@ -38,13 +46,15 @@ sub make_fill {
         SURFACE: foreach my $surface (@$surfaces) {
             Slic3r::debugf " Processing surface %s:\n", $surface->id;
             
-            my $filler = $Slic3r::fill_type;
+            my $filler = $Slic3r::fill_pattern;
             my $density = $Slic3r::fill_density;
             
             # force 100% density and rectilinear fill for external surfaces
             if ($surface->surface_type ne 'internal') {
                 $density = 1;
-                $filler = 'rectilinear';
+                $filler = $surface->isa('Slic3r::Surface::Bridge')
+                    ? 'rectilinear'
+                    : $Slic3r::solid_fill_pattern;
             } else {
                 next SURFACE unless $density > 0;
             }

+ 7 - 0
lib/Slic3r/Fill/ArchimedeanChords.pm

@@ -0,0 +1,7 @@
+package Slic3r::Fill::ArchimedeanChords;
+use Moo;
+
+extends 'Slic3r::Fill::PlanePath';
+use Math::PlanePath::ArchimedeanChords;
+
+1;

+ 6 - 5
lib/Slic3r/Fill/Base.pm

@@ -35,14 +35,15 @@ sub infill_direction {
 
 sub rotate_points {
     my $self = shift;
-    my ($polygons, $rotate_vector) = @_;
+    my ($expolygon, $rotate_vector) = @_;
     my @rotate = @{$rotate_vector->[0]};
     my @shift  = @{$rotate_vector->[1]};
     
-    # rotate surface as needed
-    @$polygons = map [ Slic3r::Geometry::move_points(\@shift, @$_) ],
-        map [ Slic3r::Geometry::rotate_points(@rotate, @$_) ], @$polygons if $rotate[0];
-    
+    # rotate points as needed
+    if ($rotate[0]) {
+        $expolygon->rotate(@rotate);
+        $expolygon->translate(@shift);
+    }
 }
 
 sub rotate_points_back {

+ 18 - 0
lib/Slic3r/Fill/Flowsnake.pm

@@ -0,0 +1,18 @@
+package Slic3r::Fill::Flowsnake;
+use Moo;
+
+extends 'Slic3r::Fill::PlanePath';
+
+use Math::PlanePath::Flowsnake;
+use Slic3r::Geometry qw(X X1 X2);
+
+# Sorry, this fill is currently broken.
+
+sub process_polyline {
+    my $self = shift;
+    my ($polyline, $bounding_box) = @_;
+    
+    $_->[X] += ($bounding_box->[X1] + $bounding_box->[X2]/2) for @{$polyline->points};
+}
+
+1;

+ 7 - 0
lib/Slic3r/Fill/HilbertCurve.pm

@@ -0,0 +1,7 @@
+package Slic3r::Fill::HilbertCurve;
+use Moo;
+
+extends 'Slic3r::Fill::PlanePath';
+use Math::PlanePath::HilbertCurve;
+
+1;

Some files were not shown because too many files changed in this diff