Browse Source

New extrusion class: ExtrusionMultiPath
This is similar to an ExtrusionLoop, but it is open.
It may contain multiple chained paths with differing parameters.
This allows one to have a hierarchy of paths, where the ExtrusionEntityCollection
will be chained by the G-code generator, but ExtrusionMultiPath will not.

bubnikv 8 years ago
parent
commit
e016c4e423

+ 1 - 0
lib/Slic3r.pm

@@ -223,6 +223,7 @@ sub thread_cleanup {
     *Slic3r::ExPolygon::Collection::DESTROY = sub {};
     *Slic3r::Extruder::DESTROY              = sub {};
     *Slic3r::ExtrusionLoop::DESTROY         = sub {};
+    *Slic3r::ExtrusionMultiPath::DESTROY    = sub {};
     *Slic3r::ExtrusionPath::DESTROY         = sub {};
     *Slic3r::ExtrusionPath::Collection::DESTROY = sub {};
     *Slic3r::ExtrusionSimulator::DESTROY    = sub {};

+ 2 - 2
lib/Slic3r/GUI/Plater/2DToolpaths.pm

@@ -488,7 +488,7 @@ sub Render {
 sub _draw {
     my ($self, $object, $print_z, $path) = @_;
     
-    my @paths = $path->isa('Slic3r::ExtrusionLoop')
+    my @paths = ($path->isa('Slic3r::ExtrusionLoop') || $path->isa('Slic3r::ExtrusionMultiPath'))
         ? @$path
         : ($path);
     
@@ -546,7 +546,7 @@ sub _simulate_extrusion {
                     push @extrusions, @$_ for @{$layerm->fills};
                 }
                 foreach my $extrusion_entity (@extrusions) {
-                    my @paths = $extrusion_entity->isa('Slic3r::ExtrusionLoop')
+                    my @paths = ($extrusion_entity->isa('Slic3r::ExtrusionLoop') || $extrusion_entity->isa('Slic3r::ExtrusionMultiPath'))
                         ? @$extrusion_entity
                         : ($extrusion_entity);
                     foreach my $path (@paths) {

+ 1 - 0
xs/MANIFEST

@@ -185,6 +185,7 @@ xsp/ExPolygonCollection.xsp
 xsp/Extruder.xsp
 xsp/ExtrusionEntityCollection.xsp
 xsp/ExtrusionLoop.xsp
+xsp/ExtrusionMultiPath.xsp
 xsp/ExtrusionPath.xsp
 xsp/ExtrusionSimulator.xsp
 xsp/Filler.xsp

+ 5 - 0
xs/lib/Slic3r/XS.pm

@@ -107,6 +107,11 @@ sub new_from_paths {
     return $loop;
 }
 
+package Slic3r::ExtrusionMultiPath;
+use overload
+    '@{}' => sub { $_[0]->arrayref },
+    'fallback' => 1;
+
 package Slic3r::ExtrusionPath;
 use overload
     '@{}' => sub { $_[0]->arrayref },

+ 56 - 0
xs/src/libslic3r/ExtrusionEntity.cpp

@@ -63,6 +63,62 @@ void ExtrusionPath::polygons_covered_by_spacing(Polygons &out, const float scale
     polygons_append(out, offset(this->polyline, 0.5f * float(flow.scaled_spacing()) + scaled_epsilon));
 }
 
+void ExtrusionMultiPath::reverse()
+{
+    for (ExtrusionPaths::iterator path = this->paths.begin(); path != this->paths.end(); ++path)
+        path->reverse();
+    std::reverse(this->paths.begin(), this->paths.end());
+}
+
+double ExtrusionMultiPath::length() const
+{
+    double len = 0;
+    for (ExtrusionPaths::const_iterator path = this->paths.begin(); path != this->paths.end(); ++path)
+        len += path->polyline.length();
+    return len;
+}
+
+void ExtrusionMultiPath::polygons_covered_by_width(Polygons &out, const float scaled_epsilon) const
+{
+    for (ExtrusionPaths::const_iterator path = this->paths.begin(); path != this->paths.end(); ++path)
+        path->polygons_covered_by_width(out, scaled_epsilon);
+}
+
+void ExtrusionMultiPath::polygons_covered_by_spacing(Polygons &out, const float scaled_epsilon) const
+{
+    for (ExtrusionPaths::const_iterator path = this->paths.begin(); path != this->paths.end(); ++path)
+        path->polygons_covered_by_spacing(out, scaled_epsilon);
+}
+
+double ExtrusionMultiPath::min_mm3_per_mm() const
+{
+    double min_mm3_per_mm = std::numeric_limits<double>::max();
+    for (ExtrusionPaths::const_iterator path = this->paths.begin(); path != this->paths.end(); ++path)
+        min_mm3_per_mm = std::min(min_mm3_per_mm, path->mm3_per_mm);
+    return min_mm3_per_mm;
+}
+
+Polyline ExtrusionMultiPath::as_polyline() const
+{
+    size_t len = 0;
+    for (size_t i_path = 0; i_path < paths.size(); ++ i_path) {
+        assert(! paths[i_path].polyline.points.empty());
+        assert(i_path == 0 || paths[i_path - 1].polyline.points.back() == paths[i_path].polyline.points.front());
+        len += paths[i_path].polyline.points.size();
+    }
+    // The connecting points between the segments are equal.
+    len -= paths.size() - 1;
+
+    Polyline out;
+    if (len > 0) {
+        out.points.reserve(len);
+        out.points.push_back(paths.front().polyline.points.front());
+        for (size_t i_path = 0; i_path < paths.size(); ++ i_path)
+            out.points.insert(out.points.end(), paths[i_path].polyline.points.begin() + 1, paths[i_path].polyline.points.end());
+    }
+    return out;
+}
+
 bool
 ExtrusionLoop::make_clockwise()
 {

+ 49 - 0
xs/src/libslic3r/ExtrusionEntity.hpp

@@ -133,6 +133,55 @@ public:
 
 typedef std::vector<ExtrusionPath> ExtrusionPaths;
 
+// Single continuous extrusion path, possibly with varying extrusion thickness, extrusion height or bridging / non bridging.
+class ExtrusionMultiPath : public ExtrusionEntity
+{
+public:
+    ExtrusionPaths paths;
+    
+    ExtrusionMultiPath() {};
+    ExtrusionMultiPath(const ExtrusionPaths &paths) : paths(paths) {};
+    ExtrusionMultiPath(const ExtrusionPath &path) { this->paths.push_back(path); }
+    bool is_loop() const { return false; }
+    bool can_reverse() const { return true; }
+    ExtrusionMultiPath* clone() const { return new ExtrusionMultiPath(*this); }
+    void reverse();
+    Point first_point() const { return this->paths.front().polyline.points.front(); }
+    Point last_point() const { return this->paths.back().polyline.points.back(); }
+    virtual double length() const;
+    bool is_perimeter() const {
+        return this->paths.front().role == erPerimeter
+            || this->paths.front().role == erExternalPerimeter
+            || this->paths.front().role == erOverhangPerimeter;
+    }
+    bool is_infill() const {
+        return this->paths.front().role == erBridgeInfill
+            || this->paths.front().role == erInternalInfill
+            || this->paths.front().role == erSolidInfill
+            || this->paths.front().role == erTopSolidInfill;
+    }
+    bool is_solid_infill() const {
+        return this->paths.front().role == erBridgeInfill
+            || this->paths.front().role == erSolidInfill
+            || this->paths.front().role == erTopSolidInfill;
+    }
+    // Produce a list of 2D polygons covered by the extruded paths, offsetted by the extrusion width.
+    // Increase the offset by scaled_epsilon to achieve an overlap, so a union will produce no gaps.
+    void polygons_covered_by_width(Polygons &out, const float scaled_epsilon) const;
+    // Produce a list of 2D polygons covered by the extruded paths, offsetted by the extrusion spacing.
+    // Increase the offset by scaled_epsilon to achieve an overlap, so a union will produce no gaps.
+    // Useful to calculate area of an infill, which has been really filled in by a 100% rectilinear infill.
+    void polygons_covered_by_spacing(Polygons &out, const float scaled_epsilon) const;
+    Polygons polygons_covered_by_width(const float scaled_epsilon = 0.f) const
+        { Polygons out; this->polygons_covered_by_width(out, scaled_epsilon); return out; }
+    Polygons polygons_covered_by_spacing(const float scaled_epsilon = 0.f) const
+        { Polygons out; this->polygons_covered_by_spacing(out, scaled_epsilon); return out; }
+    // Minimum volumetric velocity of this extrusion entity. Used by the constant nozzle pressure algorithm.
+    double min_mm3_per_mm() const;
+    Polyline as_polyline() const;
+};
+
+// Single continuous extrusion loop, possibly with varying extrusion thickness, extrusion height or bridging / non bridging.
 class ExtrusionLoop : public ExtrusionEntity
 {
     public:

+ 22 - 0
xs/src/libslic3r/GCode.cpp

@@ -766,11 +766,33 @@ GCode::extrude(ExtrusionLoop loop, std::string description, double speed)
     return gcode;
 }
 
+std::string
+GCode::extrude(ExtrusionMultiPath multipath, std::string description, double speed)
+{
+    // extrude along the path
+    std::string gcode;
+    for (ExtrusionPaths::const_iterator path = multipath.paths.begin(); path != multipath.paths.end(); ++path)
+//    description += ExtrusionLoopRole2String(loop.role);
+//    description += ExtrusionRole2String(path->role);
+        gcode += this->_extrude(*path, description, speed);
+    
+    // reset acceleration
+    gcode += this->writer.set_acceleration(this->config.default_acceleration.value);
+  
+//FIXME perform wipe on multi paths?  
+//    if (this->wipe.enable)
+//        this->wipe.path = paths.front().polyline;  // TODO: don't limit wipe to last path
+    
+    return gcode;
+}
+
 std::string
 GCode::extrude(const ExtrusionEntity &entity, std::string description, double speed)
 {
     if (const ExtrusionPath* path = dynamic_cast<const ExtrusionPath*>(&entity)) {
         return this->extrude(*path, description, speed);
+    } else if (const ExtrusionMultiPath* multipath = dynamic_cast<const ExtrusionMultiPath*>(&entity)) {
+        return this->extrude(*multipath, description, speed);
     } else if (const ExtrusionLoop* loop = dynamic_cast<const ExtrusionLoop*>(&entity)) {
         return this->extrude(*loop, description, speed);
     } else {

+ 1 - 0
xs/src/libslic3r/GCode.hpp

@@ -121,6 +121,7 @@ class GCode {
     std::string change_layer(const Layer &layer);
     std::string extrude(const ExtrusionEntity &entity, std::string description = "", double speed = -1);
     std::string extrude(ExtrusionLoop loop, std::string description = "", double speed = -1);
+    std::string extrude(ExtrusionMultiPath multipath, std::string description = "", double speed = -1);
     std::string extrude(const ExtrusionPath &path, std::string description = "", double speed = -1);
     std::string travel_to(const Point &point, ExtrusionRole role, std::string comment);
     bool needs_retraction(const Polyline &travel, ExtrusionRole role = erNone);

+ 1 - 0
xs/src/perlglue.cpp

@@ -6,6 +6,7 @@ namespace Slic3r {
 REGISTER_CLASS(ExPolygon, "ExPolygon");
 REGISTER_CLASS(ExPolygonCollection, "ExPolygon::Collection");
 REGISTER_CLASS(Extruder, "Extruder");
+REGISTER_CLASS(ExtrusionMultiPath, "ExtrusionMultiPath");
 REGISTER_CLASS(ExtrusionPath, "ExtrusionPath");
 REGISTER_CLASS(ExtrusionLoop, "ExtrusionLoop");
 // there is no ExtrusionLoop::Collection or ExtrusionEntity::Collection

+ 4 - 0
xs/xsp/ExtrusionEntityCollection.xsp

@@ -53,6 +53,8 @@ ExtrusionEntityCollection::arrayref()
             // return our item by reference
             if (ExtrusionPath* path = dynamic_cast<ExtrusionPath*>(*it)) {
                 sv_setref_pv( sv, perl_class_name_ref(path), path );
+            } else if (ExtrusionMultiPath* multipath = dynamic_cast<ExtrusionMultiPath*>(*it)) {
+                sv_setref_pv( sv, perl_class_name_ref(multipath), multipath );
             } else if (ExtrusionLoop* loop = dynamic_cast<ExtrusionLoop*>(*it)) {
                 sv_setref_pv( sv, perl_class_name_ref(loop), loop );
             } else if (ExtrusionEntityCollection* collection = dynamic_cast<ExtrusionEntityCollection*>(*it)) {
@@ -77,6 +79,8 @@ ExtrusionEntityCollection::append(...)
             // append COPIES
             if (ExtrusionPath* path = dynamic_cast<ExtrusionPath*>(entity)) {
                 THIS->entities.push_back( new ExtrusionPath(*path) );
+            } else if (ExtrusionMultiPath* multipath = dynamic_cast<ExtrusionMultiPath*>(entity)) {
+                THIS->entities.push_back( new ExtrusionMultiPath(*multipath) );
             } else if (ExtrusionLoop* loop = dynamic_cast<ExtrusionLoop*>(entity)) {
                 THIS->entities.push_back( new ExtrusionLoop(*loop) );
             } else if(ExtrusionEntityCollection* collection = dynamic_cast<ExtrusionEntityCollection*>(entity)) {

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