diff --git a/xs/CMakeLists.txt b/xs/CMakeLists.txt index 63b99a835..2bf28ec01 100644 --- a/xs/CMakeLists.txt +++ b/xs/CMakeLists.txt @@ -74,6 +74,8 @@ add_library(libslic3r STATIC ${LIBDIR}/libslic3r/Fill/FillRectilinear2.hpp ${LIBDIR}/libslic3r/Fill/FillRectilinear3.cpp ${LIBDIR}/libslic3r/Fill/FillRectilinear3.hpp + ${LIBDIR}/libslic3r/Fill/FillSmooth.cpp + ${LIBDIR}/libslic3r/Fill/FillSmooth.hpp ${LIBDIR}/libslic3r/Flow.cpp ${LIBDIR}/libslic3r/Flow.hpp ${LIBDIR}/libslic3r/Format/3mf.cpp diff --git a/xs/src/libslic3r/ExtrusionEntityCollection.cpp b/xs/src/libslic3r/ExtrusionEntityCollection.cpp index 4513139e2..e99c170a4 100644 --- a/xs/src/libslic3r/ExtrusionEntityCollection.cpp +++ b/xs/src/libslic3r/ExtrusionEntityCollection.cpp @@ -207,6 +207,45 @@ ExtrusionEntityCollection::flatten() const return coll; } +/* Returns a vector of chained (new) pointers to all non-collection items contained in this one */ +void +ExtrusionEntityCollection::flattenIfSortable(ExtrusionEntityCollection* retval) const +{ + if (no_sort){ + ExtrusionEntityCollection *unsortable = new ExtrusionEntityCollection(*this); + retval->append(*unsortable); + unsortable->entities.clear(); + for (ExtrusionEntitiesPtr::const_iterator it = this->entities.begin(); it != this->entities.end(); ++it) { + if ((*it)->is_collection()) { + ExtrusionEntityCollection* collection = dynamic_cast(*it); + collection->flattenIfSortable(unsortable); + } + else { + unsortable->append(**it); + } + } + } + else{ + for (ExtrusionEntitiesPtr::const_iterator it = this->entities.begin(); it != this->entities.end(); ++it) { + if ((*it)->is_collection()) { + ExtrusionEntityCollection* collection = dynamic_cast(*it); + retval->append(collection->flattenIfSortable().entities); + } + else { + retval->append(**it); + } + } + } +} + +ExtrusionEntityCollection +ExtrusionEntityCollection::flattenIfSortable() const +{ + ExtrusionEntityCollection coll; + this->flattenIfSortable(&coll); + return coll; +} + double ExtrusionEntityCollection::min_mm3_per_mm() const { diff --git a/xs/src/libslic3r/ExtrusionEntityCollection.hpp b/xs/src/libslic3r/ExtrusionEntityCollection.hpp index 03bd2ba97..1fdea25f1 100644 --- a/xs/src/libslic3r/ExtrusionEntityCollection.hpp +++ b/xs/src/libslic3r/ExtrusionEntityCollection.hpp @@ -77,7 +77,9 @@ public: { Polygons out; this->polygons_covered_by_spacing(out, scaled_epsilon); return out; } size_t items_count() const; void flatten(ExtrusionEntityCollection* retval) const; - ExtrusionEntityCollection flatten() const; + ExtrusionEntityCollection flatten() const; + void flattenIfSortable(ExtrusionEntityCollection* retval) const; + ExtrusionEntityCollection flattenIfSortable() const; double min_mm3_per_mm() const; // Following methods shall never be called on an ExtrusionEntityCollection. diff --git a/xs/src/libslic3r/Fill/Fill.cpp b/xs/src/libslic3r/Fill/Fill.cpp index fcb12c47e..b0a80dbeb 100644 --- a/xs/src/libslic3r/Fill/Fill.cpp +++ b/xs/src/libslic3r/Fill/Fill.cpp @@ -228,9 +228,6 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out) params.density = 0.01 * density; // params.dont_adjust = true; params.dont_adjust = false; - Polylines polylines = f->fill_surface(&surface, params); - if (polylines.empty()) - continue; // calculate actual flow from spacing (which might have been adjusted by the infill // pattern generator) @@ -244,22 +241,10 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out) float flow_percent = 1; if(surface.is_overBridge()){ - flow_percent = layerm.region()->config.over_bridge_flow_ratio; + params.flow_mult = layerm.region()->config.over_bridge_flow_ratio; } - - // Save into layer. - auto *eec = new ExtrusionEntityCollection(); - out.entities.push_back(eec); - // Only concentric fills are not sorted. - eec->no_sort = f->no_sort(); - extrusion_entities_append_paths( - eec->entities, STDMOVE(polylines), - is_bridge ? - erBridgeInfill : - (surface.is_solid() ? - ((surface.surface_type == stTop) ? erTopSolidInfill : erSolidInfill) : - erInternalInfill), - flow.mm3_per_mm()*flow_percent, flow.width*flow_percent, flow.height); + + f->fill_surface_extrusion(&surface, params, flow, out); } // add thin fill regions diff --git a/xs/src/libslic3r/Fill/FillBase.cpp b/xs/src/libslic3r/Fill/FillBase.cpp index 88645b3d9..5b4d2e195 100644 --- a/xs/src/libslic3r/Fill/FillBase.cpp +++ b/xs/src/libslic3r/Fill/FillBase.cpp @@ -3,6 +3,7 @@ #include "../ClipperUtils.hpp" #include "../Surface.hpp" #include "../PrintConfig.hpp" +#include "../ExtrusionEntityCollection.hpp" #include "FillBase.hpp" #include "FillConcentric.hpp" @@ -13,6 +14,7 @@ #include "FillRectilinear.hpp" #include "FillRectilinear2.hpp" #include "FillRectilinear3.hpp" +#include "FillSmooth.hpp" namespace Slic3r { @@ -34,6 +36,7 @@ Fill* Fill::new_from_type(const InfillPattern type) case ipArchimedeanChords: return new FillArchimedeanChords(); case ipHilbertCurve: return new FillHilbertCurve(); case ipOctagramSpiral: return new FillOctagramSpiral(); + case ipSmooth: return new FillSmooth(); default: CONFESS("unknown type"); return nullptr; } } @@ -130,4 +133,25 @@ std::pair Fill::_infill_direction(const Surface *surface) const return std::pair(out_angle, out_shift); } +void Fill::fill_surface_extrusion(const Surface *surface, const FillParams ¶ms, const Flow &flow, ExtrusionEntityCollection &out ){ + Polylines polylines = this->fill_surface(surface, params); + if (polylines.empty()) + return; + + // Save into layer. + auto *eec = new ExtrusionEntityCollection(); + out.entities.push_back(eec); + // Only concentric fills are not sorted. + eec->no_sort = this->no_sort(); + extrusion_entities_append_paths( + eec->entities, STDMOVE(polylines), + flow.bridge ? + erBridgeInfill : + (surface->is_solid() ? + ((surface->is_top()) ? erTopSolidInfill : erSolidInfill) : + erInternalInfill), + flow.mm3_per_mm() * params.flow_mult, flow.width * params.flow_mult, flow.height); + +} + } // namespace Slic3r diff --git a/xs/src/libslic3r/Fill/FillBase.hpp b/xs/src/libslic3r/Fill/FillBase.hpp index 62d18e518..9048f9e90 100644 --- a/xs/src/libslic3r/Fill/FillBase.hpp +++ b/xs/src/libslic3r/Fill/FillBase.hpp @@ -9,6 +9,7 @@ #include "../libslic3r.h" #include "../BoundingBox.hpp" #include "../PrintConfig.hpp" +#include "../Flow.hpp" namespace Slic3r { @@ -20,12 +21,16 @@ struct FillParams memset(this, 0, sizeof(FillParams)); // Adjustment does not work. dont_adjust = true; + flow_mult = 1.f; } bool full_infill() const { return density > 0.9999f; } - // Fill density, fraction in <0, 1> - float density; + // Fill density, fraction in <0, 1> + float density; + + // Fill extruding flow multiplier, fraction in <0, 1>. Used by FillSmooth + float flow_mult; // Don't connect the fill lines around the inner perimeter. bool dont_connect; @@ -75,6 +80,9 @@ public: // Do not sort the fill lines to optimize the print head path? virtual bool no_sort() const { return false; } + // This method have to fill the ExtrusionEntityCollection. It call fill_surface by default + virtual void fill_surface_extrusion(const Surface *surface, const FillParams ¶ms, const Flow &flow, ExtrusionEntityCollection &out ); + // Perform the fill. virtual Polylines fill_surface(const Surface *surface, const FillParams ¶ms); diff --git a/xs/src/libslic3r/Fill/FillSmooth.cpp b/xs/src/libslic3r/Fill/FillSmooth.cpp new file mode 100644 index 000000000..6c956435f --- /dev/null +++ b/xs/src/libslic3r/Fill/FillSmooth.cpp @@ -0,0 +1,160 @@ +#include "../ClipperUtils.hpp" +#include "../PolylineCollection.hpp" +#include "../ExtrusionEntityCollection.hpp" +#include "../Surface.hpp" +#include +#include +#include + +#include "FillSmooth.hpp" + +namespace Slic3r { + +Polylines FillSmooth::fill_surface(const Surface *surface, const FillParams ¶ms) +{ + //ERROR: you shouldn't call that. Default to the rectilinear one. + printf("FillSmooth::fill_surface() : you call the wrong method (fill_surface instead of fill_surface_extrusion).\n"); + Polylines polylines_out; + return polylines_out; +} + + +void FillSmooth::fill_surface_extrusion(const Surface *surface, const FillParams ¶ms, const Flow &flow, ExtrusionEntityCollection &out ) +{ + coordf_t init_spacing = this->spacing; + + printf("FillSmooth::fill_surface() : you call the right method (fill_surface instead of fill_surface_extrusion).\n"); + //second pass with half layer width + FillParams params1 = params; + FillParams params2 = params; + FillParams params3 = params; + params1.density *= percentWidth[0]; + params2.density *= percentWidth[1]; + params3.density *= percentWidth[2]; +// Polylines polylines_layer1; +// Polylines polylines_layer2; +// Polylines polylines_layer3; + + //a small under-overlap to prevent over-extrudion on thin surfaces (i.e. remove the overlap) + Surface surfaceNoOverlap(*surface); + //remove the overlap (prevent over-extruding) + ExPolygons offsetPloys = offset2_ex(surfaceNoOverlap.expolygon, -scale_(this->overlap)*0.9, 0); + + if(offsetPloys.size() == 1) surfaceNoOverlap.expolygon = offsetPloys[0]; + //TODO: recursive if multiple polys instead of failing + + //if (! fill_surface_by_lines(&surfaceNoOverlap/* */, params1, anglePass[0], 0.f, polylines_layer1) || + // (nbPass>1 && !fill_surface_by_lines(surface, params2, anglePass[1], 0.f, polylines_layer2)) || + // (nbPass>2 && !fill_surface_by_lines(surface, params3, anglePass[2], 0.f, polylines_layer3))) { + // printf("FillSmooth::fill_surface() failed to fill a region.\n"); + //} + /* + std::cout<<"polylines_layer1 size ="<no_sort = true; + + ExtrusionEntityCollection *eec; + + // first infill + std::unique_ptr f1 = std::unique_ptr(Fill::new_from_type(fillPattern[0])); + f1->bounding_box = this->bounding_box; + f1->spacing = init_spacing; + f1->layer_id = this->layer_id; + f1->z = this->z; + f1->angle = anglePass[0]; + // Maximum length of the perimeter segment linking two infill lines. + f1->link_max_length = this->link_max_length; + // Used by the concentric infill pattern to clip the loops to create extrusion paths. + f1->loop_clipping = this->loop_clipping; + Polylines polylines_layer1 = f1->fill_surface(surface, params1); + + if (!polylines_layer1.empty()){ + eec = new ExtrusionEntityCollection(); + eecroot->entities.push_back(eec); + eec->no_sort = false; //can be sorted inside the pass + extrusion_entities_append_paths( + eec->entities, STDMOVE(polylines_layer1), + flow.bridge ? erBridgeInfill : rolePass[0], + flow.mm3_per_mm()*percentFlow[0], (float)flow.width*percentFlow[0], (float)flow.height*0.9); + //reduced flow width & height for a better view (it's only a gui thing) + } + + //second infill + if (nbPass > 1){ + + std::unique_ptr f2 = std::unique_ptr(Fill::new_from_type(fillPattern[1])); + f2->bounding_box = this->bounding_box; + f2->spacing = init_spacing; + f2->layer_id = this->layer_id; + f2->z = this->z; + f2->angle = anglePass[1]; + // Maximum length of the perimeter segment linking two infill lines. + f2->link_max_length = this->link_max_length; + // Used by the concentric infill pattern to clip the loops to create extrusion paths. + f2->loop_clipping = this->loop_clipping; + Polylines polylines_layer2 = f2->fill_surface(&surfaceNoOverlap, params2); + + if (fillPattern[2] == InfillPattern::ipRectilinear && polylines_layer2[0].points.size() > 3){ + polylines_layer2[0].points.erase(polylines_layer2[0].points.begin()); + polylines_layer2[polylines_layer2.size() - 1].points.pop_back(); + } + if (!polylines_layer2.empty()){ + + // Save into layer smoothing path. + eec = new ExtrusionEntityCollection(); + eecroot->entities.push_back(eec); + eec->no_sort = false; + // print thin + extrusion_entities_append_paths( + eec->entities, STDMOVE(polylines_layer2), + rolePass[1], + flow.mm3_per_mm()*percentFlow[1], (float)flow.width*(percentFlow[1] < 0.1 ? 0.1 : percentFlow[1]), (float)flow.height); + } + } + + // third infill + if (nbPass > 2){ + std::unique_ptr f3 = std::unique_ptr(Fill::new_from_type(fillPattern[0])); + f3->bounding_box = this->bounding_box; + f3->spacing = init_spacing; + f3->layer_id = this->layer_id; + f3->z = this->z; + f3->angle = anglePass[2]; + // Maximum length of the perimeter segment linking two infill lines. + f3->link_max_length = this->link_max_length; + // Used by the concentric infill pattern to clip the loops to create extrusion paths. + f3->loop_clipping = this->loop_clipping; + Polylines polylines_layer3 = f3->fill_surface(&surfaceNoOverlap, params1); + + //remove some points that are not inside the area + if (fillPattern[2] == InfillPattern::ipRectilinear && polylines_layer3[0].points.size() > 3){ + polylines_layer3[0].points.erase(polylines_layer3[0].points.begin()); + polylines_layer3[polylines_layer3.size() - 1].points.pop_back(); + } + if (!polylines_layer3.empty()){ + // Save into layer smoothing path. layer 3 + eec = new ExtrusionEntityCollection(); + eecroot->entities.push_back(eec); + eec->no_sort = false; + // print thin + extrusion_entities_append_paths( + eec->entities, STDMOVE(polylines_layer3), + rolePass[2], //slow (if last) + flow.mm3_per_mm()*percentFlow[2], (float)flow.width*(percentFlow[2] < 0.1 ? 0.1 : percentFlow[2]), (float)flow.height); + } + } + + if (!eecroot->entities.empty()) + out.entities.push_back(eecroot); + +} + +} // namespace Slic3r diff --git a/xs/src/libslic3r/Fill/FillSmooth.hpp b/xs/src/libslic3r/Fill/FillSmooth.hpp new file mode 100644 index 000000000..f4a7b3a50 --- /dev/null +++ b/xs/src/libslic3r/Fill/FillSmooth.hpp @@ -0,0 +1,58 @@ +#ifndef slic3r_FillSmooth_hpp_ +#define slic3r_FillSmooth_hpp_ + +#include "../libslic3r.h" + +#include "FillBase.hpp" + +namespace Slic3r { + +class FillSmooth : public Fill +{ +public: + FillSmooth() { + nbPass = 2; + anglePass[0] = float(M_PI/4); + anglePass[1] = -float(M_PI/4); + anglePass[2] = 0; + fillPattern[0] = InfillPattern::ipRectilinear; + fillPattern[1] = InfillPattern::ipRectilinear; + fillPattern[2] = InfillPattern::ipRectilinear; + rolePass[0] = erSolidInfill; + rolePass[1] = erTopSolidInfill; + rolePass[2] = erSolidInfill; + percentWidth[0] = 0.9; + percentWidth[1] = 2; + percentWidth[2] = 1.0; + percentFlow[0] = 0.7/percentWidth[0]; //* 1.25 => 0.9 + percentFlow[1] = 0.3/percentWidth[1]; //*1.25 => 0.35 + percentFlow[2] = 0.0/percentWidth[2]; + // percentWidth[0] = 2.0; + // percentWidth[1] = 0.6; + // percentWidth[2] = 1.0; + // percentFlow[0] = 0.65; + // percentFlow[1] = 0.0; + // percentFlow[2] = 0.0; +// (extrusion mult => 0.9 + 0.15*2 = 1.2) + double extrusionMult = 1.0; + percentFlow[0] *= extrusionMult; + percentFlow[1] *= extrusionMult; + percentFlow[2] *= extrusionMult; + } + virtual Fill* clone() const { return new FillSmooth(*this); } + + virtual Polylines fill_surface(const Surface *surface, const FillParams ¶ms); + virtual void fill_surface_extrusion(const Surface *surface, const FillParams ¶ms, const Flow &flow, ExtrusionEntityCollection &out ); + +protected: + int nbPass=2; + double percentWidth[3]; + double percentFlow[3]; + float anglePass[3]; + ExtrusionRole rolePass[3]; + InfillPattern fillPattern[3]; +}; + +} // namespace Slic3r + +#endif // slic3r_FillSmooth_hpp_ diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp index 8ad479532..6f6252f29 100644 --- a/xs/src/libslic3r/GCode.cpp +++ b/xs/src/libslic3r/GCode.cpp @@ -1271,8 +1271,9 @@ void GCode::process_layer( point_inside_surface(i, fill->first_point())) { if (islands[i].by_region.empty()) islands[i].by_region.assign(print.regions.size(), ObjectByExtruder::Island::Region()); - islands[i].by_region[region_id].infills.append(fill->entities); - break; + //don't do fill->entities because it will discard no_sort + islands[i].by_region[region_id].infills.append(fill->flattenIfSortable().entities); + break; } } } // for regions @@ -2001,14 +2002,34 @@ std::string GCode::extrude_infill(const Print &print, const std::vectorconfig); ExtrusionEntityCollection chained = region.infills.chained_path_from(m_last_pos, false); - for (ExtrusionEntity *fill : chained.entities) { - auto *eec = dynamic_cast(fill); - if (eec) { - ExtrusionEntityCollection chained2 = eec->chained_path_from(m_last_pos, false); - for (ExtrusionEntity *ee : chained2.entities) - gcode += this->extrude_entity(*ee, "infill"); - } else - gcode += this->extrude_entity(*fill, "infill"); + gcode += extrude_infill(print, chained); + } + return gcode; +} + +//recursive algorithm to explore the collection tree +std::string GCode::extrude_infill(const Print &print, const ExtrusionEntityCollection &collection) +{ + std::string gcode; + + ExtrusionEntityCollection chained; + if (collection.no_sort) chained = collection; + else chained = collection.chained_path_from(m_last_pos, false); + for (ExtrusionEntity *fill : chained.entities) { + auto *eec = dynamic_cast(fill); + if (eec) { + std::cout << "recursive infill with role: " << fill->role() << " : " << (fill->role() == ExtrusionRole::erBridgeInfill) << "\n"; + gcode += extrude_infill(print, *eec); + } + else { + std::cout << "extrude infill with role: " << fill->role() << " : " << (fill->role() == ExtrusionRole::erBridgeInfill) << "\n"; + if (/*print.config.disable_fan_top_layers.value && */fill->role() == ExtrusionRole::erTopSolidInfill){ //TODO: add && params.get(disable_fan_top_layers) + // gcode += ";_DISABLE_FAN_START\n"; + } + gcode += this->extrude_entity(*fill, "infill"); + if (/*print.config.disable_fan_top_layers.value && */fill->role() == ExtrusionRole::erTopSolidInfill){ //TODO: add && params.get(disable_fan_top_layers) + // gcode += ";_DISABLE_FAN_END\n"; + } } } return gcode; diff --git a/xs/src/libslic3r/GCode.hpp b/xs/src/libslic3r/GCode.hpp index 968cd14de..fbfa171d8 100644 --- a/xs/src/libslic3r/GCode.hpp +++ b/xs/src/libslic3r/GCode.hpp @@ -221,7 +221,8 @@ protected: }; std::string extrude_perimeters(const Print &print, const std::vector &by_region, std::unique_ptr &lower_layer_edge_grid); std::string extrude_infill(const Print &print, const std::vector &by_region); - std::string extrude_support(const ExtrusionEntityCollection &support_fills); + std::string extrude_infill(const Print &print, const ExtrusionEntityCollection &collection); // recursive extrude_infill + std::string extrude_support(const ExtrusionEntityCollection &support_fills); std::string travel_to(const Point &point, ExtrusionRole role, std::string comment); bool needs_retraction(const Polyline &travel, ExtrusionRole role = erNone); diff --git a/xs/src/libslic3r/PrintConfig.cpp b/xs/src/libslic3r/PrintConfig.cpp index b93eafd9a..d6a83ab43 100644 --- a/xs/src/libslic3r/PrintConfig.cpp +++ b/xs/src/libslic3r/PrintConfig.cpp @@ -264,11 +264,13 @@ PrintConfigDef::PrintConfigDef() def->enum_values.push_back("hilbertcurve"); def->enum_values.push_back("archimedeanchords"); def->enum_values.push_back("octagramspiral"); + def->enum_values.push_back("smooth"); def->enum_labels.push_back("Rectilinear"); def->enum_labels.push_back("Concentric"); def->enum_labels.push_back("Hilbert Curve"); def->enum_labels.push_back("Archimedean Chords"); def->enum_labels.push_back("Octagram Spiral"); + def->enum_labels.push_back("Ironing"); // solid_fill_pattern is an obsolete equivalent to top_fill_pattern/bottom_fill_pattern. def->aliases.push_back("solid_fill_pattern"); def->default_value = new ConfigOptionEnum(ipRectilinear); diff --git a/xs/src/libslic3r/PrintConfig.hpp b/xs/src/libslic3r/PrintConfig.hpp index e9164aba1..66c297d62 100644 --- a/xs/src/libslic3r/PrintConfig.hpp +++ b/xs/src/libslic3r/PrintConfig.hpp @@ -29,7 +29,7 @@ enum GCodeFlavor { enum InfillPattern { ipRectilinear, ipGrid, ipTriangles, ipStars, ipCubic, ipLine, ipConcentric, ipHoneycomb, ip3DHoneycomb, - ipGyroid, ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral, + ipGyroid, ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral, ipSmooth, }; enum SupportMaterialPattern { @@ -77,6 +77,7 @@ template<> inline t_config_enum_values& ConfigOptionEnum::get_enu keys_map["hilbertcurve"] = ipHilbertCurve; keys_map["archimedeanchords"] = ipArchimedeanChords; keys_map["octagramspiral"] = ipOctagramSpiral; + keys_map["smooth"] = ipSmooth; } return keys_map; }