Flags for surface_type

simplify the dense_infill algo. TODO: use a flag instead of the field.

TODO: use the flags (without creating bugs)
This commit is contained in:
supermerill 2019-02-15 20:02:40 +01:00
parent b372e00464
commit 9454415e6d
16 changed files with 399 additions and 497 deletions

View File

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

View File

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

View File

@ -189,13 +189,7 @@ void Fill::fill_surface_extrusion(const Surface *surface, const FillParams &para
/// 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),

View File

@ -132,6 +132,17 @@ protected:
void connect_infill(const Polylines &infill_ordered, const ExPolygon &boundary, Polylines &polylines_out);
ExtrusionRole getRoleFromSurfaceType(const FillParams &params, 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);

View File

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

View File

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

View File

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

View File

@ -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> 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<SurfaceType, Polygons> 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;
}
}

View File

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

View File

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

View File

@ -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<size_t>(0, m_layers.size(), grain_size),
[this, &cache_top_botom_regions](const tbb::blocked_range<size_t>& 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<size_t>(0, m_layers.size(), grain_size),
[this, idx_region, &cache_top_botom_regions](const tbb::blocked_range<size_t>& 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 &region = *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<coordf_t> &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<coordf_t> &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<SurfacesPtr> 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);
}
}
}

View File

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

View File

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

View File

@ -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<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;
}
//inline bool operator==(SurfaceType a, SurfaceType b) {
// return static_cast<uint16_t>(a) ^ static_cast<uint16_t>(b) == 0;
//}
//inline bool operator!=(SurfaceType a, SurfaceType b) {
// return static_cast<uint16_t>(a) ^ static_cast<uint16_t>(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<Surface> Surfaces;

View File

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

View File

@ -20,20 +20,24 @@ public:
void simplify(double tolerance);
void group(std::vector<SurfacesPtr> *retval);
template <class T> 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 <class T> 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(); }