diff --git a/lib/Slic3r/Print/SupportMaterial.pm b/lib/Slic3r/Print/SupportMaterial.pm index 5c7324d65..0fcfecf2f 100644 --- a/lib/Slic3r/Print/SupportMaterial.pm +++ b/lib/Slic3r/Print/SupportMaterial.pm @@ -269,7 +269,7 @@ sub contact_area { # remove the entire bridges and only support the unsupported edges my @bridges = map $_->expolygon, grep $_->bridge_angle != -1, - @{$layerm->fill_surfaces->filter_by_type(S_TYPE_BOTTOMBRIDGE)}; + @{$layerm->fill_surfaces->filter_by_type(S_TYPE_BOTTOM + S_TYPE_BRIDGE)}; $diff = diff( $diff, diff --git a/lib/Slic3r/Surface.pm b/lib/Slic3r/Surface.pm index 0c5bb5d23..2b1814120 100644 --- a/lib/Slic3r/Surface.pm +++ b/lib/Slic3r/Surface.pm @@ -4,7 +4,7 @@ use warnings; require Exporter; our @ISA = qw(Exporter); -our @EXPORT_OK = qw(S_TYPE_TOP S_TYPE_BOTTOM S_TYPE_BOTTOMBRIDGE S_TYPE_INTERNAL S_TYPE_INTERNALSOLID S_TYPE_INTERNALBRIDGE S_TYPE_INTERNALVOID); +our @EXPORT_OK = qw(S_TYPE_TOP S_TYPE_BOTTOM S_TYPE_INTERNAL S_TYPE_SOLID S_TYPE_BRIDGE S_TYPE_VOID); our %EXPORT_TAGS = (types => \@EXPORT_OK); sub p { diff --git a/t/combineinfill.t b/t/combineinfill.t index 66e461d45..510f7aa93 100644 --- a/t/combineinfill.t +++ b/t/combineinfill.t @@ -82,7 +82,7 @@ plan tests => 8; my $print = Slic3r::Test::init_print('20mm_cube', config => $config); $print->process; - ok defined(first { @{$_->get_region(0)->fill_surfaces->filter_by_type(S_TYPE_INTERNALVOID)} > 0 } + ok defined(first { @{$_->get_region(0)->fill_surfaces->filter_by_type(S_TYPE_INTERNAL + S_TYPE_VOID)} > 0 } @{$print->print->get_object(0)->layers}), 'infill combination produces internal void surfaces'; diff --git a/xs/src/libslic3r/Layer.cpp b/xs/src/libslic3r/Layer.cpp index cbbc6b3ee..3e627b164 100644 --- a/xs/src/libslic3r/Layer.cpp +++ b/xs/src/libslic3r/Layer.cpp @@ -267,7 +267,7 @@ Layer::make_fills() /// Initially all slices are of type S_TYPE_INTERNAL. /// Slices are compared against the top / bottom slices and regions and classified to the following groups: /// S_TYPE_TOP - Part of a region, which is not covered by any upper layer. This surface will be filled with a top solid infill. -/// S_TYPE_BOTTOMBRIDGE - Part of a region, which is not fully supported, but it hangs in the air, or it hangs losely on a support or a raft. +/// S_TYPE_BOTTOM | S_TYPE_BRIDGE - Part of a region, which is not fully supported, but it hangs in the air, or it hangs losely on a support or a raft. /// S_TYPE_BOTTOM - Part of a region, which is not supported by the same region, but it is supported either by another region, or by a soluble interface layer. /// S_TYPE_INTERNAL - Part of a region, which is supported by the same region type. /// If a part of a region is of S_TYPE_BOTTOM and S_TYPE_TOP, the S_TYPE_BOTTOM wins. @@ -331,7 +331,7 @@ Layer::detect_surfaces_type() const SurfaceType surface_type_bottom = (object.config.support_material.value && object.config.support_material_contact_distance.value == 0) ? stBottom - : stBottomBridge; + : (stBottom | stBridge); // Any surface lying on the void is a true bottom bridge (an overhang) bottom.append( @@ -370,7 +370,7 @@ Layer::detect_surfaces_type() // just like any other bottom surface lying on the void const SurfaceType surface_type_bottom = (object.config.raft_layers.value > 0 && object.config.support_material_contact_distance.value > 0) - ? stBottomBridge + ? (stBottom | stBridge) : stBottom; for (Surface &s : bottom.surfaces) s.surface_type = surface_type_bottom; } diff --git a/xs/src/libslic3r/LayerRegion.cpp b/xs/src/libslic3r/LayerRegion.cpp index 49e1775ea..56fd6e09f 100644 --- a/xs/src/libslic3r/LayerRegion.cpp +++ b/xs/src/libslic3r/LayerRegion.cpp @@ -152,7 +152,7 @@ LayerRegion::process_external_surfaces() SurfaceCollection top; for (const Surface &surface : surfaces) { - if (surface.surface_type != stTop) continue; + if (!surface.is_top()) continue; // give priority to bottom surfaces ExPolygons grown = diff_ex( @@ -203,7 +203,7 @@ LayerRegion::process_external_surfaces() { SurfaceCollection other; for (const Surface &s : surfaces) - if (s.surface_type != stTop && !s.is_bottom()) + if (!s.is_top() && !s.is_bottom()) other.surfaces.push_back(s); // group surfaces @@ -238,21 +238,21 @@ LayerRegion::prepare_fill_surfaces() // if no solid layers are requested, turn top/bottom surfaces to internal if (this->region()->config.top_solid_layers == 0 && this->region()->config.min_top_bottom_shell_thickness <= 0) { - for (Surfaces::iterator surface = this->fill_surfaces.surfaces.begin(); surface != this->fill_surfaces.surfaces.end(); ++surface) { - if (surface->surface_type == stTop) { + for (Surface &surface : this->fill_surfaces.surfaces) { + if (surface.surface_type == stTop) { if (this->layer()->object()->config.infill_only_where_needed) { - surface->surface_type = stInternalVoid; + surface.surface_type = (stInternal | stVoid); } else { - surface->surface_type = stInternal; + surface.surface_type = stInternal; } } } } if (this->region()->config.bottom_solid_layers == 0 && this->region()->config.min_top_bottom_shell_thickness <= 0) { - for (Surfaces::iterator surface = this->fill_surfaces.surfaces.begin(); surface != this->fill_surfaces.surfaces.end(); ++surface) { - if (surface->surface_type == stBottom || surface->surface_type == stBottomBridge) - surface->surface_type = stInternal; + for (Surface &surface : this->fill_surfaces.surfaces) { + if (surface.is_bottom()) + surface.surface_type = stInternal; } } @@ -264,7 +264,7 @@ LayerRegion::prepare_fill_surfaces() const double min_area = this->region()->config.solid_infill_below_area.value / SCALING_FACTOR / SCALING_FACTOR; for (Surface &surface : this->fill_surfaces.surfaces) { if (surface.surface_type == stInternal && surface.area() <= min_area) - surface.surface_type = stInternalSolid; + surface.surface_type = (stInternal | stSolid); } } } diff --git a/xs/src/libslic3r/LayerRegionFill.cpp b/xs/src/libslic3r/LayerRegionFill.cpp index 3eb5e4a8d..4788fbc2a 100644 --- a/xs/src/libslic3r/LayerRegionFill.cpp +++ b/xs/src/libslic3r/LayerRegionFill.cpp @@ -67,8 +67,8 @@ LayerRegion::make_fill() if (!surface.is_solid() || surface.is_bridge()) continue; group_attrib[i].is_solid = true; - group_attrib[i].fw = (surface.surface_type == stTop) ? top_solid_infill_flow.width : solid_infill_flow.width; - group_attrib[i].pattern = surface.surface_type == stTop ? this->region()->config.top_infill_pattern.value + group_attrib[i].fw = (surface.is_top()) ? top_solid_infill_flow.width : solid_infill_flow.width; + group_attrib[i].pattern = surface.is_top() ? this->region()->config.top_infill_pattern.value : surface.is_bottom() ? this->region()->config.bottom_infill_pattern.value : ipRectilinear; } @@ -137,7 +137,7 @@ LayerRegion::make_fill() ); Polygons to_subtract; - surfaces.filter_by_type(stInternalVoid, &to_subtract); + surfaces.filter_by_type((stInternal | stVoid), &to_subtract); append_to(to_subtract, collapsed); surfaces.append( @@ -146,7 +146,7 @@ LayerRegion::make_fill() to_subtract, true ), - stInternalSolid + (stInternal | stSolid) ); } @@ -162,20 +162,20 @@ LayerRegion::make_fill() surface_it != surfaces.surfaces.end(); ++surface_it) { const Surface &surface = *surface_it; - if (surface.surface_type == stInternalVoid) + if (surface.surface_type == (stInternal | stVoid)) continue; InfillPattern fill_pattern = this->region()->config.fill_pattern.value; double density = fill_density; - FlowRole role = (surface.surface_type == stTop) ? frTopSolidInfill + FlowRole role = (surface.is_top()) ? frTopSolidInfill : surface.is_solid() ? frSolidInfill : frInfill; const bool is_bridge = this->layer()->id() > 0 && surface.is_bridge(); if (surface.is_solid()) { density = 100.; - fill_pattern = (surface.surface_type == stTop) ? this->region()->config.top_infill_pattern.value - : (surface.is_bottom() && !is_bridge) ? this->region()->config.bottom_infill_pattern.value + fill_pattern = (surface.is_top()) ? this->region()->config.top_infill_pattern.value + : (surface.is_bottom() && !is_bridge) ? this->region()->config.bottom_infill_pattern.value : ipRectilinear; } else if (density <= 0) continue; @@ -277,7 +277,7 @@ LayerRegion::make_fill() if (is_bridge) { role = erBridgeInfill; } else if (surface.is_solid()) { - role = (surface.surface_type == stTop) ? erTopSolidInfill : erSolidInfill; + role = (surface.is_top()) ? erTopSolidInfill : erSolidInfill; } else { role = erInternalInfill; } diff --git a/xs/src/libslic3r/PrintObject.cpp b/xs/src/libslic3r/PrintObject.cpp index 4bea641e5..3ae97f900 100644 --- a/xs/src/libslic3r/PrintObject.cpp +++ b/xs/src/libslic3r/PrintObject.cpp @@ -395,7 +395,7 @@ 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((stInternal | stSolid), &internal_solid); if (internal_solid.empty()) continue; // check whether we should bridge or not according to density @@ -492,15 +492,15 @@ PrintObject::bridge_over_infill() { Surfaces new_surfaces; for (Surfaces::const_iterator surface = layerm->fill_surfaces.surfaces.begin(); surface != layerm->fill_surfaces.surfaces.end(); ++surface) { - if (surface->surface_type != stInternalSolid) + if (surface->surface_type != (stInternal | stSolid)) new_surfaces.push_back(*surface); } for (ExPolygons::const_iterator ex = to_bridge.begin(); ex != to_bridge.end(); ++ex) - new_surfaces.push_back(Surface(stInternalBridge, *ex)); + new_surfaces.push_back(Surface( (stInternal | stBridge), *ex)); for (ExPolygons::const_iterator ex = not_to_bridge.begin(); ex != not_to_bridge.end(); ++ex) - new_surfaces.push_back(Surface(stInternalSolid, *ex)); + new_surfaces.push_back(Surface( (stInternal | stSolid), *ex)); layerm->fill_surfaces.surfaces = new_surfaces; } @@ -524,7 +524,7 @@ PrintObject::bridge_over_infill() )}; push @new_surfaces, map Slic3r::Surface->new( expolygon => $_, - surface_type => S_TYPE_INTERNALVOID, + surface_type => S_TYPE_INTERNAL + S_TYPE_VOID, ), @{intersection_ex( [ map $_->p, @$group ], [ map @$_, @$to_bridge ], @@ -1375,9 +1375,8 @@ PrintObject::combine_infill() } else { // Save void surfaces. layerm->fill_surfaces.append( - intersection_ex(internal, intersection_with_clearance), - stInternalVoid - ); + intersection_ex(internal, intersection_with_clearance), + (stInternal | stVoid)); } } } @@ -1481,7 +1480,7 @@ PrintObject::discover_horizontal_shells() if (region_config.solid_infill_every_layers() > 0 && region_config.fill_density() > 0 && (i % region_config.solid_infill_every_layers()) == 0) { - const auto type = region_config.fill_density() == 100 ? stInternalSolid : stInternalBridge; + const auto type = region_config.fill_density() == 100 ? (stInternal | stSolid) : (stInternal | stBridge); for (auto* s : layerm->fill_surfaces.filter_by_type(stInternal)) s->surface_type = type; } @@ -1494,7 +1493,7 @@ void PrintObject::_discover_external_horizontal_shells(LayerRegion* layerm, const size_t& i, const size_t& region_id) { const auto& region_config = layerm->region()->config; - for (auto& type : { stTop, stBottom, stBottomBridge }) { + for (auto& type : { stTop, stBottom, (stBottom | stBridge) }) { // 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 @@ -1535,7 +1534,7 @@ PrintObject::_discover_neighbor_horizontal_shells(LayerRegion* layerm, const siz { const auto& region_config = layerm->region()->config; - for (int n = (type == stTop ? i-1 : i+1); std::abs(n-int(i)) < solid_layers; (type == stTop ? n-- : n++)) { + for (int n = ((type & stTop) != 0 ? i-1 : i+1); std::abs(n-int(i)) < solid_layers; ((type & stTop) != 0 ? n-- : n++)) { if (n < 0 || static_cast(n) >= this->layer_count()) continue; LayerRegion* neighbor_layerm { this->get_layer(n)->get_region(region_id) }; @@ -1546,7 +1545,7 @@ PrintObject::_discover_neighbor_horizontal_shells(LayerRegion* layerm, const siz // intersections have contours and holes Polygons new_internal_solid = intersection( solid, - to_polygons(neighbor_fill_surfaces.filter_by_type({stInternal, stInternalSolid})), + to_polygons(neighbor_fill_surfaces.filter_by_type({stInternal, (stInternal | stSolid)})), true ); if (new_internal_solid.empty()) { @@ -1624,25 +1623,25 @@ PrintObject::_discover_neighbor_horizontal_shells(LayerRegion* layerm, const siz // internal-solid are the union of the existing internal-solid surfaces // and new ones - Polygons tmp { to_polygons(neighbor_fill_surfaces.filter_by_type(stInternalSolid)) }; + Polygons tmp { to_polygons(neighbor_fill_surfaces.filter_by_type(stInternal | stSolid)) }; polygons_append(tmp, new_internal_solid); - const auto internal_solid = union_ex(tmp); + const ExPolygons internal_solid = union_ex(tmp); // subtract intersections from layer surfaces to get resulting internal surfaces tmp = to_polygons(neighbor_fill_surfaces.filter_by_type(stInternal)); - const auto internal = diff_ex(tmp, to_polygons(internal_solid), 1); + const ExPolygons internal = diff_ex(tmp, to_polygons(internal_solid), 1); // assign resulting internal surfaces to layer neighbor_layerm->fill_surfaces.clear(); neighbor_layerm->fill_surfaces.append(internal, stInternal); // assign new internal-solid surfaces to layer - neighbor_layerm->fill_surfaces.append(internal_solid, stInternalSolid); + neighbor_layerm->fill_surfaces.append(internal_solid, (stInternal | stSolid)); // assign top and bottom surfaces to layer SurfaceCollection tmp_coll; - for (const auto& s : neighbor_fill_surfaces.surfaces) - if (s.surface_type == stTop || s.is_bottom()) + for (const Surface& s : neighbor_fill_surfaces.surfaces) + if (s.is_top() || s.is_bottom()) tmp_coll.append(s); for (auto s : tmp_coll.group()) { @@ -1720,7 +1719,7 @@ PrintObject::clip_fill_surfaces() Polygons lower_layer_internal_surfaces; for (const auto* layerm : lower_layer->regions) polygons_append(lower_layer_internal_surfaces, to_polygons( - layerm->fill_surfaces.filter_by_type({ stInternal, stInternalVoid }) + layerm->fill_surfaces.filter_by_type({ stInternal, (stInternal | stVoid) }) )); upper_internal = intersection(overhangs, lower_layer_internal_surfaces); } @@ -1730,10 +1729,10 @@ PrintObject::clip_fill_surfaces() if (layerm->region()->config.fill_density.value == 0) continue; - Polygons internal{ to_polygons(layerm->fill_surfaces.filter_by_type({ stInternal, stInternalVoid })) }; - layerm->fill_surfaces.remove_types({ stInternal, stInternalVoid }); + Polygons internal{ to_polygons(layerm->fill_surfaces.filter_by_type({ stInternal, (stInternal | stVoid) })) }; + layerm->fill_surfaces.remove_types({ stInternal, (stInternal | stVoid) }); 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(diff_ex (internal, upper_internal, true), (stInternal | stVoid)); // 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 diff --git a/xs/src/libslic3r/SupportMaterial.cpp b/xs/src/libslic3r/SupportMaterial.cpp index ce493e84d..556873297 100644 --- a/xs/src/libslic3r/SupportMaterial.cpp +++ b/xs/src/libslic3r/SupportMaterial.cpp @@ -409,7 +409,7 @@ SupportMaterial::contact_area(PrintObject *object) if (1) { // Remove the entire bridges and only support the unsupported edges. ExPolygons bridges; - for (auto surface : layer_m->fill_surfaces.filter_by_type(stBottomBridge)) { + for (auto surface : layer_m->fill_surfaces.filter_by_type(stBottom | stBridge)) { if (surface->bridge_angle != -1) { bridges.push_back(surface->expolygon); } diff --git a/xs/src/libslic3r/Surface.cpp b/xs/src/libslic3r/Surface.cpp index 4d2234e4d..4d45cc6e7 100644 --- a/xs/src/libslic3r/Surface.cpp +++ b/xs/src/libslic3r/Surface.cpp @@ -16,42 +16,37 @@ 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; + return (this->surface_type & (stTop | stBottom | stSolid | stBridge)) != 0; } bool Surface::is_external() const { - return this->surface_type == stTop - || this->surface_type == stBottom - || this->surface_type == stBottomBridge; + return is_top() || is_bottom(); } bool Surface::is_internal() const { - return this->surface_type == stInternal - || this->surface_type == stInternalBridge - || this->surface_type == stInternalSolid - || this->surface_type == stInternalVoid; + return (this->surface_type & stInternal) != 0; } bool Surface::is_bottom() const { - return this->surface_type == stBottom - || this->surface_type == stBottomBridge; + return (this->surface_type & stBottom) != 0; +} + +bool +Surface::is_top() const +{ + return (this->surface_type & stTop) != 0; } bool Surface::is_bridge() const { - return this->surface_type == stBottomBridge - || this->surface_type == stInternalBridge; + return (this->surface_type & stBridge) != 0; } } diff --git a/xs/src/libslic3r/Surface.hpp b/xs/src/libslic3r/Surface.hpp index 17e232d7c..2668dcabd 100644 --- a/xs/src/libslic3r/Surface.hpp +++ b/xs/src/libslic3r/Surface.hpp @@ -8,15 +8,22 @@ namespace Slic3r { /// Surface type enumerations. /// As it is very unlikely that there will be more than 32 or 64 of these surface types, pack into a flag -enum SurfaceType { - stTop = 0b1, - stBottom = 0b10, - stBottomBridge = 0b100, - stInternal = 0b1000, - stInternalSolid = 0b10000, - stInternalBridge = 0b100000, - stInternalVoid = 0b1000000 +enum SurfaceType : uint16_t { + stTop = 0b1, /// stTop: it has nothing just on top of it + stBottom = 0b10, /// stBottom: it's a surface with nothing just under it (or the base plate, or a support) + stInternal = 0b100, /// stInternal: not top nor bottom + stSolid = 0b1000, /// stSolid: modify the stInternal to say it should be at 100% infill + stBridge = 0b10000, /// stBridge: modify stBottom or stInternal to say it should be extruded as a bridge + stVoid = 0b100000 /// stVoid: modify stInternal to say it should be at 0% infill }; +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;} class Surface { @@ -37,6 +44,7 @@ class Surface bool is_solid() const; bool is_external() const; bool is_internal() const; + bool is_top() const; bool is_bottom() const; bool is_bridge() const; }; diff --git a/xs/src/libslic3r/SurfaceCollection.cpp b/xs/src/libslic3r/SurfaceCollection.cpp index 1fb15d023..8d9a01744 100644 --- a/xs/src/libslic3r/SurfaceCollection.cpp +++ b/xs/src/libslic3r/SurfaceCollection.cpp @@ -93,24 +93,26 @@ template bool SurfaceCollection::any_bottom_contains(const Polyline &i SurfacesPtr SurfaceCollection::filter_by_type(std::initializer_list types) { - size_t n {0}; - for (const auto& t : types) - n |= t; SurfacesPtr ss; - for (auto& s : this->surfaces) - if ((s.surface_type & n) == s.surface_type) ss.push_back(&s); + for (Surface& s : this->surfaces) + for (const SurfaceType& t : types) + if (s.surface_type == t) { + ss.push_back(&s); + break; + } return ss; } SurfacesConstPtr SurfaceCollection::filter_by_type(std::initializer_list types) const { - size_t n {0}; - for (const auto& t : types) - n |= t; SurfacesConstPtr ss; - for (auto& s : this->surfaces) - if ((s.surface_type & n) == s.surface_type) ss.push_back(&s); + for (const Surface& s : this->surfaces) + for (const SurfaceType& t : types) + if (s.surface_type == t) { + ss.push_back(&s); + break; + } return ss; } @@ -200,12 +202,23 @@ SurfaceCollection::keep_type(const SurfaceType type) void SurfaceCollection::keep_types(const SurfaceType *types, size_t ntypes) { - size_t n {0}; - for (size_t i = 0; i < ntypes; ++i) - n |= types[i]; // form bitmask. - // Use stl remove_if to remove - auto ptr = std::remove_if(surfaces.begin(), surfaces.end(),[n] (const Surface& s) { return (s.surface_type & n) != s.surface_type; }); - surfaces.erase(ptr, surfaces.cend()); + size_t j = 0; + for (size_t i = 0; i < surfaces.size(); ++ i) { + bool keep = false; + for (int k = 0; k < ntypes; ++ k) { + if (surfaces[i].surface_type == types[k]) { + keep = true; + break; + } + } + if (keep) { + if (j < i) + std::swap(surfaces[i], surfaces[j]); + ++ j; + } + } + if (j < surfaces.size()) + surfaces.erase(surfaces.begin() + j, surfaces.end()); } void diff --git a/xs/xsp/Surface.xsp b/xs/xsp/Surface.xsp index 021a8b7e4..76cd20644 100644 --- a/xs/xsp/Surface.xsp +++ b/xs/xsp/Surface.xsp @@ -19,6 +19,7 @@ bool is_external() const; bool is_internal() const; bool is_bottom() const; + bool is_top() const; bool is_bridge() const; %{ @@ -104,11 +105,10 @@ _constant() ALIAS: S_TYPE_TOP = stTop S_TYPE_BOTTOM = stBottom - S_TYPE_BOTTOMBRIDGE = stBottomBridge S_TYPE_INTERNAL = stInternal - S_TYPE_INTERNALSOLID = stInternalSolid - S_TYPE_INTERNALBRIDGE = stInternalBridge - S_TYPE_INTERNALVOID = stInternalVoid + S_TYPE_SOLID = stSolid + S_TYPE_BRIDGE = stBridge + S_TYPE_VOID = stVoid PROTOTYPE: CODE: RETVAL = ix;