Browse Source

Ported ExtrusionPath::Collection->chained_path

Alessandro Ranellucci 11 years ago
parent
commit
bd7b0e2aed

+ 0 - 36
lib/Slic3r/ExtrusionPath/Collection.pm

@@ -2,42 +2,6 @@ package Slic3r::ExtrusionPath::Collection;
 use strict;
 use warnings;
 
-sub first_point {
-    my $self = shift;
-    return $self->[0]->[0];
-}
-
-# (Same algorithm as Polyline::Collection)
-sub chained_path {
-    my $self = shift;
-    my ($start_near, $no_reverse) = @_;
-    
-    my @my_paths = @$self;
-    return @my_paths if $self->no_sort;
-    
-    my @paths = ();
-    my $start_at;
-    my $endpoints = $no_reverse
-        ? [ map { @$_[0,0] }  @my_paths ]
-        : [ map { @$_[0,-1] } @my_paths ];
-    while (@my_paths) {
-        # find nearest point
-        my $start_index = defined $start_near
-            ? $start_near->nearest_point_index($endpoints)
-            : 0;
-
-        my $path_index = int($start_index/2);
-        if ($start_index % 2 && !$no_reverse) { # index is end so reverse to make it the start
-            # path is reversed in place, but we got a copy from XS
-            $my_paths[$path_index]->reverse;
-        }
-        push @paths, splice @my_paths, $path_index, 1;
-        splice @$endpoints, $path_index*2, 2;
-        $start_near = $paths[-1]->last_point;
-    }
-    return @paths;
-}
-
 sub cleanup {
     my $self = shift;
     

+ 1 - 1
lib/Slic3r/GCode.pm

@@ -228,7 +228,7 @@ sub extrude_loop {
             $extrusion_path->intersect_expolygons($self->_layer_overhangs);
         
         # reapply the nearest point search for starting point
-        @paths = Slic3r::ExtrusionPath::Collection->new(@paths)->chained_path($start_at, 1);
+        @paths = @{Slic3r::ExtrusionPath::Collection->new(@paths)->chained_path_from($start_at, 1)};
     } else {
         push @paths, $extrusion_path;
     }

+ 3 - 3
lib/Slic3r/GCode/Layer.pm

@@ -111,12 +111,12 @@ sub process_layer {
             if ($layer->support_interface_fills) {
                 $gcode .= $self->gcodegen->set_extruder($self->extruders->[$Slic3r::Config->support_material_interface_extruder-1]);
                 $gcode .= $self->gcodegen->extrude_path($_, 'support material interface') 
-                    for $layer->support_interface_fills->chained_path($self->gcodegen->last_pos); 
+                    for @{$layer->support_interface_fills->chained_path_from($self->gcodegen->last_pos, 0)}; 
             }
             if ($layer->support_fills) {
                 $gcode .= $self->gcodegen->set_extruder($self->extruders->[$Slic3r::Config->support_material_extruder-1]);
                 $gcode .= $self->gcodegen->extrude_path($_, 'support material') 
-                    for $layer->support_fills->chained_path($self->gcodegen->last_pos);
+                    for @{$layer->support_fills->chained_path_from($self->gcodegen->last_pos, 0)};
             }
         }
         
@@ -214,7 +214,7 @@ sub _extrude_infill {
     for my $fill (@{ $island->{fills} }) {
         if ($fill->isa('Slic3r::ExtrusionPath::Collection')) {
             $gcode .= $self->gcodegen->extrude($_, 'fill') 
-                for $fill->chained_path($self->gcodegen->last_pos);
+                for @{$fill->chained_path_from($self->gcodegen->last_pos, 0)};
         } else {
             $gcode .= $self->gcodegen->extrude($fill, 'fill') ;
         }

+ 4 - 6
lib/Slic3r/Layer/Region.pm

@@ -300,15 +300,13 @@ sub make_perimeters {
     $self->perimeters->append(@loops);
     
     # add thin walls as perimeters
-    push @{ $self->perimeters }, Slic3r::ExtrusionPath::Collection->new(
-        map {
-            Slic3r::ExtrusionPath->new(
+    push @{ $self->perimeters }, @{Slic3r::ExtrusionPath::Collection->new(
+        map Slic3r::ExtrusionPath->new(
                 polyline        => ($_->isa('Slic3r::Polygon') ? $_->split_at_first_point : $_),
                 role            => EXTR_ROLE_EXTERNAL_PERIMETER,
                 flow_spacing    => $self->perimeter_flow->spacing,
-            );
-        } @{ $self->thin_walls }
-    )->chained_path;
+        ), @{ $self->thin_walls }
+    )->chained_path(0)};
 }
 
 sub _fill_gaps {

+ 4 - 4
t/fill.t

@@ -115,7 +115,7 @@ sub scale_points (@) { map [scale $_->[X], scale $_->[Y]], @_ }
         Slic3r::Polyline->new([0,10], [0,8], [0,5]),
     ]);
     is_deeply
-        [ map $_->[Y], map @$_, $collection->chained_path(Slic3r::Point->new(0,30)) ],
+        [ map $_->[Y], map @$_, $collection->chained_path(Slic3r::Point->new(0,30), 0) ],
         [20, 18, 15, 10, 8, 5],
         'chained path';
 }
@@ -126,7 +126,7 @@ sub scale_points (@) { map [scale $_->[X], scale $_->[Y]], @_ }
         Slic3r::Polyline->new([10,5], [15,5], [20,5]),
     ]);
     is_deeply
