Reverted the perimeter generator to not save the perimeter areas.
These could be calculated from the fill areas if needed. On the other side, the non-classified (non-split) fill areas are stored now for use in the "ensure vertical wall thickness" feature, also the non-split fill areas are re-used when recalculating the infills. This is safer than trying to stitch the fill region together from the classified fragments. Modified the "ensure vertical wall thickness" feature to use the non-split fill areas instead of perimeter areas for the calculation of non-supported regions. This is cheaper as the fill areas contain roughly half the edges.
This commit is contained in:
parent
2085a482c7
commit
79f5a16536
12 changed files with 94 additions and 116 deletions
|
@ -259,7 +259,7 @@ sub slice {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# merge all regions' slices to get islands
|
# Merge all regions' slices to get islands, chain them by a shortest path.
|
||||||
$layer->make_slices;
|
$layer->make_slices;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -367,6 +367,9 @@ sub _slice_region {
|
||||||
return $mesh->slice($z);
|
return $mesh->slice($z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# 1) Merges typed region slices into stInternal type.
|
||||||
|
# 2) Increases an "extra perimeters" counter at region slices where needed.
|
||||||
|
# 3) Generates perimeters, gap fills and fill regions (fill regions of type stInternal).
|
||||||
sub make_perimeters {
|
sub make_perimeters {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
|
|
||||||
|
@ -377,7 +380,8 @@ sub make_perimeters {
|
||||||
$self->set_step_started(STEP_PERIMETERS);
|
$self->set_step_started(STEP_PERIMETERS);
|
||||||
$self->print->status_cb->(20, "Generating perimeters");
|
$self->print->status_cb->(20, "Generating perimeters");
|
||||||
|
|
||||||
# merge slices if they were split into types
|
# Merge region slices if they were split into types.
|
||||||
|
# FIXME this is using a safety offset, so the region slices will be slightly bigger with each iteration.
|
||||||
if ($self->typed_slices) {
|
if ($self->typed_slices) {
|
||||||
$_->merge_slices for @{$self->layers};
|
$_->merge_slices for @{$self->layers};
|
||||||
$self->set_typed_slices(0);
|
$self->set_typed_slices(0);
|
||||||
|
@ -487,11 +491,12 @@ sub prepare_infill {
|
||||||
$self->set_step_started(STEP_PREPARE_INFILL);
|
$self->set_step_started(STEP_PREPARE_INFILL);
|
||||||
$self->print->status_cb->(30, "Preparing infill");
|
$self->print->status_cb->(30, "Preparing infill");
|
||||||
|
|
||||||
# this will assign a type (top/bottom/internal) to $layerm->slices
|
# This will assign a type (top/bottom/internal) to $layerm->slices.
|
||||||
# and transform $layerm->fill_surfaces from expolygon
|
# Then the classifcation of $layerm->slices is transfered onto
|
||||||
# to typed top/bottom/internal surfaces;
|
# the $layerm->fill_surfaces by clipping $layerm->fill_surfaces
|
||||||
|
# by the cummulative area of the previous $layerm->fill_surfaces.
|
||||||
$self->detect_surfaces_type;
|
$self->detect_surfaces_type;
|
||||||
# Mark the object to have the slices classified (typed, which also means they are split based on whether they are supported, bridging, top layers etc.)
|
# Mark the object to have the region slices classified (typed, which also means they are split based on whether they are supported, bridging, top layers etc.)
|
||||||
$self->set_typed_slices(1);
|
$self->set_typed_slices(1);
|
||||||
|
|
||||||
# Decide what surfaces are to be filled.
|
# Decide what surfaces are to be filled.
|
||||||
|
@ -615,6 +620,7 @@ sub infill {
|
||||||
);
|
);
|
||||||
|
|
||||||
### we could free memory now, but this would make this step not idempotent
|
### we could free memory now, but this would make this step not idempotent
|
||||||
|
### Vojtech: Cannot release the fill_surfaces, they are used by the support generator.
|
||||||
### $_->fill_surfaces->clear for map @{$_->regions}, @{$object->layers};
|
### $_->fill_surfaces->clear for map @{$_->regions}, @{$object->layers};
|
||||||
|
|
||||||
$self->set_step_done(STEP_INFILL);
|
$self->set_step_done(STEP_INFILL);
|
||||||
|
|
|
@ -34,7 +34,7 @@ use Slic3r::Test;
|
||||||
expolygon => $_,
|
expolygon => $_,
|
||||||
)) for @$expolygons;
|
)) for @$expolygons;
|
||||||
|
|
||||||
my ($region_config, $object_config, $print_config, $loops, $gap_fill, $perimeter_surfaces, $fill_surfaces);
|
my ($region_config, $object_config, $print_config, $loops, $gap_fill, $fill_surfaces);
|
||||||
my $g = Slic3r::Layer::PerimeterGenerator->new(
|
my $g = Slic3r::Layer::PerimeterGenerator->new(
|
||||||
# input:
|
# input:
|
||||||
$slices,
|
$slices,
|
||||||
|
@ -47,7 +47,6 @@ use Slic3r::Test;
|
||||||
# output:
|
# output:
|
||||||
($loops = Slic3r::ExtrusionPath::Collection->new),
|
($loops = Slic3r::ExtrusionPath::Collection->new),
|
||||||
($gap_fill = Slic3r::ExtrusionPath::Collection->new),
|
($gap_fill = Slic3r::ExtrusionPath::Collection->new),
|
||||||
($perimeter_surfaces = Slic3r::Surface::Collection->new),
|
|
||||||
($fill_surfaces = Slic3r::Surface::Collection->new),
|
($fill_surfaces = Slic3r::Surface::Collection->new),
|
||||||
);
|
);
|
||||||
$g->config->apply_dynamic($config);
|
$g->config->apply_dynamic($config);
|
||||||
|
|
|
@ -264,7 +264,7 @@ bool GCodePressureEqualizer::process_line(const char *line, const size_t len, GC
|
||||||
if (rate < 40.f) {
|
if (rate < 40.f) {
|
||||||
printf("Extremely low flow rate: %f. Line %d, Length: %f, extrusion: %f Old position: (%f, %f, %f), new position: (%f, %f, %f)\n",
|
printf("Extremely low flow rate: %f. Line %d, Length: %f, extrusion: %f Old position: (%f, %f, %f), new position: (%f, %f, %f)\n",
|
||||||
rate,
|
rate,
|
||||||
line_idx,
|
int(line_idx),
|
||||||
sqrt(len2), sqrt((diff[3]*diff[3])/len2),
|
sqrt(len2), sqrt((diff[3]*diff[3])/len2),
|
||||||
m_current_pos[0], m_current_pos[1], m_current_pos[2],
|
m_current_pos[0], m_current_pos[1], m_current_pos[2],
|
||||||
new_pos[0], new_pos[1], new_pos[2]);
|
new_pos[0], new_pos[1], new_pos[2]);
|
||||||
|
|
|
@ -103,8 +103,7 @@ Layer::make_slices()
|
||||||
} else {
|
} else {
|
||||||
Polygons slices_p;
|
Polygons slices_p;
|
||||||
FOREACH_LAYERREGION(this, layerm) {
|
FOREACH_LAYERREGION(this, layerm) {
|
||||||
Polygons region_slices_p = (*layerm)->slices;
|
polygons_append(slices_p, to_polygons((*layerm)->slices));
|
||||||
slices_p.insert(slices_p.end(), region_slices_p.begin(), region_slices_p.end());
|
|
||||||
}
|
}
|
||||||
union_(slices_p, &slices);
|
union_(slices_p, &slices);
|
||||||
}
|
}
|
||||||
|
@ -123,9 +122,8 @@ Layer::make_slices()
|
||||||
Slic3r::Geometry::chained_path(ordering_points, order);
|
Slic3r::Geometry::chained_path(ordering_points, order);
|
||||||
|
|
||||||
// populate slices vector
|
// populate slices vector
|
||||||
for (std::vector<Points::size_type>::const_iterator it = order.begin(); it != order.end(); ++it) {
|
for (std::vector<Points::size_type>::const_iterator it = order.begin(); it != order.end(); ++it)
|
||||||
this->slices.expolygons.push_back(slices[*it]);
|
this->slices.expolygons.push_back(STDMOVE(slices[*it]));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -200,68 +198,35 @@ Layer::make_perimeters()
|
||||||
|
|
||||||
if (layerms.size() == 1) { // optimization
|
if (layerms.size() == 1) { // optimization
|
||||||
(*layerm)->fill_surfaces.surfaces.clear();
|
(*layerm)->fill_surfaces.surfaces.clear();
|
||||||
(*layerm)->perimeter_surfaces.surfaces.clear();
|
(*layerm)->make_perimeters((*layerm)->slices, &(*layerm)->fill_surfaces);
|
||||||
(*layerm)->make_perimeters((*layerm)->slices, &(*layerm)->perimeter_surfaces, &(*layerm)->fill_surfaces);
|
(*layerm)->fill_expolygons = to_expolygons((*layerm)->fill_surfaces.surfaces);
|
||||||
this->perimeter_expolygons.expolygons.clear();
|
|
||||||
for (Surfaces::const_iterator it = (*layerm)->perimeter_surfaces.surfaces.begin(); it != (*layerm)->perimeter_surfaces.surfaces.end(); ++ it)
|
|
||||||
this->perimeter_expolygons.expolygons.push_back(it->expolygon);
|
|
||||||
} else {
|
} else {
|
||||||
// group slices (surfaces) according to number of extra perimeters
|
|
||||||
std::map<unsigned short,Surfaces> slices; // extra_perimeters => [ surface, surface... ]
|
|
||||||
for (LayerRegionPtrs::iterator l = layerms.begin(); l != layerms.end(); ++l) {
|
|
||||||
for (Surfaces::iterator s = (*l)->slices.surfaces.begin(); s != (*l)->slices.surfaces.end(); ++s) {
|
|
||||||
slices[s->extra_perimeters].push_back(*s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// merge the surfaces assigned to each group
|
|
||||||
SurfaceCollection new_slices;
|
SurfaceCollection new_slices;
|
||||||
for (std::map<unsigned short,Surfaces>::const_iterator it = slices.begin(); it != slices.end(); ++it) {
|
{
|
||||||
ExPolygons expp = union_ex(it->second, true);
|
// group slices (surfaces) according to number of extra perimeters
|
||||||
for (ExPolygons::iterator ex = expp.begin(); ex != expp.end(); ++ex) {
|
std::map<unsigned short,Surfaces> slices; // extra_perimeters => [ surface, surface... ]
|
||||||
Surface s = it->second.front(); // clone type and extra_perimeters
|
for (LayerRegionPtrs::iterator l = layerms.begin(); l != layerms.end(); ++l) {
|
||||||
s.expolygon = *ex;
|
for (Surfaces::iterator s = (*l)->slices.surfaces.begin(); s != (*l)->slices.surfaces.end(); ++s) {
|
||||||
new_slices.surfaces.push_back(s);
|
slices[s->extra_perimeters].push_back(*s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
// merge the surfaces assigned to each group
|
||||||
|
for (std::map<unsigned short,Surfaces>::const_iterator it = slices.begin(); it != slices.end(); ++it)
|
||||||
|
surfaces_append(new_slices.surfaces, union_ex(it->second, true), it->second.front());
|
||||||
}
|
}
|
||||||
|
|
||||||
// make perimeters
|
// make perimeters
|
||||||
SurfaceCollection perimeter_surfaces;
|
|
||||||
SurfaceCollection fill_surfaces;
|
SurfaceCollection fill_surfaces;
|
||||||
(*layerm)->make_perimeters(new_slices, &perimeter_surfaces, &fill_surfaces);
|
(*layerm)->make_perimeters(new_slices, &fill_surfaces);
|
||||||
// Copy the perimeter surfaces to the layer's surfaces before splitting them into the regions.
|
|
||||||
this->perimeter_expolygons.expolygons.clear();
|
|
||||||
for (Surfaces::const_iterator it = perimeter_surfaces.surfaces.begin(); it != perimeter_surfaces.surfaces.end(); ++ it)
|
|
||||||
this->perimeter_expolygons.expolygons.push_back(it->expolygon);
|
|
||||||
|
|
||||||
// assign fill_surfaces to each layer
|
// assign fill_surfaces to each layer
|
||||||
if (!fill_surfaces.surfaces.empty()) {
|
if (!fill_surfaces.surfaces.empty()) {
|
||||||
for (LayerRegionPtrs::iterator l = layerms.begin(); l != layerms.end(); ++l) {
|
for (LayerRegionPtrs::iterator l = layerms.begin(); l != layerms.end(); ++l) {
|
||||||
// Separate the fill surfaces.
|
// Separate the fill surfaces.
|
||||||
ExPolygons expp = intersection_ex(
|
ExPolygons expp = intersection_ex(to_polygons(fill_surfaces), (*l)->slices);
|
||||||
fill_surfaces,
|
(*l)->fill_expolygons = expp;
|
||||||
(*l)->slices
|
|
||||||
);
|
|
||||||
(*l)->fill_surfaces.surfaces.clear();
|
(*l)->fill_surfaces.surfaces.clear();
|
||||||
|
surfaces_append((*l)->fill_surfaces.surfaces, STDMOVE(expp), fill_surfaces.surfaces.front());
|
||||||
for (ExPolygons::iterator ex = expp.begin(); ex != expp.end(); ++ex) {
|
|
||||||
Surface s = fill_surfaces.surfaces.front(); // clone type and extra_perimeters
|
|
||||||
s.expolygon = *ex;
|
|
||||||
(*l)->fill_surfaces.surfaces.push_back(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Separate the perimeter surfaces.
|
|
||||||
expp = intersection_ex(
|
|
||||||
perimeter_surfaces,
|
|
||||||
(*l)->slices
|
|
||||||
);
|
|
||||||
(*l)->perimeter_surfaces.surfaces.clear();
|
|
||||||
|
|
||||||
for (ExPolygons::iterator ex = expp.begin(); ex != expp.end(); ++ex) {
|
|
||||||
Surface s = fill_surfaces.surfaces.front(); // clone type and extra_perimeters
|
|
||||||
s.expolygon = *ex;
|
|
||||||
(*l)->perimeter_surfaces.surfaces.push_back(s);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,8 +36,11 @@ class LayerRegion
|
||||||
// collection of extrusion paths/loops filling gaps
|
// collection of extrusion paths/loops filling gaps
|
||||||
ExtrusionEntityCollection thin_fills;
|
ExtrusionEntityCollection thin_fills;
|
||||||
|
|
||||||
|
// Unspecified fill polygons, used for overhang detection ("ensure vertical wall thickness feature")
|
||||||
|
// and for re-starting of infills.
|
||||||
|
ExPolygons fill_expolygons;
|
||||||
// collection of surfaces for infill generation
|
// collection of surfaces for infill generation
|
||||||
SurfaceCollection fill_surfaces;
|
SurfaceCollection fill_surfaces;
|
||||||
|
|
||||||
// Collection of perimeter surfaces. This is a cached result of diff(slices, fill_surfaces).
|
// Collection of perimeter surfaces. This is a cached result of diff(slices, fill_surfaces).
|
||||||
// While not necessary, the memory consumption is meager and it speeds up calculation.
|
// While not necessary, the memory consumption is meager and it speeds up calculation.
|
||||||
|
@ -63,7 +66,7 @@ class LayerRegion
|
||||||
void merge_slices();
|
void merge_slices();
|
||||||
void slices_to_fill_surfaces_clipped();
|
void slices_to_fill_surfaces_clipped();
|
||||||
void prepare_fill_surfaces();
|
void prepare_fill_surfaces();
|
||||||
void make_perimeters(const SurfaceCollection &slices, SurfaceCollection* perimeter_surfaces, SurfaceCollection* fill_surfaces);
|
void make_perimeters(const SurfaceCollection &slices, SurfaceCollection* fill_surfaces);
|
||||||
void process_external_surfaces(const Layer* lower_layer);
|
void process_external_surfaces(const Layer* lower_layer);
|
||||||
double infill_area_threshold() const;
|
double infill_area_threshold() const;
|
||||||
|
|
||||||
|
@ -103,10 +106,9 @@ public:
|
||||||
|
|
||||||
// collection of expolygons generated by slicing the original geometry;
|
// collection of expolygons generated by slicing the original geometry;
|
||||||
// also known as 'islands' (all regions and surface types are merged here)
|
// also known as 'islands' (all regions and surface types are merged here)
|
||||||
|
// The slices are chained by the shortest traverse distance and this traversal
|
||||||
|
// order will be recovered by the G-code generator.
|
||||||
ExPolygonCollection slices;
|
ExPolygonCollection slices;
|
||||||
// Surfaces of the perimeters including their gap fill.
|
|
||||||
ExPolygonCollection perimeter_expolygons;
|
|
||||||
|
|
||||||
|
|
||||||
size_t region_count() const;
|
size_t region_count() const;
|
||||||
const LayerRegion* get_region(int idx) const { return this->regions.at(idx); }
|
const LayerRegion* get_region(int idx) const { return this->regions.at(idx); }
|
||||||
|
|
|
@ -58,7 +58,8 @@ void LayerRegion::slices_to_fill_surfaces_clipped()
|
||||||
// in place. However we're now only using its boundaries (which are invariant)
|
// in place. However we're now only using its boundaries (which are invariant)
|
||||||
// so we're safe. This guarantees idempotence of prepare_infill() also in case
|
// so we're safe. This guarantees idempotence of prepare_infill() also in case
|
||||||
// that combine_infill() turns some fill_surface into VOID surfaces.
|
// that combine_infill() turns some fill_surface into VOID surfaces.
|
||||||
Polygons fill_boundaries = to_polygons(STDMOVE(this->fill_surfaces));
|
// Polygons fill_boundaries = to_polygons(STDMOVE(this->fill_surfaces));
|
||||||
|
Polygons fill_boundaries = to_polygons(this->fill_expolygons);
|
||||||
this->fill_surfaces.surfaces.clear();
|
this->fill_surfaces.surfaces.clear();
|
||||||
for (Surfaces::const_iterator surface = this->slices.surfaces.begin(); surface != this->slices.surfaces.end(); ++ surface)
|
for (Surfaces::const_iterator surface = this->slices.surfaces.begin(); surface != this->slices.surfaces.end(); ++ surface)
|
||||||
surfaces_append(
|
surfaces_append(
|
||||||
|
@ -68,7 +69,7 @@ void LayerRegion::slices_to_fill_surfaces_clipped()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollection* perimeter_surfaces, SurfaceCollection* fill_surfaces)
|
LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollection* fill_surfaces)
|
||||||
{
|
{
|
||||||
this->perimeters.clear();
|
this->perimeters.clear();
|
||||||
this->thin_fills.clear();
|
this->thin_fills.clear();
|
||||||
|
@ -85,7 +86,6 @@ LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollection*
|
||||||
// output:
|
// output:
|
||||||
&this->perimeters,
|
&this->perimeters,
|
||||||
&this->thin_fills,
|
&this->thin_fills,
|
||||||
perimeter_surfaces,
|
|
||||||
fill_surfaces
|
fill_surfaces
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -367,15 +367,10 @@ LayerRegion::prepare_fill_surfaces()
|
||||||
|
|
||||||
// if no solid layers are requested, turn top/bottom surfaces to internal
|
// if no solid layers are requested, turn top/bottom surfaces to internal
|
||||||
if (this->region()->config.top_solid_layers == 0) {
|
if (this->region()->config.top_solid_layers == 0) {
|
||||||
for (Surfaces::iterator surface = this->fill_surfaces.surfaces.begin(); surface != this->fill_surfaces.surfaces.end(); ++surface) {
|
for (Surfaces::iterator surface = this->fill_surfaces.surfaces.begin(); surface != this->fill_surfaces.surfaces.end(); ++surface)
|
||||||
if (surface->surface_type == stTop) {
|
if (surface->surface_type == stTop)
|
||||||
if (this->layer()->object()->config.infill_only_where_needed) {
|
surface->surface_type = (this->layer()->object()->config.infill_only_where_needed) ?
|
||||||
surface->surface_type = stInternalVoid;
|
stInternalVoid : stInternal;
|
||||||
} else {
|
|
||||||
surface->surface_type = stInternal;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (this->region()->config.bottom_solid_layers == 0) {
|
if (this->region()->config.bottom_solid_layers == 0) {
|
||||||
for (Surfaces::iterator surface = this->fill_surfaces.surfaces.begin(); surface != this->fill_surfaces.surfaces.end(); ++surface) {
|
for (Surfaces::iterator surface = this->fill_surfaces.surfaces.begin(); surface != this->fill_surfaces.surfaces.end(); ++surface) {
|
||||||
|
|
|
@ -246,15 +246,6 @@ PerimeterGenerator::process()
|
||||||
if (!entities.empty())
|
if (!entities.empty())
|
||||||
this->loops->append(entities);
|
this->loops->append(entities);
|
||||||
} // for each loop of an island
|
} // for each loop of an island
|
||||||
|
|
||||||
{
|
|
||||||
//FIXME how about the gaps?
|
|
||||||
// Calculate the region of surface->expolygon covered by the perimeters and their gap fills.
|
|
||||||
// The perimeters will later be used to calculate the object skin.
|
|
||||||
ExPolygons expp = diff_ex((Polygons)surface->expolygon, last, true);
|
|
||||||
for (ExPolygons::const_iterator ex = expp.begin(); ex != expp.end(); ++ex)
|
|
||||||
this->perimeter_surfaces->surfaces.push_back(Surface(stPerimeter, *ex));
|
|
||||||
}
|
|
||||||
|
|
||||||
// fill gaps
|
// fill gaps
|
||||||
if (!gaps.empty()) {
|
if (!gaps.empty()) {
|
||||||
|
@ -322,15 +313,15 @@ PerimeterGenerator::process()
|
||||||
|
|
||||||
// collapse too narrow infill areas
|
// collapse too narrow infill areas
|
||||||
coord_t min_perimeter_infill_spacing = ispacing * (1 - INSET_OVERLAP_TOLERANCE);
|
coord_t min_perimeter_infill_spacing = ispacing * (1 - INSET_OVERLAP_TOLERANCE);
|
||||||
expp = offset2_ex(
|
|
||||||
pp,
|
|
||||||
-inset -min_perimeter_infill_spacing/2,
|
|
||||||
+min_perimeter_infill_spacing/2
|
|
||||||
);
|
|
||||||
|
|
||||||
// append infill areas to fill_surfaces
|
// append infill areas to fill_surfaces
|
||||||
for (ExPolygons::const_iterator ex = expp.begin(); ex != expp.end(); ++ex)
|
surfaces_append(
|
||||||
this->fill_surfaces->surfaces.push_back(Surface(stInternal, *ex)); // use a bogus surface type
|
this->fill_surfaces->surfaces,
|
||||||
|
offset2_ex(
|
||||||
|
pp,
|
||||||
|
-inset -min_perimeter_infill_spacing/2,
|
||||||
|
+min_perimeter_infill_spacing/2),
|
||||||
|
stInternal);
|
||||||
}
|
}
|
||||||
} // for each island
|
} // for each island
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,6 @@ public:
|
||||||
// Outputs:
|
// Outputs:
|
||||||
ExtrusionEntityCollection* loops;
|
ExtrusionEntityCollection* loops;
|
||||||
ExtrusionEntityCollection* gap_fill;
|
ExtrusionEntityCollection* gap_fill;
|
||||||
SurfaceCollection* perimeter_surfaces;
|
|
||||||
SurfaceCollection* fill_surfaces;
|
SurfaceCollection* fill_surfaces;
|
||||||
|
|
||||||
PerimeterGenerator(
|
PerimeterGenerator(
|
||||||
|
@ -68,15 +67,13 @@ public:
|
||||||
ExtrusionEntityCollection* loops,
|
ExtrusionEntityCollection* loops,
|
||||||
// Gaps without the thin walls
|
// Gaps without the thin walls
|
||||||
ExtrusionEntityCollection* gap_fill,
|
ExtrusionEntityCollection* gap_fill,
|
||||||
// Perimeters including their gap fills
|
|
||||||
SurfaceCollection* perimeter_surfaces,
|
|
||||||
// Infills without the gap fills
|
// Infills without the gap fills
|
||||||
SurfaceCollection* fill_surfaces)
|
SurfaceCollection* fill_surfaces)
|
||||||
: slices(slices), lower_slices(NULL), layer_height(layer_height),
|
: slices(slices), lower_slices(NULL), layer_height(layer_height),
|
||||||
layer_id(-1), perimeter_flow(flow), ext_perimeter_flow(flow),
|
layer_id(-1), perimeter_flow(flow), ext_perimeter_flow(flow),
|
||||||
overhang_flow(flow), solid_infill_flow(flow),
|
overhang_flow(flow), solid_infill_flow(flow),
|
||||||
config(config), object_config(object_config), print_config(print_config),
|
config(config), object_config(object_config), print_config(print_config),
|
||||||
loops(loops), gap_fill(gap_fill), perimeter_surfaces(perimeter_surfaces), fill_surfaces(fill_surfaces),
|
loops(loops), gap_fill(gap_fill), fill_surfaces(fill_surfaces),
|
||||||
_ext_mm3_per_mm(-1), _mm3_per_mm(-1), _mm3_per_mm_overhang(-1)
|
_ext_mm3_per_mm(-1), _mm3_per_mm(-1), _mm3_per_mm_overhang(-1)
|
||||||
{};
|
{};
|
||||||
void process();
|
void process();
|
||||||
|
|
|
@ -313,7 +313,7 @@ PrintObject::has_support_material() const
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function analyzes slices of a region (SurfaceCollection slices).
|
// This function analyzes slices of a region (SurfaceCollection slices).
|
||||||
// Each slice (instance of Surface) is analyzed, whether it is supported or whether it is the top surface.
|
// 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 S_TYPE_INTERNAL.
|
// 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:
|
// 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_TOP - Part of a region, which is not covered by any upper layer. This surface will be filled with a top solid infill.
|
||||||
|
@ -325,14 +325,12 @@ void PrintObject::detect_surfaces_type()
|
||||||
{
|
{
|
||||||
// Slic3r::debugf "Detecting solid surfaces...\n";
|
// Slic3r::debugf "Detecting solid surfaces...\n";
|
||||||
for (int idx_region = 0; idx_region < this->_print->regions.size(); ++ idx_region) {
|
for (int idx_region = 0; idx_region < this->_print->regions.size(); ++ idx_region) {
|
||||||
// Fill in layerm->fill_surfaces by trimming the layerm->slices by the cummulative layerm->fill_surfaces.
|
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
|
||||||
for (int idx_layer = 0; idx_layer < int(this->layer_count()); ++ idx_layer) {
|
for (int idx_layer = 0; idx_layer < int(this->layer_count()); ++ idx_layer) {
|
||||||
LayerRegion *layerm = this->layers[idx_layer]->get_region(idx_region);
|
LayerRegion *layerm = this->layers[idx_layer]->get_region(idx_region);
|
||||||
layerm->slices_to_fill_surfaces_clipped();
|
|
||||||
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
|
|
||||||
layerm->export_region_fill_surfaces_to_svg_debug("1_detect_surfaces_type-initial");
|
layerm->export_region_fill_surfaces_to_svg_debug("1_detect_surfaces_type-initial");
|
||||||
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
|
|
||||||
}
|
}
|
||||||
|
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
|
||||||
|
|
||||||
for (int idx_layer = 0; idx_layer < int(this->layer_count()); ++ idx_layer) {
|
for (int idx_layer = 0; idx_layer < int(this->layer_count()); ++ idx_layer) {
|
||||||
Layer *layer = this->layers[idx_layer];
|
Layer *layer = this->layers[idx_layer];
|
||||||
|
@ -526,6 +524,7 @@ PrintObject::discover_vertical_shells()
|
||||||
coord_t infill_line_spacing = solid_infill_flow.scaled_spacing();
|
coord_t infill_line_spacing = solid_infill_flow.scaled_spacing();
|
||||||
// Find a union of perimeters below / above this surface to guarantee a minimum shell thickness.
|
// Find a union of perimeters below / above this surface to guarantee a minimum shell thickness.
|
||||||
Polygons shell;
|
Polygons shell;
|
||||||
|
Polygons holes;
|
||||||
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
|
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
|
||||||
ExPolygons shell_ex;
|
ExPolygons shell_ex;
|
||||||
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
|
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
|
||||||
|
@ -561,16 +560,31 @@ PrintObject::discover_vertical_shells()
|
||||||
cache_top_regions[idx_layer % n_extra_top_layers].valid = false;
|
cache_top_regions[idx_layer % n_extra_top_layers].valid = false;
|
||||||
if (n_extra_bottom_layers > 0 && idx_layer > 0)
|
if (n_extra_bottom_layers > 0 && idx_layer > 0)
|
||||||
cache_bottom_regions[(idx_layer - 1) % n_extra_bottom_layers].valid = false;
|
cache_bottom_regions[(idx_layer - 1) % n_extra_bottom_layers].valid = false;
|
||||||
|
bool hole_first = true;
|
||||||
for (int n = (int)idx_layer - n_extra_bottom_layers; n <= (int)idx_layer + n_extra_top_layers; ++ n)
|
for (int n = (int)idx_layer - n_extra_bottom_layers; n <= (int)idx_layer + n_extra_top_layers; ++ n)
|
||||||
if (n >= 0 && n < (int)this->layers.size()) {
|
if (n >= 0 && n < (int)this->layers.size()) {
|
||||||
Layer &neighbor_layer = *this->layers[n];
|
Layer &neighbor_layer = *this->layers[n];
|
||||||
LayerRegion &neighbor_region = *neighbor_layer.get_region(int(idx_region));
|
LayerRegion &neighbor_region = *neighbor_layer.get_region(int(idx_region));
|
||||||
polygons_append(shell, neighbor_layer.perimeter_expolygons.expolygons);
|
Polygons newholes;
|
||||||
|
for (size_t idx_region = 0; idx_region < this->_print->regions.size(); ++ idx_region)
|
||||||
|
polygons_append(newholes, to_polygons(neighbor_layer.get_region(idx_region)->fill_expolygons));
|
||||||
|
if (hole_first) {
|
||||||
|
hole_first = false;
|
||||||
|
polygons_append(holes, STDMOVE(newholes));
|
||||||
|
}
|
||||||
|
else if (! holes.empty()) {
|
||||||
|
holes = intersection(holes, newholes);
|
||||||
|
}
|
||||||
|
size_t n_shell_old = shell.size();
|
||||||
if (n > int(idx_layer)) {
|
if (n > int(idx_layer)) {
|
||||||
// Collect top surfaces.
|
// Collect top surfaces.
|
||||||
DiscoverVerticalShellsCacheEntry &cache = cache_top_regions[n % n_extra_top_layers];
|
DiscoverVerticalShellsCacheEntry &cache = cache_top_regions[n % n_extra_top_layers];
|
||||||
if (! cache.valid) {
|
if (! cache.valid) {
|
||||||
cache.valid = true;
|
cache.valid = true;
|
||||||
|
// neighbor_region.slices contain the source top regions,
|
||||||
|
// so one would think that they encompass the top fill_surfaces. But the fill_surfaces could have been
|
||||||
|
// expanded before, therefore they may protrude out of neighbor_region.slices's top surfaces.
|
||||||
|
//FIXME one should probably use the cummulative top surfaces over all regions here.
|
||||||
cache.slices = offset(to_expolygons(neighbor_region.slices.filter_by_type(stTop)), min_perimeter_infill_spacing);
|
cache.slices = offset(to_expolygons(neighbor_region.slices.filter_by_type(stTop)), min_perimeter_infill_spacing);
|
||||||
cache.fill_surfaces = offset(to_expolygons(neighbor_region.fill_surfaces.filter_by_type(stTop)), min_perimeter_infill_spacing);
|
cache.fill_surfaces = offset(to_expolygons(neighbor_region.fill_surfaces.filter_by_type(stTop)), min_perimeter_infill_spacing);
|
||||||
}
|
}
|
||||||
|
@ -582,6 +596,7 @@ PrintObject::discover_vertical_shells()
|
||||||
DiscoverVerticalShellsCacheEntry &cache = cache_bottom_regions[n % n_extra_bottom_layers];
|
DiscoverVerticalShellsCacheEntry &cache = cache_bottom_regions[n % n_extra_bottom_layers];
|
||||||
if (! cache.valid) {
|
if (! cache.valid) {
|
||||||
cache.valid = true;
|
cache.valid = true;
|
||||||
|
//FIXME one should probably use the cummulative top surfaces over all regions here.
|
||||||
cache.slices = offset(to_expolygons(neighbor_region.slices.filter_by_types(surfaces_bottom, 2)), min_perimeter_infill_spacing);
|
cache.slices = offset(to_expolygons(neighbor_region.slices.filter_by_types(surfaces_bottom, 2)), min_perimeter_infill_spacing);
|
||||||
cache.fill_surfaces = offset(to_expolygons(neighbor_region.fill_surfaces.filter_by_types(surfaces_bottom, 2)), min_perimeter_infill_spacing);
|
cache.fill_surfaces = offset(to_expolygons(neighbor_region.fill_surfaces.filter_by_types(surfaces_bottom, 2)), min_perimeter_infill_spacing);
|
||||||
}
|
}
|
||||||
|
@ -590,7 +605,8 @@ PrintObject::discover_vertical_shells()
|
||||||
}
|
}
|
||||||
// Running the union_ using the Clipper library piece by piece is cheaper
|
// Running the union_ using the Clipper library piece by piece is cheaper
|
||||||
// than running the union_ all at once.
|
// than running the union_ all at once.
|
||||||
shell = union_(shell, false);
|
if (n_shell_old < shell.size())
|
||||||
|
shell = union_(shell, false);
|
||||||
}
|
}
|
||||||
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
|
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
|
||||||
{
|
{
|
||||||
|
@ -613,8 +629,8 @@ PrintObject::discover_vertical_shells()
|
||||||
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
|
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shell.empty())
|
//if (shell.empty())
|
||||||
continue;
|
// continue;
|
||||||
|
|
||||||
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
|
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
|
||||||
{
|
{
|
||||||
|
@ -660,6 +676,7 @@ PrintObject::discover_vertical_shells()
|
||||||
const SurfaceType surfaceTypesInternal[] = { stInternal, stInternalVoid, stInternalSolid };
|
const SurfaceType surfaceTypesInternal[] = { stInternal, stInternalVoid, stInternalSolid };
|
||||||
const Polygons polygonsInternal = to_polygons(layerm->fill_surfaces.filter_by_types(surfaceTypesInternal, 2));
|
const Polygons polygonsInternal = to_polygons(layerm->fill_surfaces.filter_by_types(surfaceTypesInternal, 2));
|
||||||
shell = intersection(shell, polygonsInternal, true);
|
shell = intersection(shell, polygonsInternal, true);
|
||||||
|
polygons_append(shell, diff(polygonsInternal, holes));
|
||||||
if (shell.empty())
|
if (shell.empty())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
|
@ -97,6 +97,15 @@ inline Polygons to_polygons(const SurfacesPtr &src)
|
||||||
return polygons;
|
return polygons;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline ExPolygons to_expolygons(const Surfaces &src)
|
||||||
|
{
|
||||||
|
ExPolygons expolygons;
|
||||||
|
expolygons.reserve(src.size());
|
||||||
|
for (Surfaces::const_iterator it = src.begin(); it != src.end(); ++it)
|
||||||
|
expolygons.push_back(it->expolygon);
|
||||||
|
return expolygons;
|
||||||
|
}
|
||||||
|
|
||||||
inline ExPolygons to_expolygons(const SurfacesPtr &src)
|
inline ExPolygons to_expolygons(const SurfacesPtr &src)
|
||||||
{
|
{
|
||||||
ExPolygons expolygons;
|
ExPolygons expolygons;
|
||||||
|
|
|
@ -32,8 +32,8 @@
|
||||||
%code%{ RETVAL = THIS->flow(role, bridge, width); %};
|
%code%{ RETVAL = THIS->flow(role, bridge, width); %};
|
||||||
void merge_slices();
|
void merge_slices();
|
||||||
void prepare_fill_surfaces();
|
void prepare_fill_surfaces();
|
||||||
void make_perimeters(SurfaceCollection* slices, SurfaceCollection* perimeter_surfaces, SurfaceCollection* fill_surfaces)
|
void make_perimeters(SurfaceCollection* slices, SurfaceCollection* fill_surfaces)
|
||||||
%code%{ THIS->make_perimeters(*slices, perimeter_surfaces, fill_surfaces); %};
|
%code%{ THIS->make_perimeters(*slices, fill_surfaces); %};
|
||||||
double infill_area_threshold();
|
double infill_area_threshold();
|
||||||
|
|
||||||
void export_region_slices_to_svg(const char *path);
|
void export_region_slices_to_svg(const char *path);
|
||||||
|
@ -80,9 +80,6 @@
|
||||||
Ref<ExPolygonCollection> slices()
|
Ref<ExPolygonCollection> slices()
|
||||||
%code%{ RETVAL = &THIS->slices; %};
|
%code%{ RETVAL = &THIS->slices; %};
|
||||||
|
|
||||||
Ref<ExPolygonCollection> perimeter_expolygons()
|
|
||||||
%code%{ RETVAL = &THIS->perimeter_expolygons; %};
|
|
||||||
|
|
||||||
int ptr()
|
int ptr()
|
||||||
%code%{ RETVAL = (int)(intptr_t)THIS; %};
|
%code%{ RETVAL = (int)(intptr_t)THIS; %};
|
||||||
|
|
||||||
|
|
|
@ -10,12 +10,12 @@
|
||||||
StaticPrintConfig* region_config, StaticPrintConfig* object_config,
|
StaticPrintConfig* region_config, StaticPrintConfig* object_config,
|
||||||
StaticPrintConfig* print_config, ExtrusionEntityCollection* loops,
|
StaticPrintConfig* print_config, ExtrusionEntityCollection* loops,
|
||||||
ExtrusionEntityCollection* gap_fill,
|
ExtrusionEntityCollection* gap_fill,
|
||||||
SurfaceCollection* perimeter_surfaces, SurfaceCollection* fill_surfaces)
|
SurfaceCollection* fill_surfaces)
|
||||||
%code{% RETVAL = new PerimeterGenerator(slices, layer_height, *flow,
|
%code{% RETVAL = new PerimeterGenerator(slices, layer_height, *flow,
|
||||||
dynamic_cast<PrintRegionConfig*>(region_config),
|
dynamic_cast<PrintRegionConfig*>(region_config),
|
||||||
dynamic_cast<PrintObjectConfig*>(object_config),
|
dynamic_cast<PrintObjectConfig*>(object_config),
|
||||||
dynamic_cast<PrintConfig*>(print_config),
|
dynamic_cast<PrintConfig*>(print_config),
|
||||||
loops, gap_fill, perimeter_surfaces, fill_surfaces); %};
|
loops, gap_fill, fill_surfaces); %};
|
||||||
~PerimeterGenerator();
|
~PerimeterGenerator();
|
||||||
|
|
||||||
void set_lower_slices(ExPolygonCollection* lower_slices)
|
void set_lower_slices(ExPolygonCollection* lower_slices)
|
||||||
|
|
Loading…
Reference in a new issue