Merge branch 'alexrj_flagssurfacetype'

Completes pr #4616
This commit is contained in:
Joseph Lenox 2018-12-02 17:00:40 -06:00
commit 802b1e1aa7
12 changed files with 107 additions and 92 deletions

View File

@ -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,

View File

@ -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 {

View File

@ -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';

View File

@ -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;
}

View File

@ -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);
}
}
}

View File

@ -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;
}

View File

@ -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<size_t>(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

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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<SurfaceType>(static_cast<uint16_t>(a) | static_cast<uint16_t>(b));}
inline SurfaceType operator&(SurfaceType a, SurfaceType b)
{return static_cast<SurfaceType>(static_cast<uint16_t>(a) & static_cast<uint16_t>(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;
};

View File

@ -93,24 +93,26 @@ template bool SurfaceCollection::any_bottom_contains<Polyline>(const Polyline &i
SurfacesPtr
SurfaceCollection::filter_by_type(std::initializer_list<SurfaceType> 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<SurfaceType> 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

View File

@ -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;