-        [ map $_->[X], map @$_, $collection->chained_path(Slic3r::Point->new(30,0)) ],
+        [ map $_->[X], map @$_, $collection->chained_path(Slic3r::Point->new(30,0), 0) ],
         [reverse 4, 10, 15, 10, 15, 20],
         'chained path';
 }
@@ -138,7 +138,7 @@ sub scale_points (@) { map [scale $_->[X], scale $_->[Y]], @_ }
             Slic3r::Polyline->new([0,10], [0,8], [0,5]),
     );
     is_deeply
-        [ map $_->[Y], map @{$_->polyline}, $collection->chained_path(Slic3r::Point->new(0,30)) ],
+        [ map $_->[Y], map @{$_->polyline}, @{$collection->chained_path_from(Slic3r::Point->new(0,30), 0)} ],
         [20, 18, 15, 10, 8, 5],
         'chained path';
 }
@@ -150,7 +150,7 @@ sub scale_points (@) { map [scale $_->[X], scale $_->[Y]], @_ }
             Slic3r::Polyline->new([10,5], [15,5], [20,5]),
     );
     is_deeply
-        [ map $_->[X], map @{$_->polyline}, $collection->chained_path(Slic3r::Point->new(30,0)) ],
+        [ map $_->[X], map @{$_->polyline}, @{$collection->chained_path_from(Slic3r::Point->new(30,0), 0)} ],
         [reverse 4, 10, 15, 10, 15, 20],
         'chained path';
 }

+ 34 - 4
xs/src/ExtrusionEntity.cpp

@@ -2,24 +2,36 @@
 
 namespace Slic3r {
 
+ExtrusionPath*
+ExtrusionPath::clone() const
+{
+    return new ExtrusionPath (*this);
+}
+    
 void
 ExtrusionPath::reverse()
 {
     this->polyline.reverse();
 }
 
-const Point*
-ExtrusionPath::first_point() const
+Point*
+ExtrusionPath::first_point()
 {
     return &(this->polyline.points.front());
 }
 
-const Point*
-ExtrusionPath::last_point() const
+Point*
+ExtrusionPath::last_point()
 {
     return &(this->polyline.points.back());
 }
 
+ExtrusionLoop*
+ExtrusionLoop::clone() const
+{
+    return new ExtrusionLoop (*this);
+}
+
 ExtrusionPath*
 ExtrusionLoop::split_at_index(int index)
 {
@@ -47,4 +59,22 @@ ExtrusionLoop::make_counter_clockwise()
     return this->polygon.make_counter_clockwise();
 }
 
+void
+ExtrusionLoop::reverse()
+{
+    // no-op
+}
+
+Point*
+ExtrusionLoop::first_point()
+{
+    return &(this->polygon.points.front());
+}
+
+Point*
+ExtrusionLoop::last_point()
+{
+    return &(this->polygon.points.front());  // in polygons, first == last
+}
+
 }

+ 11 - 2
xs/src/ExtrusionEntity.hpp

@@ -25,10 +25,14 @@ enum ExtrusionRole {
 class ExtrusionEntity
 {
     public:
+    virtual ExtrusionEntity* clone() const = 0;
     virtual ~ExtrusionEntity() {};
     ExtrusionRole role;
     double height;  // vertical thickness of the extrusion expressed in mm
     double flow_spacing;
+    virtual void reverse() = 0;
+    virtual Point* first_point() = 0;
+    virtual Point* last_point() = 0;
 };
 
 typedef std::vector<ExtrusionEntity*> ExtrusionEntitiesPtr;
@@ -36,19 +40,24 @@ typedef std::vector<ExtrusionEntity*> ExtrusionEntitiesPtr;
 class ExtrusionPath : public ExtrusionEntity
 {
     public:
+    ExtrusionPath* clone() const;
     Polyline polyline;
     void reverse();
-    const Point* first_point() const;
-    const Point* last_point() const;
+    Point* first_point();
+    Point* last_point();
 };
 
 class ExtrusionLoop : public ExtrusionEntity
 {
     public:
+    ExtrusionLoop* clone() const;
     Polygon polygon;
     ExtrusionPath* split_at_index(int index);
     ExtrusionPath* split_at_first_point();
     bool make_counter_clockwise();
+    void reverse();
+    Point* first_point();
+    Point* last_point();
 };
 
 }

+ 75 - 0
xs/src/ExtrusionEntityCollection.cpp

