From e0d1aa8a1a6abb4bea8526636b6de79b515c51db Mon Sep 17 00:00:00 2001 From: bubnikv Date: Mon, 26 Sep 2016 13:44:23 +0200 Subject: [PATCH] Collect the perimeter surfaces when generating perimeters. The perimeter surfaces are later used for performing infill below overhangs and to maintan configured vertical wall thickness at sloping surfaces. --- xs/src/libslic3r/Layer.cpp | 88 +++++++++++++++++++++++-- xs/src/libslic3r/Layer.hpp | 27 ++++++-- xs/src/libslic3r/LayerRegion.cpp | 85 +++++++++++++++++++++++- xs/src/libslic3r/PerimeterGenerator.cpp | 11 +++- xs/src/libslic3r/PerimeterGenerator.hpp | 5 +- xs/xsp/Layer.xsp | 27 ++++++-- xs/xsp/PerimeterGenerator.xsp | 5 +- 7 files changed, 226 insertions(+), 22 deletions(-) diff --git a/xs/src/libslic3r/Layer.cpp b/xs/src/libslic3r/Layer.cpp index a392f732e..1d5e6562d 100644 --- a/xs/src/libslic3r/Layer.cpp +++ b/xs/src/libslic3r/Layer.cpp @@ -2,7 +2,7 @@ #include "ClipperUtils.hpp" #include "Geometry.hpp" #include "Print.hpp" - +#include "SVG.hpp" namespace Slic3r { @@ -204,7 +204,11 @@ Layer::make_perimeters() if (layerms.size() == 1) { // optimization (*layerm)->fill_surfaces.surfaces.clear(); - (*layerm)->make_perimeters((*layerm)->slices, &(*layerm)->fill_surfaces); + (*layerm)->perimeter_surfaces.surfaces.clear(); + (*layerm)->make_perimeters((*layerm)->slices, &(*layerm)->perimeter_surfaces, &(*layerm)->fill_surfaces); + this->perimeter_expolygons.expolygons.clear(); + for (Surfaces::const_iterator it = (*layerm)->perimeter_surfaces.surfaces.begin(); it != (*layerm)->perimeter_surfaces.surfaces.end(); ++ it) + this->perimeter_expolygons.expolygons.push_back(it->expolygon); } else { // group slices (surfaces) according to number of extra perimeters std::map slices; // extra_perimeters => [ surface, surface... ] @@ -226,12 +230,18 @@ Layer::make_perimeters() } // make perimeters + SurfaceCollection perimeter_surfaces; SurfaceCollection fill_surfaces; - (*layerm)->make_perimeters(new_slices, &fill_surfaces); - + (*layerm)->make_perimeters(new_slices, &perimeter_surfaces, &fill_surfaces); + // Copy the perimeter surfaces to the layer's surfaces before splitting them into the regions. + this->perimeter_expolygons.expolygons.clear(); + for (Surfaces::const_iterator it = perimeter_surfaces.surfaces.begin(); it != perimeter_surfaces.surfaces.end(); ++ it) + this->perimeter_expolygons.expolygons.push_back(it->expolygon); + // assign fill_surfaces to each layer - if (!fill_surfaces.surfaces.empty()) { + if (!fill_surfaces.surfaces.empty()) { for (LayerRegionPtrs::iterator l = layerms.begin(); l != layerms.end(); ++l) { + // Separate the fill surfaces. ExPolygons expp = intersection_ex( fill_surfaces, (*l)->slices @@ -243,12 +253,80 @@ Layer::make_perimeters() s.expolygon = *ex; (*l)->fill_surfaces.surfaces.push_back(s); } + + // Separate the perimeter surfaces. + expp = intersection_ex( + perimeter_surfaces, + (*l)->slices + ); + (*l)->perimeter_surfaces.surfaces.clear(); + + for (ExPolygons::iterator ex = expp.begin(); ex != expp.end(); ++ex) { + Surface s = fill_surfaces.surfaces.front(); // clone type and extra_perimeters + s.expolygon = *ex; + (*l)->perimeter_surfaces.surfaces.push_back(s); + } } } } } } +void Layer::export_region_slices_to_svg(const char *path) +{ + BoundingBox bbox; + for (LayerRegionPtrs::const_iterator region = this->regions.begin(); region != this->regions.end(); ++region) + for (Surfaces::const_iterator surface = (*region)->slices.surfaces.begin(); surface != (*region)->slices.surfaces.end(); ++surface) + bbox.merge(get_extents(surface->expolygon)); + Point legend_size = export_surface_type_legend_to_svg_box_size(); + Point legend_pos(bbox.min.x, bbox.max.y); + bbox.merge(Point(std::max(bbox.min.x + legend_size.x, bbox.max.x), bbox.max.y + legend_size.y)); + + SVG svg(path, bbox); + const float transparency = 0.5f; + for (LayerRegionPtrs::const_iterator region = this->regions.begin(); region != this->regions.end(); ++region) + for (Surfaces::const_iterator surface = (*region)->slices.surfaces.begin(); surface != (*region)->slices.surfaces.end(); ++surface) + svg.draw(surface->expolygon, surface_type_to_color_name(surface->surface_type), transparency); + export_surface_type_legend_to_svg(svg, legend_pos); + svg.Close(); +} + +// Export to "out/LayerRegion-name-%d.svg" with an increasing index with every export. +void Layer::export_region_slices_to_svg_debug(const char *name) +{ + static size_t idx = 0; + char path[2048]; + sprintf(path, "out\\Layer-slices-%s-%d.svg", name, idx ++); + this->export_region_slices_to_svg(path); +} + +void Layer::export_region_fill_surfaces_to_svg(const char *path) +{ + BoundingBox bbox; + for (LayerRegionPtrs::const_iterator region = this->regions.begin(); region != this->regions.end(); ++region) + for (Surfaces::const_iterator surface = (*region)->fill_surfaces.surfaces.begin(); surface != (*region)->fill_surfaces.surfaces.end(); ++surface) + bbox.merge(get_extents(surface->expolygon)); + Point legend_size = export_surface_type_legend_to_svg_box_size(); + Point legend_pos(bbox.min.x, bbox.max.y); + bbox.merge(Point(std::max(bbox.min.x + legend_size.x, bbox.max.x), bbox.max.y + legend_size.y)); + + SVG svg(path, bbox); + const float transparency = 0.5f; + for (LayerRegionPtrs::const_iterator region = this->regions.begin(); region != this->regions.end(); ++region) + for (Surfaces::const_iterator surface = (*region)->fill_surfaces.surfaces.begin(); surface != (*region)->fill_surfaces.surfaces.end(); ++surface) + svg.draw(surface->expolygon, surface_type_to_color_name(surface->surface_type), transparency); + export_surface_type_legend_to_svg(svg, legend_pos); + svg.Close(); +} + +// Export to "out/LayerRegion-name-%d.svg" with an increasing index with every export. +void Layer::export_region_fill_surfaces_to_svg_debug(const char *name) +{ + static size_t idx = 0; + char path[2048]; + sprintf(path, "out\\Layer-fill_surfaces-%s-%d.svg", name, idx ++); + this->export_region_fill_surfaces_to_svg(path); +} SupportLayer::SupportLayer(size_t id, PrintObject *object, coordf_t height, coordf_t print_z, coordf_t slice_z) diff --git a/xs/src/libslic3r/Layer.hpp b/xs/src/libslic3r/Layer.hpp index 4badb8374..23bc84e90 100644 --- a/xs/src/libslic3r/Layer.hpp +++ b/xs/src/libslic3r/Layer.hpp @@ -38,6 +38,11 @@ class LayerRegion // collection of surfaces for infill generation SurfaceCollection fill_surfaces; + // Collection of perimeter surfaces. This is a cached result of diff(slices, fill_surfaces). + // While not necessary, the memory consumption is meager and it speeds up calculation. + // The perimeter_surfaces keep the IDs of the slices (top/bottom/) + SurfaceCollection perimeter_surfaces; + // collection of expolygons representing the bridged areas (thus not // needing support material) Polygons bridged; @@ -56,10 +61,16 @@ class LayerRegion Flow flow(FlowRole role, bool bridge = false, double width = -1) const; void merge_slices(); void prepare_fill_surfaces(); - void make_perimeters(const SurfaceCollection &slices, SurfaceCollection* fill_surfaces); + void make_perimeters(const SurfaceCollection &slices, SurfaceCollection* perimeter_surfaces, SurfaceCollection* fill_surfaces); void process_external_surfaces(const Layer* lower_layer); double infill_area_threshold() const; - + + void export_region_slices_to_svg(const char *path); + void export_region_fill_surfaces_to_svg(const char *path); + // Export to "out/LayerRegion-name-%d.svg" with an increasing index with every export. + void export_region_slices_to_svg_debug(const char *name); + void export_region_fill_surfaces_to_svg_debug(const char *name); + private: Layer *_layer; PrintRegion *_region; @@ -74,7 +85,7 @@ typedef std::vector LayerRegionPtrs; class Layer { friend class PrintObject; - public: +public: size_t id() const; void set_id(size_t id); PrintObject* object(); @@ -91,6 +102,8 @@ class Layer { // collection of expolygons generated by slicing the original geometry; // also known as 'islands' (all regions and surface types are merged here) ExPolygonCollection slices; + // Surfaces of the perimeters including their gap fill. + ExPolygonCollection perimeter_expolygons; size_t region_count() const; @@ -102,8 +115,14 @@ class Layer { template bool any_internal_region_slice_contains(const T &item) const; template bool any_bottom_region_slice_contains(const T &item) const; void make_perimeters(); + + void export_region_slices_to_svg(const char *path); + void export_region_fill_surfaces_to_svg(const char *path); + // Export to "out/LayerRegion-name-%d.svg" with an increasing index with every export. + void export_region_slices_to_svg_debug(const char *name); + void export_region_fill_surfaces_to_svg_debug(const char *name); - protected: +protected: size_t _id; // sequential number of layer, 0-based PrintObject *_object; diff --git a/xs/src/libslic3r/LayerRegion.cpp b/xs/src/libslic3r/LayerRegion.cpp index d713b7c1f..fe35fd04b 100644 --- a/xs/src/libslic3r/LayerRegion.cpp +++ b/xs/src/libslic3r/LayerRegion.cpp @@ -4,6 +4,10 @@ #include "PerimeterGenerator.hpp" #include "Print.hpp" #include "Surface.hpp" +#include "SVG.hpp" + +#include +#include namespace Slic3r { @@ -56,7 +60,7 @@ LayerRegion::merge_slices() } void -LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollection* fill_surfaces) +LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollection* perimeter_surfaces, SurfaceCollection* fill_surfaces) { this->perimeters.clear(); this->thin_fills.clear(); @@ -73,6 +77,7 @@ LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollection* // output: &this->perimeters, &this->thin_fills, + perimeter_surfaces, fill_surfaces ); @@ -94,10 +99,15 @@ LayerRegion::process_external_surfaces(const Layer* lower_layer) const Surfaces &surfaces = this->fill_surfaces.surfaces; const double margin = scale_(EXTERNAL_INFILL_MARGIN); +#ifdef SLIC3R_DEBUG_SLICE_PROCESSING + export_region_fill_surfaces_to_svg_debug("3_process_external_surfaces-initial"); +#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */ + SurfaceCollection bottom; + // For all stBottom && stBottomBridge surfaces: for (Surfaces::const_iterator surface = surfaces.begin(); surface != surfaces.end(); ++surface) { if (!surface->is_bottom()) continue; - + // Grown by 3mm. ExPolygons grown = offset_ex(surface->expolygon, +margin); /* detect bridge direction before merging grown surfaces otherwise adjacent bridges @@ -109,6 +119,7 @@ LayerRegion::process_external_surfaces(const Layer* lower_layer) BridgeDetector bd( surface->expolygon, lower_layer->slices, + // Using extrusion width of an infill. this->flow(frInfill, this->layer()->height, true).scaled_width() ); @@ -118,10 +129,12 @@ LayerRegion::process_external_surfaces(const Layer* lower_layer) if (bd.detect_angle()) { angle = bd.angle; - + // Are supports enabled? if (this->layer()->object()->config.support_material) { Polygons coverage = bd.coverage(); + // Bridged polygons do not require supports. this->bridged.insert(this->bridged.end(), coverage.begin(), coverage.end()); + // Unsupported edges of the infill. this->unsupported_bridge_edges.append(bd.unsupported_edges()); } } @@ -228,6 +241,10 @@ LayerRegion::process_external_surfaces(const Layer* lower_layer) } this->fill_surfaces = new_surfaces; + +#ifdef SLIC3R_DEBUG_SLICE_PROCESSING + export_region_fill_surfaces_to_svg_debug("3_process_external_surfaces-final"); +#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */ } void @@ -265,6 +282,10 @@ LayerRegion::prepare_fill_surfaces() surface->surface_type = stInternalSolid; } } + +#ifdef SLIC3R_DEBUG_SLICE_PROCESSING + export_region_slices_to_svg_debug("2_prepare_fill_surfaces"); +#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */ } double @@ -274,4 +295,62 @@ LayerRegion::infill_area_threshold() const return ss*ss; } + +void LayerRegion::export_region_slices_to_svg(const char *path) +{ + BoundingBox bbox; + for (Surfaces::const_iterator surface = this->slices.surfaces.begin(); surface != this->slices.surfaces.end(); ++surface) + bbox.merge(get_extents(surface->expolygon)); + Point legend_size = export_surface_type_legend_to_svg_box_size(); + Point legend_pos(bbox.min.x, bbox.max.y); + bbox.merge(Point(std::max(bbox.min.x + legend_size.x, bbox.max.x), bbox.max.y + legend_size.y)); + + SVG svg(path, bbox); + const float transparency = 0.5f; + for (Surfaces::const_iterator surface = this->slices.surfaces.begin(); surface != this->slices.surfaces.end(); ++surface) + svg.draw(surface->expolygon, surface_type_to_color_name(surface->surface_type), transparency); + for (Surfaces::const_iterator surface = this->fill_surfaces.surfaces.begin(); surface != this->fill_surfaces.surfaces.end(); ++surface) + svg.draw(surface->expolygon.lines(), surface_type_to_color_name(surface->surface_type)); + export_surface_type_legend_to_svg(svg, legend_pos); + svg.Close(); } + +// Export to "out/LayerRegion-name-%d.svg" with an increasing index with every export. +void LayerRegion::export_region_slices_to_svg_debug(const char *name) +{ + static std::map idx_map; + size_t &idx = idx_map[name]; + char path[2048]; + sprintf(path, "out\\LayerRegion-slices-%s-%d.svg", name, idx ++); + this->export_region_slices_to_svg(path); +} + +void LayerRegion::export_region_fill_surfaces_to_svg(const char *path) +{ + BoundingBox bbox; + for (Surfaces::const_iterator surface = this->fill_surfaces.surfaces.begin(); surface != this->fill_surfaces.surfaces.end(); ++surface) + bbox.merge(get_extents(surface->expolygon)); + Point legend_size = export_surface_type_legend_to_svg_box_size(); + Point legend_pos(bbox.min.x, bbox.max.y); + bbox.merge(Point(std::max(bbox.min.x + legend_size.x, bbox.max.x), bbox.max.y + legend_size.y)); + + SVG svg(path, bbox); + const float transparency = 0.5f; + for (Surfaces::const_iterator surface = this->fill_surfaces.surfaces.begin(); surface != this->fill_surfaces.surfaces.end(); ++surface) + svg.draw(surface->expolygon, surface_type_to_color_name(surface->surface_type), transparency); + export_surface_type_legend_to_svg(svg, legend_pos); + svg.Close(); +} + +// Export to "out/LayerRegion-name-%d.svg" with an increasing index with every export. +void LayerRegion::export_region_fill_surfaces_to_svg_debug(const char *name) +{ + static std::map idx_map; + size_t &idx = idx_map[name]; + char path[2048]; + sprintf(path, "out\\LayerRegion-fill_surfaces-%s-%d.svg", name, idx ++); + this->export_region_fill_surfaces_to_svg(path); +} + +} + \ No newline at end of file diff --git a/xs/src/libslic3r/PerimeterGenerator.cpp b/xs/src/libslic3r/PerimeterGenerator.cpp index aa0b2600f..d0cec1167 100644 --- a/xs/src/libslic3r/PerimeterGenerator.cpp +++ b/xs/src/libslic3r/PerimeterGenerator.cpp @@ -239,6 +239,15 @@ PerimeterGenerator::process() this->loops->append(entities); } // for each loop of an island + { + //FIXME how about the gaps? + // Calculate the region of surface->expolygon covered by the perimeters and their gap fills. + // The perimeters will later be used to calculate the object skin. + ExPolygons expp = diff_ex((Polygons)surface->expolygon, last, true); + for (ExPolygons::const_iterator ex = expp.begin(); ex != expp.end(); ++ex) + this->perimeter_surfaces->surfaces.push_back(Surface(stPerimeter, *ex)); + } + // fill gaps if (!gaps.empty()) { /* @@ -275,7 +284,7 @@ PerimeterGenerator::process() last = diff(last, gap_fill.grow()); } } - + // create one more offset to be used as boundary for fill // we offset by half the perimeter spacing (to get to the actual infill boundary) // and then we offset back and forth by half the infill spacing to only consider the diff --git a/xs/src/libslic3r/PerimeterGenerator.hpp b/xs/src/libslic3r/PerimeterGenerator.hpp index 0e7fbd3e4..09289a2d4 100644 --- a/xs/src/libslic3r/PerimeterGenerator.hpp +++ b/xs/src/libslic3r/PerimeterGenerator.hpp @@ -52,6 +52,7 @@ public: // Outputs: ExtrusionEntityCollection* loops; ExtrusionEntityCollection* gap_fill; + SurfaceCollection* perimeter_surfaces; SurfaceCollection* fill_surfaces; PerimeterGenerator( @@ -67,13 +68,15 @@ public: ExtrusionEntityCollection* loops, // Gaps without the thin walls ExtrusionEntityCollection* gap_fill, + // Perimeters including their gap fills + SurfaceCollection* perimeter_surfaces, // Infills without the gap fills SurfaceCollection* fill_surfaces) : slices(slices), lower_slices(NULL), layer_height(layer_height), layer_id(-1), perimeter_flow(flow), ext_perimeter_flow(flow), overhang_flow(flow), solid_infill_flow(flow), config(config), object_config(object_config), print_config(print_config), - loops(loops), gap_fill(gap_fill), fill_surfaces(fill_surfaces), + loops(loops), gap_fill(gap_fill), perimeter_surfaces(perimeter_surfaces), fill_surfaces(fill_surfaces), _ext_mm3_per_mm(-1), _mm3_per_mm(-1), _mm3_per_mm_overhang(-1) {}; void process(); diff --git a/xs/xsp/Layer.xsp b/xs/xsp/Layer.xsp index e5697ce89..c4490cf71 100644 --- a/xs/xsp/Layer.xsp +++ b/xs/xsp/Layer.xsp @@ -17,6 +17,8 @@ %code%{ RETVAL = &THIS->thin_fills; %}; Ref fill_surfaces() %code%{ RETVAL = &THIS->fill_surfaces; %}; + Ref perimeter_surfaces() + %code%{ RETVAL = &THIS->perimeter_surfaces; %}; Polygons bridged() %code%{ RETVAL = THIS->bridged; %}; Ref unsupported_bridge_edges() @@ -30,9 +32,14 @@ %code%{ RETVAL = THIS->flow(role, bridge, width); %}; void merge_slices(); void prepare_fill_surfaces(); - void make_perimeters(SurfaceCollection* slices, SurfaceCollection* fill_surfaces) - %code%{ THIS->make_perimeters(*slices, fill_surfaces); %}; + void make_perimeters(SurfaceCollection* slices, SurfaceCollection* perimeter_surfaces, SurfaceCollection* fill_surfaces) + %code%{ THIS->make_perimeters(*slices, perimeter_surfaces, fill_surfaces); %}; double infill_area_threshold(); + + void export_region_slices_to_svg(const char *path); + void export_region_fill_surfaces_to_svg(const char *path); + void export_region_slices_to_svg_debug(const char *name); + void export_region_fill_surfaces_to_svg_debug(const char *name); }; %name{Slic3r::Layer} class Layer { @@ -72,6 +79,9 @@ Ref slices() %code%{ RETVAL = &THIS->slices; %}; + + Ref perimeter_expolygons() + %code%{ RETVAL = &THIS->perimeter_expolygons; %}; int ptr() %code%{ RETVAL = (int)(intptr_t)THIS; %}; @@ -86,6 +96,11 @@ bool any_bottom_region_slice_contains_polyline(Polyline* polyline) %code%{ RETVAL = THIS->any_bottom_region_slice_contains(*polyline); %}; void make_perimeters(); + + void export_region_slices_to_svg(const char *path); + void export_region_fill_surfaces_to_svg(const char *path); + void export_region_slices_to_svg_debug(const char *name); + void export_region_fill_surfaces_to_svg_debug(const char *name); }; %name{Slic3r::Layer::Support} class SupportLayer { @@ -136,8 +151,8 @@ Ref slices() %code%{ RETVAL = &THIS->slices; %}; - bool any_internal_region_slice_contains_polyline(Polyline* polyline) - %code%{ RETVAL = THIS->any_internal_region_slice_contains(*polyline); %}; - bool any_bottom_region_slice_contains_polyline(Polyline* polyline) - %code%{ RETVAL = THIS->any_bottom_region_slice_contains(*polyline); %}; + void export_region_slices_to_svg(const char *path); + void export_region_fill_surfaces_to_svg(const char *path); + void export_region_slices_to_svg_debug(const char *name); + void export_region_fill_surfaces_to_svg_debug(const char *name); }; diff --git a/xs/xsp/PerimeterGenerator.xsp b/xs/xsp/PerimeterGenerator.xsp index b4d1d94ec..b8c3edf69 100644 --- a/xs/xsp/PerimeterGenerator.xsp +++ b/xs/xsp/PerimeterGenerator.xsp @@ -9,12 +9,13 @@ PerimeterGenerator(SurfaceCollection* slices, double layer_height, Flow* flow, StaticPrintConfig* region_config, StaticPrintConfig* object_config, StaticPrintConfig* print_config, ExtrusionEntityCollection* loops, - ExtrusionEntityCollection* gap_fill, SurfaceCollection* fill_surfaces) + ExtrusionEntityCollection* gap_fill, + SurfaceCollection* perimeter_surfaces, SurfaceCollection* fill_surfaces) %code{% RETVAL = new PerimeterGenerator(slices, layer_height, *flow, dynamic_cast(region_config), dynamic_cast(object_config), dynamic_cast(print_config), - loops, gap_fill, fill_surfaces); %}; + loops, gap_fill, perimeter_surfaces, fill_surfaces); %}; ~PerimeterGenerator(); void set_lower_slices(ExPolygonCollection* lower_slices)