diff --git a/src/libslic3r/ExtrusionEntity.hpp b/src/libslic3r/ExtrusionEntity.hpp index 274f842cd..9fd09e0f3 100644 --- a/src/libslic3r/ExtrusionEntity.hpp +++ b/src/libslic3r/ExtrusionEntity.hpp @@ -30,6 +30,9 @@ enum ExtrusionRole { // Extrusion role for a collection with multiple extrusion roles. erMixed, }; +// perimeter / infill / support / skirt / gapfill / wipetower / custom / mixed +// side / internal / top / bottom +// bridge inline bool is_perimeter(ExtrusionRole role) { diff --git a/src/libslic3r/Fill/Fill.cpp b/src/libslic3r/Fill/Fill.cpp index 872e52920..d3548208f 100644 --- a/src/libslic3r/Fill/Fill.cpp +++ b/src/libslic3r/Fill/Fill.cpp @@ -66,7 +66,7 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out) for (uint32_t num_srf = 0; num_srf < groups[num_group].size(); ++num_srf) { Surface *srf = groups[num_group][num_srf]; //if solid, wrong group - if (srf->is_solid()) break; + if (srf->has_fill_solid()) break; //find surface that can be used as dense infill if (srf->maxNbSolidLayersOnTop <= 1 && srf->maxNbSolidLayersOnTop > 0) { @@ -100,11 +100,11 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out) // we can only merge solid non-bridge non-overextruded surfaces, so discard // non-solid surfaces const Surface &surface = *groups[i].front(); - if (surface.is_solid() && (!surface.is_bridge() || layerm.layer()->id() == 0) && !surface.is_overBridge()) { + if (surface.has_fill_solid() && (!surface.has_mod_bridge() || layerm.layer()->id() == 0) && !surface.has_mod_overBridge()) { group_attrib[i].is_solid = true; - group_attrib[i].flow_width = (surface.is_top()) ? top_solid_infill_flow.width : solid_infill_flow.width; - group_attrib[i].pattern = (surface.is_top() && surface.is_external()) ? layerm.region()->config().top_fill_pattern.value : layerm.region()->config().solid_fill_pattern.value; - group_attrib[i].pattern = (surface.is_bottom() && surface.is_external()) ? layerm.region()->config().bottom_fill_pattern.value : layerm.region()->config().solid_fill_pattern.value; + group_attrib[i].flow_width = (surface.has_pos_top()) ? top_solid_infill_flow.width : solid_infill_flow.width; + group_attrib[i].pattern = surface.has_pos_top() ? layerm.region()->config().top_fill_pattern.value : layerm.region()->config().solid_fill_pattern.value; + group_attrib[i].pattern = surface.has_pos_bottom() ? layerm.region()->config().bottom_fill_pattern.value : layerm.region()->config().solid_fill_pattern.value; } } // Loop through solid groups, find compatible groups and append them to this one. @@ -183,7 +183,7 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out) Polygons to_subtract; to_subtract.reserve(collapsed.size() + number_polygons(surfaces)); for (Surfaces::const_iterator it_surface = surfaces.begin(); it_surface != surfaces.end(); ++ it_surface) - if (it_surface->surface_type == stInternalVoid) + if (it_surface->surface_type == (stPosInternal |stDensVoid) ) polygons_append(to_subtract, *it_surface); polygons_append(to_subtract, collapsed); surfaces_append( @@ -192,7 +192,7 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out) offset(collapsed, distance_between_surfaces), to_subtract, true), - stInternalSolid); + stPosInternal | stDensSolid); }*/ if (0) { @@ -203,20 +203,20 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out) // ); } for (const Surface &surface : surfaces) { - if (surface.surface_type == stInternalVoid) + if (surface.surface_type == (stPosInternal | stDensVoid)) continue; InfillPattern fill_pattern = layerm.region()->config().fill_pattern.value; double density = fill_density; - FlowRole role = (surface.is_top()) ? frTopSolidInfill : - (surface.is_solid() ? frSolidInfill : frInfill); - bool is_bridge = layerm.layer()->id() > 0 && surface.is_bridge(); + FlowRole role = (surface.has_pos_top()) ? frTopSolidInfill : + (surface.has_fill_solid() ? frSolidInfill : frInfill); + bool is_bridge = layerm.layer()->id() > 0 && surface.has_mod_bridge(); bool is_denser = false; - if (surface.is_solid()) { + if (surface.has_fill_solid()) { density = 100.; fill_pattern = ipRectilinear; - if (surface.is_external() && !is_bridge) - fill_pattern = surface.is_top() ? layerm.region()->config().top_fill_pattern.value : layerm.region()->config().bottom_fill_pattern.value; + if (surface.has_pos_external() && !is_bridge) + fill_pattern = surface.has_pos_top() ? layerm.region()->config().top_fill_pattern.value : layerm.region()->config().bottom_fill_pattern.value; else if (!is_bridge) fill_pattern = layerm.region()->config().solid_fill_pattern.value; } else { @@ -249,7 +249,7 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out) // calculate flow spacing for infill pattern generation bool using_internal_flow = false; - if (! surface.is_solid() && ! is_bridge) { + if (! surface.has_fill_solid() && ! is_bridge) { // it's internal infill, so we can calculate a generic flow spacing // for all layers, for avoiding the ugly effect of // misaligned infill on first layer because of different extrusion width and @@ -314,7 +314,7 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out) } float flow_percent = 1; - if(surface.is_overBridge()){ + if (surface.has_mod_overBridge()){ params.density = layerm.region()->config().over_bridge_flow_ratio; //params.flow_mult = layerm.region()->config().over_bridge_flow_ratio; } diff --git a/src/libslic3r/Fill/FillBase.cpp b/src/libslic3r/Fill/FillBase.cpp index 3a3b83bf9..fbf857d6b 100644 --- a/src/libslic3r/Fill/FillBase.cpp +++ b/src/libslic3r/Fill/FillBase.cpp @@ -189,13 +189,7 @@ void Fill::fill_surface_extrusion(const Surface *surface, const FillParams ¶ /// add it into the collection out.push_back(eec); //get the role - ExtrusionRole good_role = params.role; - if (good_role == erNone || good_role == erCustom) { - good_role = (params.flow->bridge ? erBridgeInfill : - (surface->is_solid() ? - ((surface->is_top()) ? erTopSolidInfill : erSolidInfill) : - erInternalInfill)); - } + ExtrusionRole good_role = getRoleFromSurfaceType(params, surface); /// push the path extrusion_entities_append_paths( eec->entities, std::move(polylines), diff --git a/src/libslic3r/Fill/FillBase.hpp b/src/libslic3r/Fill/FillBase.hpp index dbb700b58..e6e963040 100644 --- a/src/libslic3r/Fill/FillBase.hpp +++ b/src/libslic3r/Fill/FillBase.hpp @@ -132,6 +132,17 @@ protected: void connect_infill(const Polylines &infill_ordered, const ExPolygon &boundary, Polylines &polylines_out); + ExtrusionRole getRoleFromSurfaceType(const FillParams ¶ms, const Surface *surface){ + if (params.role == erNone || params.role == erCustom) { + return params.flow->bridge ? + erBridgeInfill : + (surface->has_fill_solid() ? + ((surface->has_pos_top()) ? erTopSolidInfill : erSolidInfill) : + erInternalInfill); + } + return params.role; + } + public: static coord_t _adjust_solid_spacing(const coord_t width, const coord_t distance); diff --git a/src/libslic3r/Fill/FillConcentric.cpp b/src/libslic3r/Fill/FillConcentric.cpp index 87c24c954..ed1fd0f85 100644 --- a/src/libslic3r/Fill/FillConcentric.cpp +++ b/src/libslic3r/Fill/FillConcentric.cpp @@ -125,13 +125,7 @@ void FillConcentricWGapFill::fill_surface_extrusion(const Surface *surface, cons //get the role - ExtrusionRole good_role = params.role; - if (good_role == erNone || good_role == erCustom) { - good_role = (params.flow->bridge ? erBridgeInfill : - (surface->is_solid() ? - ((surface->is_top()) ? erTopSolidInfill : erSolidInfill) : - erInternalInfill)); - } + ExtrusionRole good_role = getRoleFromSurfaceType(params, surface); ExtrusionEntityCollection *coll_nosort = new ExtrusionEntityCollection(); coll_nosort->no_sort = true; //can be sorted inside the pass diff --git a/src/libslic3r/Fill/FillRectilinear2.cpp b/src/libslic3r/Fill/FillRectilinear2.cpp index face63d84..24ca15d15 100644 --- a/src/libslic3r/Fill/FillRectilinear2.cpp +++ b/src/libslic3r/Fill/FillRectilinear2.cpp @@ -1537,14 +1537,7 @@ FillRectilinear2Peri::fill_surface_extrusion(const Surface *surface, const FillP /// add it into the collection eecroot->entities.push_back(eec); //get the role - ExtrusionRole good_role = params.role; - if (good_role == erNone || good_role == erCustom) { - good_role = params.flow->bridge ? - erBridgeInfill : - (surface->is_solid() ? - ((surface->is_top()) ? erTopSolidInfill : erSolidInfill) : - erInternalInfill); - } + ExtrusionRole good_role = getRoleFromSurfaceType(params, surface); /// push the path extrusion_entities_append_paths( eec->entities, @@ -1576,14 +1569,7 @@ FillRectilinear2Peri::fill_surface_extrusion(const Surface *surface, const FillP /// add it into the collection eecroot->entities.push_back(eec); //get the role - ExtrusionRole good_role = params.role; - if (good_role == erNone || good_role == erCustom) { - good_role = params.flow->bridge ? - erBridgeInfill : - (surface->is_solid() ? - ((surface->is_top()) ? erTopSolidInfill : erSolidInfill) : - erInternalInfill); - } + ExtrusionRole good_role = getRoleFromSurfaceType(params, surface); /// push the path extrusion_entities_append_paths( eec->entities, @@ -1683,14 +1669,8 @@ FillRectilinearSawtooth::fill_surface_extrusion(const Surface *surface, const Fi /// pass the no_sort attribute to the extrusion path eec->no_sort = this->no_sort(); - ExtrusionRole good_role = params.role; - if (good_role == erNone || good_role == erCustom) { - good_role = params.flow->bridge ? - erBridgeInfill : - (surface->is_solid() ? - ((surface->is_top()) ? erTopSolidInfill : erSolidInfill) : - erInternalInfill); - } + ExtrusionRole good_role = getRoleFromSurfaceType(params, surface); + for (Polyline poly : polylines_out) { if (!poly.is_valid()) continue; diff --git a/src/libslic3r/Layer.cpp b/src/libslic3r/Layer.cpp index 91170ecdd..163197e2e 100644 --- a/src/libslic3r/Layer.cpp +++ b/src/libslic3r/Layer.cpp @@ -70,11 +70,11 @@ void Layer::merge_slices() if (m_regions.size() == 1) { // Optimization, also more robust. Don't merge classified pieces of layerm->slices, // but use the non-split islands of a layer. For a single region print, these shall be equal. - m_regions.front()->slices.set(this->slices.expolygons, stInternal); + m_regions.front()->slices.set(this->slices.expolygons, stPosInternal | stDensSparse); } else { for (LayerRegion *layerm : m_regions) // without safety offset, artifacts are generated (GH #2494) - layerm->slices.set(union_ex(to_polygons(std::move(layerm->slices.surfaces)), true), stInternal); + layerm->slices.set(union_ex(to_polygons(std::move(layerm->slices.surfaces)), true), stPosInternal | stDensSparse); } } diff --git a/src/libslic3r/LayerRegion.cpp b/src/libslic3r/LayerRegion.cpp index 71d84e17a..c2957cb67 100644 --- a/src/libslic3r/LayerRegion.cpp +++ b/src/libslic3r/LayerRegion.cpp @@ -37,16 +37,15 @@ void LayerRegion::slices_to_fill_surfaces_clipped() // Polygons fill_boundaries = to_polygons(std::move(this->fill_surfaces)); Polygons fill_boundaries = to_polygons(this->fill_expolygons); // Collect polygons per surface type. - std::vector polygons_by_surface; - polygons_by_surface.assign(size_t(stCount), Polygons()); - for (Surface &surface : this->slices.surfaces) - polygons_append(polygons_by_surface[(size_t)surface.surface_type], surface.expolygon); + std::map polygons_by_surface; + for (Surface &surface : this->slices.surfaces) { + polygons_append(polygons_by_surface[surface.surface_type], surface.expolygon); + } // Trim surfaces by the fill_boundaries. this->fill_surfaces.surfaces.clear(); - for (size_t surface_type = 0; surface_type < size_t(stCount); ++ surface_type) { - const Polygons &polygons = polygons_by_surface[surface_type]; - if (! polygons.empty()) - this->fill_surfaces.append(intersection_ex(polygons, fill_boundaries), SurfaceType(surface_type)); + for (auto const& entry : polygons_by_surface) { + if (!entry.second.empty()) + this->fill_surfaces.append(intersection_ex(entry.second, fill_boundaries), entry.first); } } @@ -131,24 +130,24 @@ void LayerRegion::process_external_surfaces(const Layer* lower_layer) fill_boundaries.reserve(number_polygons(surfaces)); bool has_infill = this->region()->config().fill_density.value > 0.; for (const Surface &surface : this->fill_surfaces.surfaces) { - if (surface.is_top()) { + if (surface.has_pos_top()) { // Collect the top surfaces, inflate them and trim them by the bottom surfaces. // This gives the priority to bottom surfaces. surfaces_append(top, offset_ex(surface.expolygon, float(margin), EXTERNAL_SURFACES_OFFSET_PARAMETERS), surface); - } else if (surface.surface_type == stBottom || (surface.surface_type == stBottomBridge && lower_layer == NULL)) { + } else if (surface.has_pos_bottom() && (!surface.has_mod_bridge() || lower_layer == NULL)) { // Grown by 3mm. surfaces_append(bottom, offset_ex(surface.expolygon, float(margin), EXTERNAL_SURFACES_OFFSET_PARAMETERS), surface); - } else if (surface.surface_type == stBottomBridge) { + } else if (surface.has_pos_bottom() && surface.has_mod_bridge()) { if (! surface.empty()) bridges.push_back(surface); } - if (has_infill || surface.surface_type != stInternal) { - if (!surface.is_external()) + if (has_infill || !(surface.has_pos_internal() && surface.has_fill_sparse())) { + if (!surface.has_pos_external()) // Make a copy as the following line uses the move semantics. internal.push_back(surface); polygons_append(fill_boundaries, std::move(surface.expolygon)); } else{ - if (!surface.is_external()) + if (!surface.has_pos_external()) internal.push_back(std::move(surface)); //push surface as perimeter-only inside the fill_boundaries if (margin_bridged > 0) { @@ -324,7 +323,7 @@ void LayerRegion::process_external_surfaces(const Layer* lower_layer) s2.clear(); } } - if (s1.is_top()) + if (s1.has_pos_top()) // Trim the top surfaces by the bottom surfaces. This gives the priority to the bottom surfaces. polys = diff(polys, bottom_polygons); surfaces_append( @@ -376,14 +375,14 @@ void LayerRegion::prepare_fill_surfaces() // if no solid layers are requested, turn top/bottom surfaces to internal if (this->region()->config().top_solid_layers == 0) { for (Surfaces::iterator surface = this->fill_surfaces.surfaces.begin(); surface != this->fill_surfaces.surfaces.end(); ++surface) - if (surface->is_top()) + if (surface->has_pos_top()) surface->surface_type = (this->layer()->object()->config().infill_only_where_needed) ? - stInternalVoid : stInternal; + stPosInternal | stDensVoid : stPosInternal | stDensSparse; } if (this->region()->config().bottom_solid_layers == 0) { for (Surfaces::iterator surface = this->fill_surfaces.surfaces.begin(); surface != this->fill_surfaces.surfaces.end(); ++surface) { - if (surface->is_bottom()) - surface->surface_type = stInternal; + if (surface->has_pos_bottom()) + surface->surface_type = stPosInternal | stDensSparse; } } @@ -392,8 +391,8 @@ void LayerRegion::prepare_fill_surfaces() // scaling an area requires two calls! double min_area = scale_(scale_(this->region()->config().solid_infill_below_area.value)); for (Surfaces::iterator surface = this->fill_surfaces.surfaces.begin(); surface != this->fill_surfaces.surfaces.end(); ++surface) { - if (surface->surface_type == stInternal && surface->area() <= min_area) - surface->surface_type = stInternalSolid; + if (surface->has_fill_sparse() && surface->has_pos_internal() && surface->area() <= min_area) + surface->surface_type = stPosInternal | stDensSolid; } } diff --git a/src/libslic3r/PerimeterGenerator.cpp b/src/libslic3r/PerimeterGenerator.cpp index 5bf74060a..b35cba2ea 100644 --- a/src/libslic3r/PerimeterGenerator.cpp +++ b/src/libslic3r/PerimeterGenerator.cpp @@ -195,7 +195,7 @@ void PerimeterGenerator::process() // this will avoid to throw wrong offsets into a good polygons this->fill_surfaces->append( unsupported_filtered, - stInternal); + stPosInternal | stDensSparse); // store the results last = diff_ex(last, unsupported_filtered, true); @@ -204,7 +204,7 @@ void PerimeterGenerator::process() if (intersection_ex(support, ExPolygons() = { last[i] }).empty()) { this->fill_surfaces->append( ExPolygons() = { last[i] }, - stInternal); + stPosInternal | stDensSparse); last.erase(last.begin() + i); i--; } @@ -529,7 +529,7 @@ void PerimeterGenerator::process() ExPolygons infill_exp = offset2_ex(not_filled_exp, -inset - min_perimeter_infill_spacing / 2 + overlap, (float)min_perimeter_infill_spacing / 2); - this->fill_surfaces->append(infill_exp, stInternal); + this->fill_surfaces->append(infill_exp, stPosInternal | stDensSparse); if (overlap != 0) { ExPolygons polyWithoutOverlap = offset2_ex( diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index b7a0efcd9..50f9f0be4 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -183,7 +183,7 @@ private: void bridge_over_infill(); void replaceSurfaceType(SurfaceType st_to_replace, SurfaceType st_replacement, SurfaceType st_under_it); void clip_fill_surfaces(); - void count_distance_solid(); + void tag_under_bridge(); void discover_horizontal_shells(); void combine_infill(); void _generate_support_material(); diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 53780adc8..28dae1b28 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -332,13 +332,21 @@ void PrintObject::prepare_infill() //if (this->) this->bridge_over_infill(); m_print->throw_if_canceled(); - this->replaceSurfaceType(stInternalSolid, stInternalOverBridge, stInternalBridge); + this->replaceSurfaceType(stPosInternal | stDensSolid, + stPosInternal | stDensSolid | stModOverBridge, + stPosInternal | stDensSolid | stModBridge); m_print->throw_if_canceled(); - this->replaceSurfaceType(stInternalSolid, stInternalOverBridge, stBottomBridge); + this->replaceSurfaceType(stPosTop | stDensSolid, + stPosTop | stDensSolid | stModOverBridge, + stPosInternal | stDensSolid | stModBridge); m_print->throw_if_canceled(); - this->replaceSurfaceType(stTop, stTopOverBridge, stInternalBridge); + this->replaceSurfaceType(stPosInternal | stDensSolid, + stPosInternal | stDensSolid | stModOverBridge, + stPosBottom | stDensSolid | stModBridge); m_print->throw_if_canceled(); - this->replaceSurfaceType(stTop, stTopOverBridge, stBottomBridge); + this->replaceSurfaceType(stPosTop | stDensSolid, + stPosTop | stDensSolid | stModOverBridge, + stPosBottom | stDensSolid | stModBridge); m_print->throw_if_canceled(); // combine fill surfaces to honor the "infill every N layers" option @@ -347,7 +355,7 @@ void PrintObject::prepare_infill() // count the distance from the nearest top surface, to allow to use denser infill // if needed and if infill_dense_layers is positive. - this->count_distance_solid(); + this->tag_under_bridge(); m_print->throw_if_canceled(); #ifdef SLIC3R_DEBUG_SLICE_PROCESSING @@ -710,17 +718,13 @@ ExPolygons fit_to_size(ExPolygon polygon_to_cover, ExPolygon polygon_to_check, c return intersection_ex(polygon_reduced, growing_area); } -//FIXME: cerify it works if the part is split in 2 in the Z axis -void PrintObject::count_distance_solid() { - //if dense area * COEFF_SPLIT > sparse area then fill all with dense - // sparse area = layer's fill area - solid area - const float COEFF_SPLIT = 2; - const int NB_DENSE_LAYERS = 1; - int idR = 0; +void PrintObject::tag_under_bridge() { + const float COEFF_SPLIT = 1.5; + for (const PrintRegion *region : this->m_print->regions()) { LayerRegion *previousOne = NULL; //count how many surface there are on each one - if (region->config().infill_dense.getBool() && region->config().fill_density<40) { + if (region->config().infill_dense.getBool() && region->config().fill_density < 40) { for (size_t idx_layer = this->layers().size() - 1; idx_layer < this->layers().size(); --idx_layer) { LayerRegion *layerm = NULL; for (LayerRegion * lregion : this->layers()[idx_layer]->regions()) { @@ -734,131 +738,88 @@ void PrintObject::count_distance_solid() { continue; } if (previousOne == NULL) { - for (Surface &surf : layerm->fill_surfaces.surfaces) { - if (surf.is_solid()) { - surf.maxNbSolidLayersOnTop = 0; - } - } previousOne = layerm; continue; } Surfaces surf_to_add; for (Surface &surf : layerm->fill_surfaces.surfaces) { - if (!surf.is_solid()){ - surf.maxNbSolidLayersOnTop = 30000; - uint16_t dense_dist = 30000; + surf.maxNbSolidLayersOnTop = -1; + if (!surf.has_fill_solid()){ ExPolygons dense_polys; ExPolygons sparse_polys = { surf.expolygon }; - //find the surface which intersect with the smalle maxNb possible + //find the surface which intersect with the smallest maxNb possible for (Surface &upp : previousOne->fill_surfaces.surfaces) { - // i'm using intersection_ex because the result different than - // upp.expolygon.overlaps(surf.expolygon) or surf.expolygon.overlaps(upp.expolygon) - ExPolygons intersect = intersection_ex(sparse_polys, offset_ex(upp.expolygon, -layerm->flow(frInfill).scaled_width()), true); - if (!intersect.empty()) { - if (layerm->region()->config().infill_dense_algo == dfaEnlarged) { - uint16_t dist = (uint16_t)(upp.maxNbSolidLayersOnTop + 1); - const int nb_dense_layers = 1; - if (dist <= nb_dense_layers) { - // it will be a dense infill, split the surface if needed - uint64_t area_intersect = 0; - for (ExPolygon poly_inter : intersect) area_intersect += poly_inter.area(); - //if it's in a dense area and the current surface isn't a dense one yet and the not-dense is too small. - if ((surf.area() > area_intersect * COEFF_SPLIT) && - surf.maxNbSolidLayersOnTop > nb_dense_layers) { - //split in two - if (dist == 1) { - //if just under the solid area, we can expand a bit - //remove too small sections and grew a bit to anchor it into the part - intersect = offset_ex(intersect, layerm->flow(frInfill).scaled_width() + scale_(layerm->region()->config().bridged_infill_margin)); - } else { - //just remove too small sections - intersect = offset_ex(intersect, - layerm->flow(frInfill).scaled_width()); - } - if (!intersect.empty()) { - ExPolygons sparse_surfaces = offset2_ex( - diff_ex(sparse_polys, intersect, true), - -layerm->flow(frInfill).scaled_width(), - layerm->flow(frInfill).scaled_width()); - ExPolygons dense_surfaces = diff_ex(sparse_polys, sparse_surfaces, true); - //assign (copy) - sparse_polys.clear(); - sparse_polys.insert(sparse_polys.begin(), sparse_surfaces.begin(), sparse_surfaces.end()); - dense_polys.insert(dense_polys.end(), dense_surfaces.begin(), dense_surfaces.end()); - dense_dist = std::min(dense_dist, dist); - } - } else { - surf.maxNbSolidLayersOnTop = std::min(surf.maxNbSolidLayersOnTop, dist); - } - } else { - surf.maxNbSolidLayersOnTop = std::min(surf.maxNbSolidLayersOnTop, dist); - } - } else if (layerm->region()->config().infill_dense_algo == dfaAutoNotFull || layerm->region()->config().infill_dense_algo == dfaAutomatic) { - double area_intersect = 0; - for (ExPolygon poly_inter : intersect) area_intersect += poly_inter.area(); - //like intersect.empty() but more resilient - if (area_intersect > layerm->flow(frInfill).scaled_width() * layerm->flow(frInfill).scaled_width() * 2) { - uint16_t dist = (uint16_t)(upp.maxNbSolidLayersOnTop + 1); - if (dist <= NB_DENSE_LAYERS) { + if (upp.has_fill_solid()){ + // i'm using intersection_ex because the result different than + // upp.expolygon.overlaps(surf.expolygon) or surf.expolygon.overlaps(upp.expolygon) + //and a little offset2 to remove the almost supported area + ExPolygons intersect = + offset2_ex( + intersection_ex(sparse_polys, { upp.expolygon }, true) + , -layerm->flow(frInfill).scaled_width(), layerm->flow(frInfill).scaled_width()); + if (!intersect.empty()) { + + if (layerm->region()->config().infill_dense_algo == dfaEnlarged) { + //expand the area a bit + intersect = offset_ex(intersect, scale_(layerm->region()->config().bridged_infill_margin)); + } else if (layerm->region()->config().infill_dense_algo == dfaAutoNotFull + || layerm->region()->config().infill_dense_algo == dfaAutomatic){ + + //check if area isn't too big for autonotfull + double area_intersect = 0; + if (layerm->region()->config().infill_dense_algo == dfaAutoNotFull) + for (ExPolygon poly_inter : intersect) + area_intersect += poly_inter.area(); + //like intersect.empty() but more resilient + if (layerm->region()->config().infill_dense_algo == dfaAutomatic + || surf.area() > area_intersect * COEFF_SPLIT) { + // it will be a dense infill, split the surface if needed - //if the not-dense is too big to do a full dense and the current surface isn't a dense one yet. - if ((layerm->region()->config().infill_dense_algo == dfaAutomatic || surf.area() > area_intersect * COEFF_SPLIT) && - surf.maxNbSolidLayersOnTop > NB_DENSE_LAYERS) { - //split in two - if (dist == 1) { - //if just under the solid area, we can expand a bit - ExPolygons cover_intersect; - for (ExPolygon &expoly_tocover : intersect) { - ExPolygons temp = (fit_to_size(expoly_tocover, expoly_tocover, - diff_ex(offset_ex(layerm->fill_no_overlap_expolygons, layerm->flow(frInfill).scaled_width()), - offset_ex(layerm->fill_no_overlap_expolygons, -layerm->flow(frInfill).scaled_width())), - surf.expolygon, - 4 * layerm->flow(frInfill).scaled_width(), 0.01)); - cover_intersect.insert(cover_intersect.end(), temp.begin(), temp.end()); - } - intersect = offset_ex(cover_intersect, - layerm->flow(frInfill).scaled_width());// +scale_(expandby)); - //layerm->region()->config().external_infill_margin)); - } else { - //just remove too small sections - intersect = offset_ex(intersect, - layerm->flow(frInfill).scaled_width()); - } - if (!intersect.empty()) { - ExPolygons sparse_surfaces = offset2_ex( - diff_ex(sparse_polys, intersect, true), - -layerm->flow(frInfill).scaled_width(), - layerm->flow(frInfill).scaled_width()); - ExPolygons dense_surfaces = diff_ex(sparse_polys, sparse_surfaces, true); - //assign (copy) - sparse_polys.clear(); - sparse_polys.insert(sparse_polys.begin(), sparse_surfaces.begin(), sparse_surfaces.end()); - dense_polys.insert(dense_polys.end(), dense_surfaces.begin(), dense_surfaces.end()); - dense_dist = std::min(dense_dist, dist); - } - } else { - if (area_intersect < layerm->flow(frInfill).scaled_width() * layerm->flow(frInfill).scaled_width() * 2) - surf.maxNbSolidLayersOnTop = std::min(surf.maxNbSolidLayersOnTop, dist); + ExPolygons cover_intersect; + for (ExPolygon &expoly_tocover : intersect) { + ExPolygons temp = (fit_to_size(expoly_tocover, expoly_tocover, + diff_ex(offset_ex(layerm->fill_no_overlap_expolygons, layerm->flow(frInfill).scaled_width()), + offset_ex(layerm->fill_no_overlap_expolygons, -layerm->flow(frInfill).scaled_width())), + surf.expolygon, + 4 * layerm->flow(frInfill).scaled_width(), 0.01)); + cover_intersect.insert(cover_intersect.end(), temp.begin(), temp.end()); } + intersect = offset2_ex(cover_intersect, + -layerm->flow(frInfill).scaled_width(), + layerm->flow(frInfill).scaled_width() * 2); } else { - surf.maxNbSolidLayersOnTop = std::min(surf.maxNbSolidLayersOnTop, dist); + intersect.clear(); } } + if (!intersect.empty()) { + ExPolygons sparse_surfaces = offset2_ex( + diff_ex(sparse_polys, intersect, true), + -layerm->flow(frInfill).scaled_width(), + layerm->flow(frInfill).scaled_width()); + ExPolygons dense_surfaces = diff_ex(sparse_polys, sparse_surfaces, true); + //assign (copy) + sparse_polys = std::move(sparse_surfaces); + dense_polys.insert(dense_polys.end(), dense_surfaces.begin(), dense_surfaces.end()); + } } } + //check if we are full-dense + if (sparse_polys.empty()) break; } + //check if we need to split the surface - if (dense_dist != 30000) { + if (!dense_polys.empty()) { double area_dense = 0; for (ExPolygon poly_inter : dense_polys) area_dense += poly_inter.area(); double area_sparse = 0; for (ExPolygon poly_inter : sparse_polys) area_sparse += poly_inter.area(); + std::cout << "need to split? " << area_sparse << " > " << area_dense << " * " << COEFF_SPLIT << "\n"; if (area_sparse > area_dense * COEFF_SPLIT) { //split dense_polys = union_ex(dense_polys); for (ExPolygon dense_poly : dense_polys) { Surface dense_surf(surf, dense_poly); - dense_surf.maxNbSolidLayersOnTop = dense_dist; + dense_surf.maxNbSolidLayersOnTop = 1; surf_to_add.push_back(dense_surf); } sparse_polys = union_ex(sparse_polys); @@ -868,29 +829,19 @@ void PrintObject::count_distance_solid() { } //layerm->fill_surfaces.surfaces.erase(it_surf); } else { - surf.maxNbSolidLayersOnTop = dense_dist; + surf.maxNbSolidLayersOnTop = 1; surf_to_add.push_back(surf); } - } else { - surf_to_add.push_back(surf); - } - } else { - surf.maxNbSolidLayersOnTop = 0; - surf_to_add.push_back(surf); - } + } else surf_to_add.emplace_back(std::move(surf)); + } else surf_to_add.emplace_back(std::move(surf)); } - //if (!surf_to_add.empty()) { - // layerm->fill_surfaces.surfaces.insert(layerm->fill_surfaces.surfaces.begin(), surf_to_add.begin(), surf_to_add.end()); - //} - layerm->fill_surfaces.surfaces.clear(); - layerm->fill_surfaces.surfaces.insert(layerm->fill_surfaces.surfaces.begin(), surf_to_add.begin(), surf_to_add.end()); + layerm->fill_surfaces.surfaces = std::move(surf_to_add); previousOne = layerm; } } } } - // This function analyzes slices of a region (SurfaceCollection slices). // Each region slice (instance of Surface) is analyzed, whether it is supported or whether it is the top surface. // Initially all slices are of type stInternal. @@ -930,12 +881,12 @@ void PrintObject::detect_surfaces_type() // If we have raft layers, consider bottom layer as a bridge just like any other bottom surface lying on the void. SurfaceType surface_type_bottom_1st = (m_config.raft_layers.value > 0 && m_config.support_material_contact_distance_type.value != zdNone) ? - stBottomBridge : stBottom; + stPosBottom | stDensSolid | stModBridge : stPosBottom | stDensSolid; // If we have soluble support material, don't bridge. The overhang will be squished against a soluble layer separating // the support from the print. SurfaceType surface_type_bottom_other = (m_config.support_material.value && m_config.support_material_contact_distance_type.value == zdNone) ? - stBottom : stBottomBridge; + stPosBottom | stDensSolid : stPosBottom | stDensSolid | stModBridge; for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++ idx_layer) { m_print->throw_if_canceled(); // BOOST_LOG_TRIVIAL(trace) << "Detecting solid surfaces for region " << idx_region << " and layer " << layer->print_z; @@ -961,13 +912,13 @@ void PrintObject::detect_surfaces_type() surfaces_append(top, //FIXME implement offset2_ex working over ExPolygons, that should be a bit more efficient than calling offset_ex twice. offset_ex(offset_ex(diff_ex(layerm_slices_surfaces, upper_slices, true), -offset), offset), - stTop); + stPosTop | stDensSolid); } else { // if no upper layer, all surfaces of this one are solid // we clone surfaces because we're going to clear the slices collection top = layerm->slices.surfaces; for (Surface &surface : top) - surface.surface_type = stTop; + surface.surface_type = stPosTop | stDensSolid; } // Find bottom surfaces (difference between current surfaces of current layer and lower one). @@ -1002,7 +953,7 @@ void PrintObject::detect_surfaces_type() to_polygons(lower_layer->get_region(idx_region)->slices.surfaces), true), -offset, offset), - stBottom); + stPosBottom | stDensSolid); } #endif } else { @@ -1024,7 +975,7 @@ void PrintObject::detect_surfaces_type() top.clear(); surfaces_append(top, diff_ex(top_polygons, to_polygons(bottom), false), - stTop); + stPosTop | stDensSolid); } #ifdef SLIC3R_DEBUG_SLICE_PROCESSING @@ -1049,7 +1000,7 @@ void PrintObject::detect_surfaces_type() polygons_append(topbottom, to_polygons(bottom)); surfaces_append(surfaces_out, diff_ex(layerm_slices_surfaces, topbottom, false), - stInternal); + stPosInternal | stDensSparse); } surfaces_append(surfaces_out, std::move(top)); @@ -1153,7 +1104,6 @@ void PrintObject::discover_vertical_shells() tbb::parallel_for( tbb::blocked_range(0, m_layers.size(), grain_size), [this, &cache_top_botom_regions](const tbb::blocked_range& range) { - const SurfaceType surfaces_bottom[2] = { stBottom, stBottomBridge }; const size_t num_regions = this->region_volumes.size(); for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++ idx_layer) { m_print->throw_if_canceled(); @@ -1170,9 +1120,10 @@ void PrintObject::discover_vertical_shells() LayerRegion &layerm = *layer.m_regions[idx_region]; float min_perimeter_infill_spacing = float(layerm.flow(frSolidInfill).scaled_spacing()) * 1.05f; // Top surfaces. - append(cache.top_surfaces, offset(to_expolygons(layerm.slices.filter_by_type(stTop)), min_perimeter_infill_spacing)); - append(cache.top_surfaces, offset(to_expolygons(layerm.fill_surfaces.filter_by_type(stTop)), min_perimeter_infill_spacing)); + append(cache.top_surfaces, offset(to_expolygons(layerm.slices.filter_by_type(stPosTop | stDensSolid)), min_perimeter_infill_spacing)); + append(cache.top_surfaces, offset(to_expolygons(layerm.fill_surfaces.filter_by_type(stPosTop | stDensSolid)), min_perimeter_infill_spacing)); // Bottom surfaces. + const SurfaceType surfaces_bottom[2] = { stPosBottom | stDensSolid, stPosBottom | stDensSolid | stModBridge }; append(cache.bottom_surfaces, offset(to_expolygons(layerm.slices.filter_by_types(surfaces_bottom, 2)), min_perimeter_infill_spacing)); append(cache.bottom_surfaces, offset(to_expolygons(layerm.fill_surfaces.filter_by_types(surfaces_bottom, 2)), min_perimeter_infill_spacing)); // Calculate the maximum perimeter offset as if the slice was extruded with a single extruder only. @@ -1238,7 +1189,6 @@ void PrintObject::discover_vertical_shells() tbb::parallel_for( tbb::blocked_range(0, m_layers.size(), grain_size), [this, idx_region, &cache_top_botom_regions](const tbb::blocked_range& range) { - const SurfaceType surfaces_bottom[2] = { stBottom, stBottomBridge }; for (size_t idx_layer = range.begin(); idx_layer < range.end(); ++ idx_layer) { m_print->throw_if_canceled(); Layer &layer = *m_layers[idx_layer]; @@ -1246,9 +1196,10 @@ void PrintObject::discover_vertical_shells() float min_perimeter_infill_spacing = float(layerm.flow(frSolidInfill).scaled_spacing()) * 1.05f; // Top surfaces. auto &cache = cache_top_botom_regions[idx_layer]; - cache.top_surfaces = offset(to_expolygons(layerm.slices.filter_by_type(stTop)), min_perimeter_infill_spacing); - append(cache.top_surfaces, offset(to_expolygons(layerm.fill_surfaces.filter_by_type(stTop)), min_perimeter_infill_spacing)); + cache.top_surfaces = offset(to_expolygons(layerm.slices.filter_by_type(stPosTop | stDensSolid)), min_perimeter_infill_spacing); + append(cache.top_surfaces, offset(to_expolygons(layerm.fill_surfaces.filter_by_type(stPosTop | stDensSolid)), min_perimeter_infill_spacing)); // Bottom surfaces. + const SurfaceType surfaces_bottom[2] = { stPosBottom | stDensSolid, stPosBottom | stDensSolid | stModBridge }; cache.bottom_surfaces = offset(to_expolygons(layerm.slices.filter_by_types(surfaces_bottom, 2)), min_perimeter_infill_spacing); append(cache.bottom_surfaces, offset(to_expolygons(layerm.fill_surfaces.filter_by_types(surfaces_bottom, 2)), min_perimeter_infill_spacing)); // Holes over all regions. Only collect them once, they are valid for all idx_region iterations. @@ -1402,7 +1353,7 @@ void PrintObject::discover_vertical_shells() #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */ // Trim the shells region by the internal & internal void surfaces. - const SurfaceType surfaceTypesInternal[] = { stInternal, stInternalVoid, stInternalSolid }; + const SurfaceType surfaceTypesInternal[] = { stPosInternal | stDensSparse, stPosInternal | stDensVoid, stPosInternal | stDensSolid }; const Polygons polygonsInternal = to_polygons(layerm->fill_surfaces.filter_by_types(surfaceTypesInternal, 3)); shell = intersection(shell, polygonsInternal, true); polygons_append(shell, diff(polygonsInternal, holes)); @@ -1410,7 +1361,7 @@ void PrintObject::discover_vertical_shells() continue; // Append the internal solids, so they will be merged with the new ones. - polygons_append(shell, to_polygons(layerm->fill_surfaces.filter_by_type(stInternalSolid))); + polygons_append(shell, to_polygons(layerm->fill_surfaces.filter_by_type(stPosInternal | stDensSolid))); // These regions will be filled by a rectilinear full infill. Currently this type of infill // only fills regions, which fit at least a single line. To avoid gaps in the sparse infill, @@ -1458,12 +1409,12 @@ void PrintObject::discover_vertical_shells() // Trim the internal & internalvoid by the shell. Slic3r::ExPolygons new_internal = diff_ex( - to_polygons(layerm->fill_surfaces.filter_by_type(stInternal)), + to_polygons(layerm->fill_surfaces.filter_by_type(stPosInternal | stDensSparse)), shell, false ); Slic3r::ExPolygons new_internal_void = diff_ex( - to_polygons(layerm->fill_surfaces.filter_by_type(stInternalVoid)), + to_polygons(layerm->fill_surfaces.filter_by_type(stPosInternal | stDensVoid)), shell, false ); @@ -1477,11 +1428,12 @@ void PrintObject::discover_vertical_shells() #endif /* SLIC3R_DEBUG_SLICE_PROCESSING */ // Assign resulting internal surfaces to layer. - const SurfaceType surfaceTypesKeep[] = { stTop, stBottom, stBottomBridge }; + const SurfaceType surfaceTypesKeep[] = { stPosTop | stDensSolid, stPosBottom | stDensSolid, stPosBottom | stDensSolid | stModBridge }; layerm->fill_surfaces.keep_types(surfaceTypesKeep, sizeof(surfaceTypesKeep)/sizeof(SurfaceType)); - layerm->fill_surfaces.append(new_internal, stInternal); - layerm->fill_surfaces.append(new_internal_void, stInternalVoid); - layerm->fill_surfaces.append(new_internal_solid, stInternalSolid); + //layerm->fill_surfaces.keep_types_flag(stPosTop | stPosBottom); + layerm->fill_surfaces.append(new_internal, stPosInternal | stDensSparse); + layerm->fill_surfaces.append(new_internal_void, stPosInternal | stDensVoid); + layerm->fill_surfaces.append(new_internal_solid, stPosInternal | stDensSolid); } // for each layer }); m_print->throw_if_canceled(); @@ -1535,7 +1487,7 @@ void PrintObject::bridge_over_infill() // extract the stInternalSolid surfaces that might be transformed into bridges Polygons internal_solid; - layerm->fill_surfaces.filter_by_type(stInternalSolid, &internal_solid); + layerm->fill_surfaces.filter_by_type(stPosInternal | stDensSolid, &internal_solid); // check whether the lower area is deep enough for absorbing the extra flow // (for obvious physical reasons but also for preventing the bridge extrudates @@ -1555,7 +1507,7 @@ void PrintObject::bridge_over_infill() // iterate through regions and collect internal surfaces Polygons lower_internal; for (LayerRegion *lower_layerm : lower_layer->m_regions) - lower_layerm->fill_surfaces.filter_by_type(stInternal, &lower_internal); + lower_layerm->fill_surfaces.filter_by_type(stPosInternal | stDensSparse, &lower_internal); // intersect such lower internal surfaces with the candidate solid surfaces to_bridge_pp = intersection(to_bridge_pp, lower_internal); @@ -1584,11 +1536,11 @@ void PrintObject::bridge_over_infill() ExPolygons not_to_bridge = diff_ex(internal_solid, to_polygons(to_bridge), true); to_bridge = intersection_ex(to_polygons(to_bridge), internal_solid, true); // build the new collection of fill_surfaces - layerm->fill_surfaces.remove_type(stInternalSolid); + layerm->fill_surfaces.remove_type(stPosInternal | stDensSolid); for (ExPolygon &ex : to_bridge) - layerm->fill_surfaces.surfaces.push_back(Surface(stInternalBridge, ex)); + layerm->fill_surfaces.surfaces.push_back(Surface(stPosInternal | stDensSolid | stModBridge, ex)); for (ExPolygon &ex : not_to_bridge) - layerm->fill_surfaces.surfaces.push_back(Surface(stInternalSolid, ex)); + layerm->fill_surfaces.surfaces.push_back(Surface(stPosInternal | stDensSolid, ex)); /* # exclude infill from the layers below if needed # see discussion at https://github.com/alexrj/Slic3r/issues/240 @@ -1636,7 +1588,8 @@ void PrintObject::bridge_over_infill() bridge (which is over sparse infill) note: it's almost complete copy/paste from the method behind, i think it should be merged before gitpull that. */ -void PrintObject::replaceSurfaceType(SurfaceType st_to_replace, SurfaceType st_replacement, SurfaceType st_under_it) +void +PrintObject::replaceSurfaceType(SurfaceType st_to_replace, SurfaceType st_replacement, SurfaceType st_under_it) { BOOST_LOG_TRIVIAL(info) << "overextrude over Bridge..."; @@ -1644,151 +1597,52 @@ void PrintObject::replaceSurfaceType(SurfaceType st_to_replace, SurfaceType st_r const PrintRegion ®ion = *m_print->regions()[region_id]; for (LayerPtrs::iterator layer_it = m_layers.begin(); layer_it != m_layers.end(); ++layer_it) { - // skip first layer if (layer_it == this->layers().begin()) continue; - - Layer* layer = *layer_it; + + Layer* layer = *layer_it; LayerRegion* layerm = layer->regions()[region_id]; - - // extract the stInternalSolid surfaces that might be transformed into bridges - Polygons internal_solid; - layerm->fill_surfaces.filter_by_type(st_to_replace, &internal_solid); - - double internsolidareainit=0; - for (ExPolygon &ex : union_ex(internal_solid)) internsolidareainit+=ex.area(); - - Polygons internal_over_tot_init; - layerm->fill_surfaces.filter_by_type(st_replacement, &internal_over_tot_init); - double totoverareaInit=0; - for (ExPolygon &ex : union_ex(internal_over_tot_init)) totoverareaInit+=ex.area(); - Polygons stBottom_init; - layerm->fill_surfaces.filter_by_type(stBottom, &stBottom_init); - double bottomeareainit=0; - for (ExPolygon &ex : union_ex(stBottom_init)) bottomeareainit+=ex.area(); + Polygons poly_to_check; + // extract the surfaces that might be transformed + layerm->fill_surfaces.filter_by_type(st_to_replace, &poly_to_check); + Polygons poly_to_replace = poly_to_check; - Polygons stBottomBridge_init; - layerm->fill_surfaces.filter_by_type(stBottomBridge, &stBottomBridge_init); - double bottombridgearea=0; - for (ExPolygon &ex : union_ex(stBottomBridge_init)) bottombridgearea+=ex.area(); - - Polygons stIntBridge_init; - layerm->fill_surfaces.filter_by_type(st_under_it, &stIntBridge_init); - double intbridgeareainit=0; - for (ExPolygon &ex : union_ex(stIntBridge_init)) intbridgeareainit+=ex.area(); - - // check whether the lower area is deep enough for absorbing the extra flow - // (for obvious physical reasons but also for preventing the bridge extrudates - // from overflowing in 3D preview) - ExPolygons to_overextrude; - { - Polygons to_overextrude_pp = internal_solid; - - // get previous layer - if (int(layer_it - this->layers().begin()) - 1 >= 0) { - const Layer* lower_layer = this->layers()[int(layer_it - this->layers().begin()) - 1]; - - // iterate through regions and collect internal surfaces - Polygons lower_internal; - for (LayerRegion *lower_layerm : lower_layer->m_regions) { - lower_layerm->fill_surfaces.filter_by_type(stInternal, &lower_internal); - Polygons lower_internal_OK; - Polygons lower_internal_Bridge; - Polygons lower_internal_Over; - lower_layerm->fill_surfaces.filter_by_type(st_replacement, &lower_internal_OK); - lower_layerm->fill_surfaces.filter_by_type(st_under_it, &lower_internal_Bridge); - lower_layerm->fill_surfaces.filter_by_type(st_to_replace, &lower_internal_Over); - double okarea =0, bridgearea=0, overarea=0; - for (ExPolygon &ex : union_ex(lower_internal_OK)) okarea+=ex.area(); - for (ExPolygon &ex : union_ex(lower_internal_Bridge)) bridgearea+=ex.area(); - for (ExPolygon &ex : union_ex(lower_internal_Over)) overarea+=ex.area(); + // check the lower layer + if (int(layer_it - this->layers().begin()) - 1 >= 0) { + const Layer* lower_layer = this->layers()[int(layer_it - this->layers().begin()) - 1]; - lower_layerm->fill_surfaces.filter_by_type(st_under_it, &lower_internal); - } - double sumarea=0; - for (ExPolygon &ex : union_ex(lower_internal)) sumarea+=ex.area(); - - // intersect such lower internal surfaces with the candidate solid surfaces - to_overextrude_pp = intersection(to_overextrude_pp, lower_internal); + // iterate through regions and collect internal surfaces + Polygons lower_internal; + for (LayerRegion *lower_layerm : lower_layer->m_regions) { + lower_layerm->fill_surfaces.filter_by_type(st_under_it, &lower_internal); } - - // there's no point in overextruding too thin/short regions - //FIXME Vojtech: The offset2 function is not a geometric offset, - // therefore it may create 1) gaps, and 2) sharp corners, which are outside the original contour. - // The gaps will be filled by a separate region, which makes the infill less stable and it takes longer. - // { - // float min_width = float(bridge_flow.scaled_width()) * 3.f; - // to_overextrude_pp = offset2(to_overextrude_pp, -min_width, +min_width); - // } - - if (to_overextrude_pp.empty()) continue; - - // convert into ExPolygons - to_overextrude = union_ex(to_overextrude_pp); + + // intersect such lower internal surfaces with the candidate solid surfaces + poly_to_replace = intersection(poly_to_replace, lower_internal); } - - #ifdef SLIC3R_DEBUG - printf("Bridging " PRINTF_ZU " internal areas at layer " PRINTF_ZU "\n", to_overextrude.size(), layer->id()); - #endif - + + if (poly_to_replace.empty()) continue; + // compute the remaning internal solid surfaces as difference - ExPolygons not_to_overextrude = diff_ex(internal_solid, to_polygons(to_overextrude), true); - to_overextrude = intersection_ex(to_polygons(to_overextrude), internal_solid, true); + ExPolygons not_expoly_to_replace = diff_ex(poly_to_check, poly_to_replace, true); // build the new collection of fill_surfaces - layerm->fill_surfaces.remove_type(st_to_replace); - double overareafinal = 0, solidareafinal=0; - for (ExPolygon &ex : to_overextrude){ - overareafinal += ex.area(); - layerm->fill_surfaces.surfaces.push_back(Surface(st_replacement, ex)); - } - for (ExPolygon &ex : not_to_overextrude){ - solidareafinal += ex.area(); - layerm->fill_surfaces.surfaces.push_back(Surface(st_to_replace, ex)); - } - Polygons internal_over_tot; - layerm->fill_surfaces.filter_by_type(stInternalOverBridge, &internal_over_tot); - double totoverarea=0; - for (ExPolygon &ex : union_ex(internal_over_tot)) totoverarea+=ex.area(); - - /* - # exclude infill from the layers below if needed - # see discussion at https://github.com/alexrj/Slic3r/issues/240 - # Update: do not exclude any infill. Sparse infill is able to absorb the excess material. - if (0) { - my $excess = $layerm->extruders->{infill}->bridge_flow->width - $layerm->height; - for (my $i = $layer_id-1; $excess >= $self->get_layer($i)->height; $i--) { - Slic3r::debugf " skipping infill below those areas at layer %d\n", $i; - foreach my $lower_layerm (@{$self->get_layer($i)->regions}) { - my @new_surfaces = (); - # subtract the area from all types of surfaces - foreach my $group (@{$lower_layerm->fill_surfaces->group}) { - push @new_surfaces, map $group->[0]->clone(expolygon => $_), - @{diff_ex( - [ map $_->p, @$group ], - [ map @$_, @$to_overextrude ], - )}; - push @new_surfaces, map Slic3r::Surface->new( - expolygon => $_, - surface_type => S_TYPE_INTERNALVOID, - ), @{intersection_ex( - [ map $_->p, @$group ], - [ map @$_, @$to_overextrude ], - )}; - } - $lower_layerm->fill_surfaces->clear; - $lower_layerm->fill_surfaces->append($_) for @new_surfaces; - } - - $excess -= $self->get_layer($i)->height; + { + Surfaces new_surfaces; + for (Surfaces::const_iterator surface = layerm->fill_surfaces.surfaces.begin(); surface != layerm->fill_surfaces.surfaces.end(); ++surface) { + if (surface->surface_type != st_to_replace) + new_surfaces.push_back(*surface); } - } - */ -#ifdef SLIC3R_DEBUG_SLICE_PROCESSING - layerm->export_region_slices_to_svg_debug("7_overextrude_over_bridge"); - layerm->export_region_fill_surfaces_to_svg_debug("7_overextrude_over_bridge"); -#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */ + for (ExPolygon &ex : union_ex(poly_to_replace)) { + new_surfaces.push_back(Surface(st_replacement, ex)); + } + for (ExPolygon &ex : not_expoly_to_replace){ + new_surfaces.push_back(Surface(st_to_replace, ex)); + } + + layerm->fill_surfaces.surfaces = new_surfaces; + } } } } @@ -1951,7 +1805,7 @@ void PrintObject::_slice(const std::vector &layer_height_profile) m_print->throw_if_canceled(); BOOST_LOG_TRIVIAL(debug) << "Slicing objects - append slices " << region_id << " start"; for (size_t layer_id = 0; layer_id < expolygons_by_layer.size(); ++ layer_id) - m_layers[layer_id]->regions()[region_id]->slices.append(std::move(expolygons_by_layer[layer_id]), stInternal); + m_layers[layer_id]->regions()[region_id]->slices.append(std::move(expolygons_by_layer[layer_id]), stPosInternal | stDensSparse); m_print->throw_if_canceled(); BOOST_LOG_TRIVIAL(debug) << "Slicing objects - append slices " << region_id << " end"; } @@ -1978,9 +1832,9 @@ void PrintObject::_slice(const std::vector &layer_height_profile) if (my_parts.empty()) continue; // Remove such parts from original region. - other_layerm->slices.set(diff_ex(other_slices, to_polygons(my_parts)), stInternal); + other_layerm->slices.set(diff_ex(other_slices, to_polygons(my_parts)), stPosInternal | stDensSparse); // Append new parts to our region. - layerm->slices.append(std::move(my_parts), stInternal); + layerm->slices.append(std::move(my_parts), stPosInternal | stDensSparse); } } m_print->throw_if_canceled(); @@ -2020,7 +1874,7 @@ end: if (scale) { // Single region, growing or shrinking. LayerRegion *layerm = layer->m_regions.front(); - layerm->slices.set(offset_ex(to_expolygons(std::move(layerm->slices.surfaces)), delta), stInternal); + layerm->slices.set(offset_ex(to_expolygons(std::move(layerm->slices.surfaces)), delta), stPosInternal | stDensSparse); } _offsetHoles(hole_delta, layer->regions().front()); } else if (scale || clip || hole_delta != 0.f) { @@ -2038,7 +1892,7 @@ end: if (clip && region_id + 1 < layer->m_regions.size()) // Collect the already processed regions to trim the to be processed regions. polygons_append(processed, slices); - layerm->slices.set(std::move(slices), stInternal); + layerm->slices.set(std::move(slices), stPosInternal | stDensSparse); _offsetHoles(hole_delta, layerm); } } @@ -2085,7 +1939,7 @@ void PrintObject::_offsetHoles(float hole_delta, LayerRegion *layerm) { } new_polys.push_back(new_ex_poly); } - layerm->slices.set(std::move(new_polys), stInternal); + layerm->slices.set(std::move(new_polys), stPosInternal | stDensSparse); } } @@ -2217,7 +2071,7 @@ std::string PrintObject::_fix_slicing_errors() if (lower_surfaces) for (const auto &surface : *lower_surfaces) polygons_append(holes, surface.expolygon.holes); - layerm->slices.set(diff_ex(union_(outer), holes, false), stInternal); + layerm->slices.set(diff_ex(union_(outer), holes, false), stPosInternal | stDensSparse); } // Update layer slices after repairing the single regions. layer->make_slices(); @@ -2397,7 +2251,7 @@ void PrintObject::clip_fill_surfaces() for (const LayerRegion *layerm : layer->m_regions) for (const Surface &surface : layerm->fill_surfaces.surfaces) { Polygons polygons = to_polygons(surface.expolygon); - if (surface.is_solid()) + if (surface.has_fill_solid()) polygons_append(overhangs, polygons); polygons_append(fill_surfaces, std::move(polygons)); } @@ -2406,7 +2260,7 @@ void PrintObject::clip_fill_surfaces() for (const LayerRegion *layerm : lower_layer->m_regions) for (const Surface &surface : layerm->fill_surfaces.surfaces) { Polygons polygons = to_polygons(surface.expolygon); - if (surface.surface_type == stInternal || surface.surface_type == stInternalVoid) + if (surface.has_pos_internal() && (surface.has_fill_sparse() || surface.has_fill_void()) ) polygons_append(lower_layer_internal_surfaces, polygons); polygons_append(lower_layer_fill_surfaces, std::move(polygons)); } @@ -2431,14 +2285,14 @@ void PrintObject::clip_fill_surfaces() for (LayerRegion *layerm : lower_layer->m_regions) { if (layerm->region()->config().fill_density.value == 0) continue; - SurfaceType internal_surface_types[] = { stInternal, stInternalVoid }; + SurfaceType internal_surface_types[] = { stPosInternal | stDensSparse, stPosInternal | stDensVoid }; Polygons internal; for (Surface &surface : layerm->fill_surfaces.surfaces) - if (surface.surface_type == stInternal || surface.surface_type == stInternalVoid) + if (surface.has_pos_internal() && (surface.has_fill_sparse() || surface.has_fill_void())) polygons_append(internal, std::move(surface.expolygon)); layerm->fill_surfaces.remove_types(internal_surface_types, 2); - layerm->fill_surfaces.append(intersection_ex(internal, upper_internal, true), stInternal); - layerm->fill_surfaces.append(diff_ex (internal, upper_internal, true), stInternalVoid); + layerm->fill_surfaces.append(intersection_ex(internal, upper_internal, true), stPosInternal | stDensSparse); + layerm->fill_surfaces.append(diff_ex (internal, upper_internal, true), stPosInternal | stDensVoid); // If there are voids it means that our internal infill is not adjacent to // perimeters. In this case it would be nice to add a loop around infill to // make it more robust and nicer. TODO. @@ -2462,9 +2316,9 @@ void PrintObject::discover_horizontal_shells() if (region_config.solid_infill_every_layers.value > 0 && region_config.fill_density.value > 0 && (i % region_config.solid_infill_every_layers) == 0) { // Insert a solid internal layer. Mark stInternal surfaces as stInternalSolid or stInternalBridge. - SurfaceType type = (region_config.fill_density == 100) ? stInternalSolid : stInternalBridge; + SurfaceType type = (region_config.fill_density == 100) ? (stPosInternal | stDensSolid) : (stPosInternal | stDensSolid | stModBridge); for (Surface &surface : layerm->fill_surfaces.surfaces) - if (surface.surface_type == stInternal) + if (surface.surface_type == stPosInternal | stDensSparse) surface.surface_type = type; } @@ -2474,7 +2328,8 @@ void PrintObject::discover_horizontal_shells() for (int idx_surface_type = 0; idx_surface_type < 3; ++ idx_surface_type) { m_print->throw_if_canceled(); - SurfaceType type = (idx_surface_type == 0) ? stTop : (idx_surface_type == 1) ? stBottom : stBottomBridge; + SurfaceType type = (idx_surface_type == 0) ? (stPosTop | stDensSolid) : + ( (idx_surface_type == 1) ? (stPosBottom | stDensSolid) : (stPosBottom | stDensSolid |stModBridge)); // Find slices of current type for current layer. // Use slices instead of fill_surfaces, because they also include the perimeter area, // which needs to be propagated in shells; we need to grow slices like we did for @@ -2500,8 +2355,8 @@ void PrintObject::discover_horizontal_shells() continue; // Slic3r::debugf "Layer %d has %s surfaces\n", $i, ($type == S_TYPE_TOP) ? 'top' : 'bottom'; - size_t solid_layers = (type == stTop || type == stTopOverBridge) ? region_config.top_solid_layers.value : region_config.bottom_solid_layers.value; - for (int n = (type == stTop || type == stTopOverBridge) ? i-1 : i+1; std::abs(n - i) < solid_layers; (type == stTop || type == stTopOverBridge) ? -- n : ++ n) { + size_t solid_layers = (type & stPosTop == stPosTop) ? region_config.top_solid_layers.value : region_config.bottom_solid_layers.value; + for (int n = (type & stPosTop == stPosTop) ? i - 1 : i + 1; std::abs(n - i) < solid_layers; (type & stPosTop == stPosTop) ? --n : ++n) { if (n < 0 || n >= int(m_layers.size())) continue; // Slic3r::debugf " looking for neighbors on layer %d...\n", $n; @@ -2522,7 +2377,7 @@ void PrintObject::discover_horizontal_shells() { Polygons internal; for (const Surface &surface : neighbor_layerm->fill_surfaces.surfaces) - if (surface.surface_type == stInternal || surface.surface_type == stInternalSolid) + if (surface.has_pos_internal() &&(surface.has_fill_sparse() || surface.has_fill_solid())) polygons_append(internal, to_polygons(surface.expolygon)); new_internal_solid = intersection(solid, internal, true); } @@ -2580,7 +2435,7 @@ void PrintObject::discover_horizontal_shells() // make sure our grown surfaces don't exceed the fill area Polygons internal; for (const Surface &surface : neighbor_layerm->fill_surfaces.surfaces) - if (surface.is_internal() && !surface.is_bridge()) + if (surface.has_pos_internal() && !surface.has_mod_bridge()) polygons_append(internal, to_polygons(surface.expolygon)); polygons_append(new_internal_solid, intersection( @@ -2598,22 +2453,23 @@ void PrintObject::discover_horizontal_shells() // internal-solid are the union of the existing internal-solid surfaces // and new ones SurfaceCollection backup = std::move(neighbor_layerm->fill_surfaces); - polygons_append(new_internal_solid, to_polygons(backup.filter_by_type(stInternalSolid))); + polygons_append(new_internal_solid, to_polygons(backup.filter_by_type(stPosInternal | stDensSolid))); ExPolygons internal_solid = union_ex(new_internal_solid, false); // assign new internal-solid surfaces to layer - neighbor_layerm->fill_surfaces.set(internal_solid, stInternalSolid); + neighbor_layerm->fill_surfaces.set(internal_solid, stPosInternal | stDensSolid); // subtract intersections from layer surfaces to get resulting internal surfaces Polygons polygons_internal = to_polygons(std::move(internal_solid)); ExPolygons internal = diff_ex( - to_polygons(backup.filter_by_type(stInternal)), + to_polygons(backup.filter_by_type(stPosInternal | stDensSparse)), polygons_internal, true); // assign resulting internal surfaces to layer - neighbor_layerm->fill_surfaces.append(internal, stInternal); + neighbor_layerm->fill_surfaces.append(internal, stPosInternal | stDensSparse); polygons_append(polygons_internal, to_polygons(std::move(internal))); // assign top and bottom surfaces to layer - SurfaceType surface_types_solid[] = { stTop, stBottom, stBottomBridge }; + SurfaceType surface_types_solid[] = { stPosTop | stDensSolid, stPosBottom | stDensSolid, stPosBottom | stDensSolid | stModBridge }; backup.keep_types(surface_types_solid, 3); + //backup.keep_types_flag(stPosTop | stPosBottom); std::vector top_bottom_groups; backup.group(&top_bottom_groups); for (SurfacesPtr &group : top_bottom_groups) @@ -2694,12 +2550,12 @@ void PrintObject::combine_infill() layerms.emplace_back(m_layers[i]->regions()[region_id]); // We need to perform a multi-layer intersection, so let's split it in pairs. // Initialize the intersection with the candidates of the lowest layer. - ExPolygons intersection = to_expolygons(layerms.front()->fill_surfaces.filter_by_type(stInternal)); + ExPolygons intersection = to_expolygons(layerms.front()->fill_surfaces.filter_by_type(stPosInternal | stDensSparse)); // Start looping from the second layer and intersect the current intersection with it. for (size_t i = 1; i < layerms.size(); ++ i) intersection = intersection_ex( to_polygons(intersection), - to_polygons(layerms[i]->fill_surfaces.filter_by_type(stInternal)), + to_polygons(layerms[i]->fill_surfaces.filter_by_type(stPosInternal | stDensSparse)), false); double area_threshold = layerms.front()->infill_area_threshold(); if (! intersection.empty() && area_threshold > 0.) @@ -2730,12 +2586,12 @@ void PrintObject::combine_infill() for (ExPolygon &expoly : intersection) polygons_append(intersection_with_clearance, offset(expoly, clearance_offset)); for (LayerRegion *layerm : layerms) { - Polygons internal = to_polygons(layerm->fill_surfaces.filter_by_type(stInternal)); - layerm->fill_surfaces.remove_type(stInternal); - layerm->fill_surfaces.append(diff_ex(internal, intersection_with_clearance, false), stInternal); + Polygons internal = to_polygons(layerm->fill_surfaces.filter_by_type(stPosInternal | stDensSparse)); + layerm->fill_surfaces.remove_type(stPosInternal | stDensSparse); + layerm->fill_surfaces.append(diff_ex(internal, intersection_with_clearance, false), stPosInternal | stDensSparse); if (layerm == layerms.back()) { // Apply surfaces back with adjusted depth to the uppermost layer. - Surface templ(stInternal, ExPolygon()); + Surface templ(stPosInternal | stDensSparse, ExPolygon()); templ.thickness = 0.; for (LayerRegion *layerm2 : layerms) templ.thickness += layerm2->layer()->height; @@ -2745,7 +2601,7 @@ void PrintObject::combine_infill() // Save void surfaces. layerm->fill_surfaces.append( intersection_ex(internal, intersection_with_clearance, false), - stInternalVoid); + stPosInternal | stDensVoid); } } } diff --git a/src/libslic3r/SupportMaterial.cpp b/src/libslic3r/SupportMaterial.cpp index da8683b8b..d556e586b 100644 --- a/src/libslic3r/SupportMaterial.cpp +++ b/src/libslic3r/SupportMaterial.cpp @@ -824,7 +824,7 @@ namespace SupportMaterialInternal { for (const LayerRegion *region : layer.regions()) { if (SupportMaterialInternal::has_bridging_perimeters(region->perimeters)) return true; - if (region->fill_surfaces.has(stBottomBridge) && has_bridging_fills(region->fills)) + if (region->fill_surfaces.has(stPosBottom | stDensSolid | stModBridge) && has_bridging_fills(region->fills)) return true; } return false; @@ -922,7 +922,7 @@ namespace SupportMaterialInternal { // remove the entire bridges and only support the unsupported edges //FIXME the brided regions are already collected as layerm->bridged. Use it? for (const Surface &surface : layerm->fill_surfaces.surfaces) - if (surface.surface_type == stBottomBridge && surface.bridge_angle != -1) + if (surface.has_pos_bottom() && surface.has_mod_bridge() && surface.bridge_angle != -1) polygons_append(bridges, surface.expolygon); //FIXME add the gap filled areas. Extrude the gaps with a bridge flow? // Remove the unsupported ends of the bridges from the bridged areas. @@ -1468,7 +1468,7 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::bottom_conta if (! m_object_config->support_material_buildplate_only) // Find the bottom contact layers above the top surfaces of this layer. task_group.run([this, &object, &top_contacts, contact_idx, &layer, layer_id, &layer_storage, &layer_support_areas, &bottom_contacts, &projection_raw] { - Polygons top = collect_region_slices_by_type(layer, stTop); + Polygons top = collect_region_slices_by_type(layer, stPosTop| stDensSolid); #ifdef SLIC3R_DEBUG { BoundingBox bbox = get_extents(projection_raw); @@ -2134,7 +2134,7 @@ void PrintObjectSupportMaterial::trim_support_layers_by_object( break; some_region_overlaps = true; polygons_append(polygons_trimming, - offset(to_expolygons(region->fill_surfaces.filter_by_type(stBottomBridge)), + offset(to_expolygons(region->fill_surfaces.filter_by_type(stPosBottom | stDensSolid | stModBridge)), gap_xy_scaled, SUPPORT_SURFACES_OFFSET_PARAMETERS)); if (region->region()->config().overhangs.value) SupportMaterialInternal::collect_bridging_perimeter_areas(region->perimeters, gap_xy_scaled, polygons_trimming); @@ -2335,7 +2335,7 @@ static inline void fill_expolygons_generate_paths( fill_params.flow = &flow; fill_params.role = role; for (const ExPolygon &expoly : expolygons) { - Surface surface(stInternal, expoly); + Surface surface(stPosInternal | stDensSparse, expoly); filler->fill_surface_extrusion(&surface, fill_params, dst); } } @@ -2355,7 +2355,7 @@ static inline void fill_expolygons_generate_paths( fill_params.flow = &flow; fill_params.role = role; for (ExPolygon &expoly : expolygons) { - Surface surface(stInternal, std::move(expoly)); + Surface surface(stPosInternal | stDensSparse, std::move(expoly)); filler->fill_surface_extrusion(&surface, fill_params, dst); } } diff --git a/src/libslic3r/Surface.cpp b/src/libslic3r/Surface.cpp index 40abc82d6..7db9bee72 100644 --- a/src/libslic3r/Surface.cpp +++ b/src/libslic3r/Surface.cpp @@ -16,61 +16,53 @@ Surface::area() const } bool -Surface::is_solid() const -{ - return this->surface_type == stTop - || this->surface_type == stBottom - || this->surface_type == stBottomBridge - || this->surface_type == stInternalSolid - || this->surface_type == stInternalBridge - || this->surface_type == stInternalOverBridge - || this->surface_type == stTopOverBridge; +Surface::has_fill_void() const { + return (this->surface_type & stDensVoid) != 0; } bool -Surface::is_external() const -{ - return this->surface_type == stTop - || this->surface_type == stBottom - || this->surface_type == stBottomBridge - || this->surface_type == stTopOverBridge; +Surface::has_fill_sparse() const { + return (this->surface_type & stDensSparse) != 0; } bool -Surface::is_top() const -{ - return this->surface_type == stTop - || this->surface_type == stTopOverBridge; +Surface::has_fill_solid() const { + return (this->surface_type & stDensSolid) != 0; } bool -Surface::is_internal() const +Surface::has_pos_external() const { - return this->surface_type == stInternal - || this->surface_type == stInternalBridge - || this->surface_type == stInternalOverBridge - || this->surface_type == stInternalSolid - || this->surface_type == stInternalVoid; + return has_pos_top() || has_pos_bottom(); } bool -Surface::is_bottom() const +Surface::has_pos_top() const { - return this->surface_type == stBottom - || this->surface_type == stBottomBridge; + return (this->surface_type & stPosTop) != 0; } bool -Surface::is_bridge() const +Surface::has_pos_internal() const { - return this->surface_type == stBottomBridge - || this->surface_type == stInternalBridge; + return (this->surface_type & stPosInternal) != 0; +} + +bool +Surface::has_pos_bottom() const +{ + return (this->surface_type & stPosBottom) != 0; +} + +bool +Surface::has_mod_bridge() const +{ + return (this->surface_type & stModBridge) != 0; } bool -Surface::is_overBridge() const +Surface::has_mod_overBridge() const { - return this->surface_type == stInternalOverBridge - || this->surface_type == stTopOverBridge; + return (this->surface_type & stModOverBridge) != 0; } BoundingBox get_extents(const Surface &surface) @@ -102,18 +94,16 @@ BoundingBox get_extents(const SurfacesPtr &surfaces) const char* surface_type_to_color_name(const SurfaceType surface_type) { - switch (surface_type) { - case stTop: return "rgb(255,0,0)"; // "red"; - case stBottom: return "rgb(0,255,0)"; // "green"; - case stBottomBridge: return "rgb(0,0,255)"; // "blue"; - case stInternal: return "rgb(255,255,128)"; // yellow - case stInternalSolid: return "rgb(255,0,255)"; // magenta - case stInternalBridge: return "rgb(0,255,255)"; // cyan - case stInternalOverBridge: return "rgb(0,255,128)"; // green-cyan - case stInternalVoid: return "rgb(128,128,128)"; - case stPerimeter: return "rgb(128,0,0)"; // maroon - default: return "rgb(64,64,64)"; - }; + if ((surface_type & stPosTop) != 0) return "rgb(255,0,0)"; // "red"; + if (surface_type == stPosBottom | stDensSolid | stModBridge) return "rgb(0,0,255)"; // "blue"; + if ((surface_type & stPosBottom) != 0) return "rgb(0,255,0)"; // "green"; + if (surface_type == stPosInternal | stDensSolid | stModBridge) return "rgb(0,255,255)"; // cyan + if (surface_type == stPosInternal | stDensSolid | stModOverBridge) return "rgb(0,255,128)"; // green-cyan + if (surface_type == stPosInternal | stDensSolid) return "rgb(255,0,255)"; // magenta + if (surface_type == stPosInternal | stDensVoid) return "rgb(128,128,128)"; // gray + if (surface_type == stPosInternal | stDensSparse) return "rgb(255,255,128)"; // yellow + if ((surface_type & stPosPerimeter) != 0) return "rgb(128,0,0)"; // maroon + return "rgb(64,64,64)"; //dark gray } Point export_surface_type_legend_to_svg_box_size() @@ -128,27 +118,27 @@ void export_surface_type_legend_to_svg(SVG &svg, const Point &pos) coord_t pos_x = pos_x0; coord_t pos_y = pos(1) + scale_(1.5); coord_t step_x = scale_(10.); - svg.draw_legend(Point(pos_x, pos_y), "perimeter" , surface_type_to_color_name(stPerimeter)); + svg.draw_legend(Point(pos_x, pos_y), "perimeter" , surface_type_to_color_name(stPosPerimeter)); pos_x += step_x; - svg.draw_legend(Point(pos_x, pos_y), "top" , surface_type_to_color_name(stTop)); + svg.draw_legend(Point(pos_x, pos_y), "top" , surface_type_to_color_name(stPosTop)); pos_x += step_x; - svg.draw_legend(Point(pos_x, pos_y), "bottom" , surface_type_to_color_name(stBottom)); + svg.draw_legend(Point(pos_x, pos_y), "bottom" , surface_type_to_color_name(stPosBottom)); pos_x += step_x; - svg.draw_legend(Point(pos_x, pos_y), "bottom bridge" , surface_type_to_color_name(stBottomBridge)); + svg.draw_legend(Point(pos_x, pos_y), "bottom bridge" , surface_type_to_color_name(stPosBottom | stModBridge)); pos_x += step_x; svg.draw_legend(Point(pos_x, pos_y), "invalid" , surface_type_to_color_name(SurfaceType(-1))); // 2nd row pos_x = pos_x0; pos_y = pos(1)+scale_(2.8); - svg.draw_legend(Point(pos_x, pos_y), "internal" , surface_type_to_color_name(stInternal)); + svg.draw_legend(Point(pos_x, pos_y), "internal" , surface_type_to_color_name(stPosInternal | stDensSparse)); pos_x += step_x; - svg.draw_legend(Point(pos_x, pos_y), "internal solid" , surface_type_to_color_name(stInternalSolid)); + svg.draw_legend(Point(pos_x, pos_y), "internal solid" , surface_type_to_color_name(stPosInternal | stDensSolid)); pos_x += step_x; - svg.draw_legend(Point(pos_x, pos_y), "internal bridge", surface_type_to_color_name(stInternalBridge)); + svg.draw_legend(Point(pos_x, pos_y), "internal bridge", surface_type_to_color_name(stPosInternal | stDensSolid | stModBridge)); pos_x += step_x; - svg.draw_legend(Point(pos_x, pos_y), "internal over bridge", surface_type_to_color_name(stInternalOverBridge)); + svg.draw_legend(Point(pos_x, pos_y), "internal over bridge", surface_type_to_color_name(stPosInternal| stDensSolid | stModOverBridge)); pos_x += step_x; - svg.draw_legend(Point(pos_x, pos_y), "internal void" , surface_type_to_color_name(stInternalVoid)); + svg.draw_legend(Point(pos_x, pos_y), "internal void" , surface_type_to_color_name(stPosInternal | stDensVoid)); } bool export_to_svg(const char *path, const Surfaces &surfaces, const float transparency) diff --git a/src/libslic3r/Surface.hpp b/src/libslic3r/Surface.hpp index f9bba7891..5f67ca440 100644 --- a/src/libslic3r/Surface.hpp +++ b/src/libslic3r/Surface.hpp @@ -6,31 +6,50 @@ namespace Slic3r { -enum SurfaceType { - // Top horizontal surface, visible from the top. - stTop, - // Bottom horizontal surface, visible from the bottom, printed with a normal extrusion flow. - stBottom, - // Bottom horizontal surface, visible from the bottom, unsupported, printed with a bridging extrusion flow. - stBottomBridge, - // Normal sparse infill. - stInternal, - // Full infill, supporting the top surfaces and/or defining the verticall wall thickness. - stInternalSolid, - // 1st layer of dense infill over sparse infill, printed with a bridging extrusion flow. - stInternalBridge, - // 2nd layer of dense infill over sparse infill/nothing, printed with an over-extruding flow. - stInternalOverBridge, - stTopOverBridge, - // stInternal turns into void surfaces if the sparse infill is used for supports only, - // or if sparse infill layers get combined into a single layer. - stInternalVoid, - // Inner/outer perimeters. - stPerimeter, - // Last surface type, if the SurfaceType is used as an index into a vector. - stLast, - stCount = stLast + 1 +/// a SurfaceType should be composed of a Position & density flag +/// Position: top, bottom, internal +/// Density: solid, sparse, void +/// optinally, is can also have one bridge modifier (bridge, over-bridge). +enum SurfaceType : uint16_t { + stNone = 0, + /// Position: Top horizontal surface, visible from the top. + stPosTop = 1 << 0, + /// Position: Bottom horizontal surface, visible from the bottom, printed with a normal extrusion flow. + stPosBottom = 1 << 1, + /// Position: Normal sparse infill. + stPosInternal = 1 << 2, + /// Position: Inner/outer perimeters. Mainly used for coloring + stPosPerimeter = 1 << 3, + /// Density: Solid infill (100%). + stDensSolid = 1 << 4, + /// Density: Sparse infill (>0% & <100%). + stDensSparse = 1 << 5, + /// Density: or if sparse infill layers get combined into a single layer. + stDensVoid = 1 << 6, + /// Bridge Modifier: 1st layer of dense infill over sparse infill, printed with a bridging extrusion flow. + stModBridge = 1 << 7, + /// Bridge Modifier: 2nd layer of dense infill over sparse infill/nothing, may be printed with an over-extruding flow. + stModOverBridge = 1 << 8, }; +inline SurfaceType operator|(SurfaceType a, SurfaceType b) { + return static_cast(static_cast(a) | static_cast(b)); +} +inline SurfaceType operator&(SurfaceType a, SurfaceType b) { + return static_cast(static_cast(a)& static_cast(b)); +} +inline SurfaceType operator|=(SurfaceType& a, SurfaceType b) { + a = a | b; return a; +} +inline SurfaceType operator&=(SurfaceType& a, SurfaceType b) { + a = a & b; return a; +} +//inline bool operator==(SurfaceType a, SurfaceType b) { +// return static_cast(a) ^ static_cast(b) == 0; +//} +//inline bool operator!=(SurfaceType a, SurfaceType b) { +// return static_cast(a) ^ static_cast(b) != 0; +//} + class Surface { @@ -108,13 +127,15 @@ public: double area() const; bool empty() const { return expolygon.empty(); } void clear() { expolygon.clear(); } - bool is_solid() const; - bool is_external() const; - bool is_top() const; - bool is_internal() const; - bool is_bottom() const; - bool is_bridge() const; - bool is_overBridge() const; + bool has_fill_solid() const; + bool has_fill_sparse() const; + bool has_fill_void() const; + bool has_pos_external() const; + bool has_pos_top() const; + bool has_pos_internal() const; + bool has_pos_bottom() const; + bool has_mod_bridge() const; + bool has_mod_overBridge() const; }; typedef std::vector Surfaces; diff --git a/src/libslic3r/SurfaceCollection.cpp b/src/libslic3r/SurfaceCollection.cpp index 6db599306..27ebe24ee 100644 --- a/src/libslic3r/SurfaceCollection.cpp +++ b/src/libslic3r/SurfaceCollection.cpp @@ -64,6 +64,16 @@ SurfaceCollection::filter_by_type(const SurfaceType type) return ss; } +SurfacesPtr +SurfaceCollection::filter_by_type_flag(const SurfaceType allowed, const SurfaceType not_allowed) +{ + SurfacesPtr ss; + for (Surfaces::iterator surface = this->surfaces.begin(); surface != this->surfaces.end(); ++surface) { + if (surface->surface_type & allowed == allowed && surface->surface_type & not_allowed == 0) ss.push_back(&*surface); + } + return ss; +} + SurfacesPtr SurfaceCollection::filter_by_types(const SurfaceType *types, int ntypes) { @@ -80,7 +90,7 @@ SurfaceCollection::filter_by_types(const SurfaceType *types, int ntypes) } void -SurfaceCollection::filter_by_type(SurfaceType type, Polygons* polygons) +SurfaceCollection::filter_by_type(const SurfaceType type, Polygons* polygons) { for (Surfaces::iterator surface = this->surfaces.begin(); surface != this->surfaces.end(); ++surface) { if (surface->surface_type == type) { @@ -89,16 +99,41 @@ SurfaceCollection::filter_by_type(SurfaceType type, Polygons* polygons) } } } +void +SurfaceCollection::filter_by_type_flag(Polygons* polygons, const SurfaceType flags_needed, const SurfaceType flags_not_allowed) +{ + for (Surfaces::iterator surface = this->surfaces.begin(); surface != this->surfaces.end(); ++surface) { + if (surface->surface_type & flags_needed == flags_needed && surface->surface_type & flags_not_allowed) { + Polygons pp = surface->expolygon; + polygons->insert(polygons->end(), pp.begin(), pp.end()); + } + } +} void SurfaceCollection::keep_type(const SurfaceType type) { size_t j = 0; - for (size_t i = 0; i < surfaces.size(); ++ i) { + for (size_t i = 0; i < surfaces.size(); ++i) { if (surfaces[i].surface_type == type) { if (j < i) std::swap(surfaces[i], surfaces[j]); - ++ j; + ++j; + } + } + if (j < surfaces.size()) + surfaces.erase(surfaces.begin() + j, surfaces.end()); +} + +void +SurfaceCollection::keep_type_flag(const SurfaceType type_to_keep, const SurfaceType type_to_remove) +{ + size_t j = 0; + for (size_t i = 0; i < surfaces.size(); ++i) { + if (surfaces[i].surface_type & type_to_keep == type_to_keep && surfaces[i].surface_type & type_to_remove == 0) { + if (j < i) + std::swap(surfaces[i], surfaces[j]); + ++j; } } if (j < surfaces.size()) @@ -127,6 +162,21 @@ SurfaceCollection::keep_types(const SurfaceType *types, int ntypes) surfaces.erase(surfaces.begin() + j, surfaces.end()); } +void +SurfaceCollection::keep_types_flag(const SurfaceType types_to_keep, const SurfaceType type_to_remove) +{ + size_t j = 0; + for (size_t i = 0; i < surfaces.size(); ++i) { + if (surfaces[i].surface_type & types_to_keep != 0 && surfaces[i].surface_type & type_to_remove == 0) { + if (j < i) + std::swap(surfaces[i], surfaces[j]); + ++j; + } + } + if (j < surfaces.size()) + surfaces.erase(surfaces.begin() + j, surfaces.end()); +} + void SurfaceCollection::remove_type(const SurfaceType type) { diff --git a/src/libslic3r/SurfaceCollection.hpp b/src/libslic3r/SurfaceCollection.hpp index 9544748e9..6fb68cc23 100644 --- a/src/libslic3r/SurfaceCollection.hpp +++ b/src/libslic3r/SurfaceCollection.hpp @@ -20,20 +20,24 @@ public: void simplify(double tolerance); void group(std::vector *retval); template bool any_internal_contains(const T &item) const { - for (const Surface &surface : this->surfaces) if (surface.is_internal() && surface.expolygon.contains(item)) return true; + for (const Surface &surface : this->surfaces) if (surface.has_pos_internal() && surface.expolygon.contains(item)) return true; return false; } template bool any_bottom_contains(const T &item) const { - for (const Surface &surface : this->surfaces) if (surface.is_bottom() && surface.expolygon.contains(item)) return true; + for (const Surface &surface : this->surfaces) if (surface.has_pos_bottom() && surface.expolygon.contains(item)) return true; return false; } SurfacesPtr filter_by_type(const SurfaceType type); + SurfacesPtr filter_by_type_flag(const SurfaceType allowed, const SurfaceType not_allowed = stNone); SurfacesPtr filter_by_types(const SurfaceType *types, int ntypes); void keep_type(const SurfaceType type); + void keep_type_flag(const SurfaceType flags_needed, const SurfaceType flags_to_remove = stNone); void keep_types(const SurfaceType *types, int ntypes); + void keep_types_flag(const SurfaceType flags_to_keep, const SurfaceType flags_to_remove = stNone); void remove_type(const SurfaceType type); void remove_types(const SurfaceType *types, int ntypes); - void filter_by_type(SurfaceType type, Polygons* polygons); + void filter_by_type(const SurfaceType type, Polygons* polygons); + void filter_by_type_flag(Polygons* polygons, const SurfaceType flags_needed, const SurfaceType flags_not_allowed = stNone); void clear() { surfaces.clear(); } bool empty() const { return surfaces.empty(); }