@@ -0,0 +1,75 @@
+#include "ExtrusionEntityCollection.hpp"
+
+namespace Slic3r {
+
+ExtrusionEntityCollection*
+ExtrusionEntityCollection::clone() const
+{
+    return new ExtrusionEntityCollection (*this);
+}
+
+void
+ExtrusionEntityCollection::reverse()
+{
+    for (ExtrusionEntitiesPtr::iterator it = this->entities.begin(); it != this->entities.end(); ++it) {
+        (*it)->reverse();
+    }
+    std::reverse(this->entities.begin(), this->entities.end());
+}
+
+Point*
+ExtrusionEntityCollection::first_point()
+{
+    return this->entities.front()->first_point();
+}
+
+Point*
+ExtrusionEntityCollection::last_point()
+{
+    return this->entities.back()->last_point();
+}
+
+ExtrusionEntityCollection*
+ExtrusionEntityCollection::chained_path(bool no_reverse) const
+{
+    if (this->entities.empty()) {
+        return new ExtrusionEntityCollection ();
+    }
+    return this->chained_path_from(this->entities.front()->first_point(), no_reverse);
+}
+
+ExtrusionEntityCollection*
+ExtrusionEntityCollection::chained_path_from(Point* start_near, bool no_reverse) const
+{
+    if (this->no_sort) return new ExtrusionEntityCollection(*this);
+    ExtrusionEntityCollection* retval = new ExtrusionEntityCollection;
+    ExtrusionEntitiesPtr my_paths = this->entities;
+    
+    Points endpoints;
+    for (ExtrusionEntitiesPtr::iterator it = my_paths.begin(); it != my_paths.end(); ++it) {
+        endpoints.push_back(*(*it)->first_point());
+        if (no_reverse) {
+            endpoints.push_back(*(*it)->first_point());
+        } else {
+            endpoints.push_back(*(*it)->last_point());
+        }
+    }
+    
+    while (!my_paths.empty()) {
+        // find nearest point
+        int start_index = start_near->nearest_point_index(endpoints);
+        int path_index = start_index/2;
+        if (start_index % 2 && !no_reverse) {
+            my_paths.at(path_index) = my_paths.at(path_index)->clone();  // maybe we should clone them all when building my_paths?
+            my_paths.at(path_index)->reverse();
+        }
+        retval->entities.push_back(my_paths.at(path_index));
+        my_paths.erase(my_paths.begin() + path_index);
+        endpoints.erase(endpoints.begin() + 2*path_index, endpoints.begin() + 2*path_index + 2);
+        start_near = retval->entities.back()->last_point();
+    }
+    
+    return retval;
+}
+
+}

+ 6 - 0
xs/src/ExtrusionEntityCollection.hpp

@@ -9,9 +9,15 @@ namespace Slic3r {
 class ExtrusionEntityCollection : public ExtrusionEntity
 {
     public:
+    ExtrusionEntityCollection* clone() const;
     ExtrusionEntitiesPtr entities;
     bool no_sort;
     ExtrusionEntityCollection(): no_sort(false) {};
+    ExtrusionEntityCollection* chained_path(bool no_reverse) const;
+    ExtrusionEntityCollection* chained_path_from(Point* start_near, bool no_reverse) const;
+    void reverse();
+    Point* first_point();
+    Point* last_point();
 };
 
 }

+ 28 - 1
xs/t/12_extrusionpathcollection.t

@@ -4,7 +4,7 @@ use strict;
 use warnings;
 
 use Slic3r::XS;
-use Test::More tests => 9;
+use Test::More tests => 12;
 
 my $points = [
     [100, 100],
@@ -41,5 +41,32 @@ isa_ok $collection->[3], 'Slic3r::ExtrusionLoop', 'correct object returned for l
 
 is scalar(@{$collection->[1]}), 1, 'appended collection was duplicated';
 
+{
+    my $collection = Slic3r::ExtrusionPath::Collection->new(
+        map Slic3r::ExtrusionPath->new(polyline => $_, role => 0),
+            Slic3r::Polyline->new([0,15], [0,18], [0,20]),
+            Slic3r::Polyline->new([0,10], [0,8], [0,5]),
+    );
+    is_deeply
+        [ map $_->y, map @{$_->polyline}, @{$collection->chained_path_from(Slic3r::Point->new(0,30), 0)} ],
+        [20, 18, 15, 10, 8, 5],
+        'chained_path_from';
+    is_deeply
+        [ map $_->y, map @{$_->polyline}, @{$collection->chained_path(0)} ],
+        [15, 18, 20, 10, 8, 5],
+        'chained_path';
+}
+
+{
+    my $collection = Slic3r::ExtrusionPath::Collection->new(
+        map Slic3r::ExtrusionPath->new(polyline => $_, role => 0),
+            Slic3r::Polyline->new([15,0], [10,0], [4,0]),
+            Slic3r::Polyline->new([10,5], [15,5], [20,5]),
+    );
+    is_deeply
+        [ map $_->x, map @{$_->polyline}, @{$collection->chained_path_from(Slic3r::Point->new(30,0), 0)} ],
+        [reverse 4, 10, 15, 10, 15, 20],
+        'chained_path_from';
+}
 
 __END__

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