Visualization of fill surfaces.

This commit is contained in:
bubnikv 2016-09-26 13:56:24 +02:00
parent e0d1aa8a1a
commit 790b640521
6 changed files with 314 additions and 26 deletions

View file

@ -11,6 +11,8 @@ use Slic3r::Geometry::Clipper qw(diff diff_ex intersection intersection_ex union
use Slic3r::Print::State ':steps'; use Slic3r::Print::State ':steps';
use Slic3r::Surface ':types'; use Slic3r::Surface ':types';
# If enabled, phases of prepare_infill will be written into SVG files to an "out" directory.
our $SLIC3R_DEBUG_SLICE_PROCESSING = 0;
# TODO: lazy # TODO: lazy
sub fill_maker { sub fill_maker {
@ -492,19 +494,76 @@ sub prepare_infill {
# and transform $layerm->fill_surfaces from expolygon # and transform $layerm->fill_surfaces from expolygon
# to typed top/bottom/internal surfaces; # to typed top/bottom/internal 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.)
$self->set_typed_slices(1); $self->set_typed_slices(1);
# decide what surfaces are to be filled # Decide what surfaces are to be filled.
# Here the S_TYPE_TOP / S_TYPE_BOTTOMBRIDGE / S_TYPE_BOTTOM infill is turned to just S_TYPE_INTERNAL if zero top / bottom infill layers are configured.
# Also tiny S_TYPE_INTERNAL surfaces are turned to S_TYPE_INTERNAL_SOLID.
$_->prepare_fill_surfaces for map @{$_->regions}, @{$self->layers}; $_->prepare_fill_surfaces for map @{$_->regions}, @{$self->layers};
# this will detect bridges and reverse bridges # this will detect bridges and reverse bridges
# and rearrange top/bottom/internal surfaces # and rearrange top/bottom/internal surfaces
# It produces enlarged overlapping bridging areas.
#
# 1) S_TYPE_BOTTOMBRIDGE / S_TYPE_BOTTOM infill is grown by 3mm and clipped by the total infill area. Bridges are detected. The areas may overlap.
# 2) S_TYPE_TOP is grown by 3mm and clipped by the grown bottom areas. The areas may overlap.
# 3) Clip the internal surfaces by the grown top/bottom surfaces.
# 4) Merge surfaces with the same style. This will mostly get rid of the overlaps.
#FIXME This does not likely merge surfaces, which are supported by a material with different colors, but same properties.
$self->process_external_surfaces; $self->process_external_surfaces;
# detect which fill surfaces are near external layers # Add solid fills to ensure the shell vertical thickness.
# they will be split in internal and internal-solid surfaces $self->discover_vertical_shells;
# Debugging output.
if ($SLIC3R_DEBUG_SLICE_PROCESSING) {
for my $region_id (0 .. ($self->print->region_count-1)) {
for (my $i = 0; $i < $self->layer_count; $i++) {
my $layerm = $self->get_layer($i)->regions->[$region_id];
$layerm->export_region_slices_to_svg_debug("6_discover_vertical_shells-final");
$layerm->export_region_fill_surfaces_to_svg_debug("6_discover_vertical_shells-final");
} # for each layer
} # for each region
}
# Detect, which fill surfaces are near external layers.
# They will be split in internal and internal-solid surfaces.
# The purpose is to add a configurable number of solid layers to support the TOP surfaces
# and to add a configurable number of solid layers above the BOTTOM / BOTTOMBRIDGE surfaces
# to close these surfaces reliably.
#FIXME Vojtech: Is this a good place to add supporting infills below sloping perimeters?
$self->discover_horizontal_shells; $self->discover_horizontal_shells;
if ($SLIC3R_DEBUG_SLICE_PROCESSING) {
# Debugging output.
for my $region_id (0 .. ($self->print->region_count-1)) {
for (my $i = 0; $i < $self->layer_count; $i++) {
my $layerm = $self->get_layer($i)->regions->[$region_id];
$layerm->export_region_slices_to_svg_debug("7_discover_horizontal_shells-final");
$layerm->export_region_fill_surfaces_to_svg_debug("7_discover_horizontal_shells-final");
} # for each layer
} # for each region
}
# Only active if config->infill_only_where_needed. This step trims the sparse infill,
# so it acts as an internal support. It maintains all other infill types intact.
# Here the internal surfaces and perimeters have to be supported by the sparse infill.
#FIXME The surfaces are supported by a sparse infill, but the sparse infill is only as large as the area to support.
# Likely the sparse infill will not be anchored correctly, so it will not work as intended.
# Also one wishes the perimeters to be supported by a full infill.
$self->clip_fill_surfaces; $self->clip_fill_surfaces;
if ($SLIC3R_DEBUG_SLICE_PROCESSING) {
# Debugging output.
for my $region_id (0 .. ($self->print->region_count-1)) {
for (my $i = 0; $i < $self->layer_count; $i++) {
my $layerm = $self->get_layer($i)->regions->[$region_id];
$layerm->export_region_slices_to_svg_debug("8_clip_surfaces-final");
$layerm->export_region_fill_surfaces_to_svg_debug("8_clip_surfaces-final");
} # for each layer
} # for each region
}
# the following step needs to be done before combination because it may need # the following step needs to be done before combination because it may need
# to remove only half of the combined infill # to remove only half of the combined infill
@ -513,6 +572,22 @@ sub prepare_infill {
# combine fill surfaces to honor the "infill every N layers" option # combine fill surfaces to honor the "infill every N layers" option
$self->combine_infill; $self->combine_infill;
# Debugging output.
if ($SLIC3R_DEBUG_SLICE_PROCESSING) {
for my $region_id (0 .. ($self->print->region_count-1)) {
for (my $i = 0; $i < $self->layer_count; $i++) {
my $layerm = $self->get_layer($i)->regions->[$region_id];
$layerm->export_region_slices_to_svg_debug("9_prepare_infill-final");
$layerm->export_region_fill_surfaces_to_svg_debug("9_prepare_infill-final");
} # for each layer
} # for each region
for (my $i = 0; $i < $self->layer_count; $i++) {
my $layer = $self->get_layer($i);
$layer->export_region_slices_to_svg_debug("9_prepare_infill-final");
$layer->export_region_fill_surfaces_to_svg_debug("9_prepare_infill-final");
} # for each layer
}
$self->set_step_done(STEP_PREPARE_INFILL); $self->set_step_done(STEP_PREPARE_INFILL);
} }
@ -591,6 +666,15 @@ sub _support_material {
); );
} }
# 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.
# Initially all slices are of type S_TYPE_INTERNAL.
# Slices are compared against the top / bottom slices and regions and classified to the following groups:
# S_TYPE_TOP - Part of a region, which is not covered by any upper layer. This surface will be filled with a top solid infill.
# S_TYPE_BOTTOMBRIDGE - Part of a region, which is not fully supported, but it hangs in the air, or it hangs losely on a support or a raft.
# S_TYPE_BOTTOM - Part of a region, which is not supported by the same region, but it is supported either by another region, or by a soluble interface layer.
# S_TYPE_INTERNAL - Part of a region, which is supported by the same region type.
# If a part of a region is of S_TYPE_BOTTOM and S_TYPE_TOP, the S_TYPE_BOTTOM wins.
sub detect_surfaces_type { sub detect_surfaces_type {
my $self = shift; my $self = shift;
Slic3r::debugf "Detecting solid surfaces...\n"; Slic3r::debugf "Detecting solid surfaces...\n";
@ -623,6 +707,8 @@ sub detect_surfaces_type {
# of current layer and upper one) # of current layer and upper one)
my @top = (); my @top = ();
if ($upper_layer) { if ($upper_layer) {
# Config value $self->config->interface_shells is true, if a support is separated from the object
# by a soluble material (for example a PVA plastic).
my $upper_slices = $self->config->interface_shells my $upper_slices = $self->config->interface_shells
? [ map $_->expolygon, @{$upper_layer->regions->[$region_id]->slices} ] ? [ map $_->expolygon, @{$upper_layer->regions->[$region_id]->slices} ]
: $upper_layer->slices; : $upper_layer->slices;
@ -643,14 +729,15 @@ sub detect_surfaces_type {
# of current layer and lower one) # of current layer and lower one)
my @bottom = (); my @bottom = ();
if ($lower_layer) { if ($lower_layer) {
# any surface lying on the void is a true bottom bridge # Any surface lying on the void is a true bottom bridge (an overhang)
push @bottom, $difference->( push @bottom, $difference->(
[ map $_->expolygon, @{$layerm->slices} ], [ map $_->expolygon, @{$layerm->slices} ],
$lower_layer->slices, $lower_layer->slices,
S_TYPE_BOTTOMBRIDGE, S_TYPE_BOTTOMBRIDGE,
); );
# if we have soluble support material, don't bridge # If we have soluble support material, don't bridge. The overhang will be squished against a soluble layer separating
# the support from the print.
if ($self->config->support_material && $self->config->support_material_contact_distance == 0) { if ($self->config->support_material && $self->config->support_material_contact_distance == 0) {
$_->surface_type(S_TYPE_BOTTOM) for @bottom; $_->surface_type(S_TYPE_BOTTOM) for @bottom;
} }
@ -707,7 +794,11 @@ sub detect_surfaces_type {
Slic3r::debugf " layer %d has %d bottom, %d top and %d internal surfaces\n", Slic3r::debugf " layer %d has %d bottom, %d top and %d internal surfaces\n",
$layerm->layer->id, scalar(@bottom), scalar(@top), scalar(@internal) if $Slic3r::debug; $layerm->layer->id, scalar(@bottom), scalar(@top), scalar(@internal) if $Slic3r::debug;
}
if ($SLIC3R_DEBUG_SLICE_PROCESSING) {
$layerm->export_region_slices_to_svg_debug("detect_surfaces_type-final");
}
} # for each layer of a region
# clip surfaces to the fill boundaries # clip surfaces to the fill boundaries
foreach my $layer (@{$self->layers}) { foreach my $layer (@{$self->layers}) {
@ -728,8 +819,12 @@ sub detect_surfaces_type {
for map Slic3r::Surface->new(expolygon => $_, surface_type => $surface->surface_type), for map Slic3r::Surface->new(expolygon => $_, surface_type => $surface->surface_type),
@$intersection; @$intersection;
} }
}
} if ($SLIC3R_DEBUG_SLICE_PROCESSING) {
$layerm->export_region_fill_surfaces_to_svg_debug("1_detect_surfaces_type-final");
}
} # for each layer of a region
} # for each $self->print->region_count
} }
# Idempotence of this method is guaranteed by the fact that we don't remove things from # Idempotence of this method is guaranteed by the fact that we don't remove things from
@ -771,6 +866,8 @@ sub clip_fill_surfaces {
); );
# only consider perimeter areas that are at least one extrusion width thick # only consider perimeter areas that are at least one extrusion width thick
#FIXME Offset2 eats out from both sides, while the perimeters are create outside in.
#Should the $pw not be half of the current value?
my $pw = min(map $_->flow(FLOW_ROLE_PERIMETER)->scaled_width, @{$layer->regions}); my $pw = min(map $_->flow(FLOW_ROLE_PERIMETER)->scaled_width, @{$layer->regions});
$perimeters = offset2($perimeters, -$pw, +$pw); $perimeters = offset2($perimeters, -$pw, +$pw);
@ -829,6 +926,10 @@ sub clip_fill_surfaces {
$layerm->fill_surfaces->clear; $layerm->fill_surfaces->clear;
$layerm->fill_surfaces->append($_) for (@new, @other); $layerm->fill_surfaces->append($_) for (@new, @other);
if ($SLIC3R_DEBUG_SLICE_PROCESSING) {
$layerm->export_region_fill_surfaces_to_svg_debug("6_clip_fill_surfaces");
}
} }
} }
} }
@ -844,6 +945,8 @@ sub discover_horizontal_shells {
if ($layerm->region->config->solid_infill_every_layers && $layerm->region->config->fill_density > 0 if ($layerm->region->config->solid_infill_every_layers && $layerm->region->config->fill_density > 0
&& ($i % $layerm->region->config->solid_infill_every_layers) == 0) { && ($i % $layerm->region->config->solid_infill_every_layers) == 0) {
# This is the layer to put the sparse infill in. Mark S_TYPE_INTERNAL surfaces as S_TYPE_INTERNALSOLID or S_TYPE_INTERNALBRIDGE.
# If the sparse infill is not active, the internal surfaces are of type S_TYPE_INTERNAL.
my $type = $layerm->region->config->fill_density == 100 ? S_TYPE_INTERNALSOLID : S_TYPE_INTERNALBRIDGE; my $type = $layerm->region->config->fill_density == 100 ? S_TYPE_INTERNALSOLID : S_TYPE_INTERNALBRIDGE;
$_->surface_type($type) for @{$layerm->fill_surfaces->filter_by_type(S_TYPE_INTERNAL)}; $_->surface_type($type) for @{$layerm->fill_surfaces->filter_by_type(S_TYPE_INTERNAL)};
} }
@ -869,15 +972,18 @@ sub discover_horizontal_shells {
? $layerm->region->config->top_solid_layers ? $layerm->region->config->top_solid_layers
: $layerm->region->config->bottom_solid_layers; : $layerm->region->config->bottom_solid_layers;
NEIGHBOR: for (my $n = ($type == S_TYPE_TOP) ? $i-1 : $i+1; NEIGHBOR: for (my $n = ($type == S_TYPE_TOP) ? $i-1 : $i+1;
abs($n - $i) <= $solid_layers-1; abs($n - $i) < $solid_layers;
($type == S_TYPE_TOP) ? $n-- : $n++) { ($type == S_TYPE_TOP) ? $n-- : $n++) {
next if $n < 0 || $n >= $self->layer_count; next if $n < 0 || $n >= $self->layer_count;
Slic3r::debugf " looking for neighbors on layer %d...\n", $n; Slic3r::debugf " looking for neighbors on layer %d...\n", $n;
# Reference to the lower layer of a TOP surface, or an upper layer of a BOTTOM surface.
my $neighbor_layerm = $self->get_layer($n)->regions->[$region_id]; my $neighbor_layerm = $self->get_layer($n)->regions->[$region_id];
# Reference to the neighbour fill surfaces.
my $neighbor_fill_surfaces = $neighbor_layerm->fill_surfaces; my $neighbor_fill_surfaces = $neighbor_layerm->fill_surfaces;
my @neighbor_fill_surfaces = map $_->clone, @$neighbor_fill_surfaces; # clone because we will use these surfaces even after clearing the collection # Clone because we will use these surfaces even after clearing the collection.
my @neighbor_fill_surfaces = map $_->clone, @$neighbor_fill_surfaces;
# find intersection between neighbor and current layer's surfaces # find intersection between neighbor and current layer's surfaces
# intersections have contours and holes # intersections have contours and holes
@ -888,6 +994,7 @@ sub discover_horizontal_shells {
# shells to be generated in the base but not in the walls (where there are many # shells to be generated in the base but not in the walls (where there are many
# narrow bottom surfaces): reassigning $solid will consider the 'shadow' of the # narrow bottom surfaces): reassigning $solid will consider the 'shadow' of the
# upper perimeter as an obstacle and shell will not be propagated to more upper layers # upper perimeter as an obstacle and shell will not be propagated to more upper layers
#FIXME How does it work for S_TYPE_INTERNALBRIDGE? This is set for sparse infill. Likely this does not work.
my $new_internal_solid = $solid = intersection( my $new_internal_solid = $solid = intersection(
$solid, $solid,
[ map $_->p, grep { ($_->surface_type == S_TYPE_INTERNAL) || ($_->surface_type == S_TYPE_INTERNALSOLID) } @neighbor_fill_surfaces ], [ map $_->p, grep { ($_->surface_type == S_TYPE_INTERNAL) || ($_->surface_type == S_TYPE_INTERNALSOLID) } @neighbor_fill_surfaces ],
@ -914,7 +1021,7 @@ sub discover_horizontal_shells {
# make sure the new internal solid is wide enough, as it might get collapsed # make sure the new internal solid is wide enough, as it might get collapsed
# when spacing is added in Fill.pm # when spacing is added in Fill.pm
{ if (0) {
my $margin = 3 * $layerm->flow(FLOW_ROLE_SOLID_INFILL)->scaled_width; # require at least this size my $margin = 3 * $layerm->flow(FLOW_ROLE_SOLID_INFILL)->scaled_width; # require at least this size
# we use a higher miterLimit here to handle areas with acute angles # we use a higher miterLimit here to handle areas with acute angles
# in those cases, the default miterLimit would cut the corner and we'd # in those cases, the default miterLimit would cut the corner and we'd
@ -984,12 +1091,23 @@ sub discover_horizontal_shells {
for map $s->[0]->clone(expolygon => $_), @$solid_surfaces; for map $s->[0]->clone(expolygon => $_), @$solid_surfaces;
} }
} }
} } # foreach my $type (S_TYPE_TOP, S_TYPE_BOTTOM, S_TYPE_BOTTOMBRIDGE)
} } # for each layer
} # for each region
# Debugging output.
if ($SLIC3R_DEBUG_SLICE_PROCESSING) {
for my $region_id (0 .. ($self->print->region_count-1)) {
for (my $i = 0; $i < $self->layer_count; $i++) {
my $layerm = $self->get_layer($i)->regions->[$region_id];
$layerm->export_region_slices_to_svg_debug("5_discover_horizontal_shells");
$layerm->export_region_fill_surfaces_to_svg_debug("5_discover_horizontal_shells");
} # for each layer
} # for each region
} }
} }
# combine fill surfaces across layers # combine fill surfaces across layers to honor the "infill every N layers" option
# Idempotence of this method is guaranteed by the fact that we don't remove things from # Idempotence of this method is guaranteed by the fact that we don't remove things from
# fill_surfaces but we only turn them into VOID surfaces, thus preserving the boundaries. # fill_surfaces but we only turn them into VOID surfaces, thus preserving the boundaries.
sub combine_infill { sub combine_infill {

View file

@ -134,7 +134,7 @@ namespace boost { namespace polygon {
return t.holes.end(); return t.holes.end();
} }
static inline unsigned int size_holes(const ExPolygon& t) { static inline unsigned int size_holes(const ExPolygon& t) {
return t.holes.size(); return (int)t.holes.size();
} }
}; };

View file

@ -138,6 +138,7 @@ class PrintObject
bool has_support_material() const; bool has_support_material() const;
void process_external_surfaces(); void process_external_surfaces();
void discover_vertical_shells();
void bridge_over_infill(); void bridge_over_infill();
private: private:

View file

@ -2,6 +2,7 @@
#include "BoundingBox.hpp" #include "BoundingBox.hpp"
#include "ClipperUtils.hpp" #include "ClipperUtils.hpp"
#include "Geometry.hpp" #include "Geometry.hpp"
#include "SVG.hpp"
namespace Slic3r { namespace Slic3r {
@ -358,6 +359,167 @@ PrintObject::process_external_surfaces()
} }
} }
void
PrintObject::discover_vertical_shells()
{
for (size_t idx_region = 0; idx_region < this->_print->regions.size(); ++ idx_region) {
for (size_t idx_layer = 0; idx_layer < this->layers.size(); ++ idx_layer) {
Layer* layer = this->layers[idx_layer];
LayerRegion* layerm = layer->get_region(idx_region);
// Find a union of perimeters below / above this surface to guarantee a minimum shell thickness.
Polygons shell;
ExPolygons shell_ex;
if (1)
{
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
{
static size_t idx = 0;
char path_cummulative[2048];
sprintf(path_cummulative, "out\\discover_vertical_shells-perimeters-before-union-run%d.svg", idx);
SVG svg_cummulative(path_cummulative, this->bounding_box());
for (int n = (int)idx_layer - layerm->region()->config.bottom_solid_layers + 1; n < (int)idx_layer + layerm->region()->config.top_solid_layers; ++ n) {
if (n < 0 || n >= (int)this->layers.size())
continue;
ExPolygons &expolys = this->layers[n]->perimeter_expolygons;
for (size_t i = 0; i < expolys.size(); ++ i) {
char path[2048];
sprintf(path, "out\\discover_vertical_shells-perimeters-before-union-run%d-layer%d-expoly%d.svg", idx, n, i);
SVG svg(path, get_extents(expolys[i]));
svg.draw(expolys[i]);
svg.draw_outline(expolys[i].contour, "black", scale_(0.05));
svg.draw_outline(expolys[i].holes, "blue", scale_(0.05));
svg.Close();
svg_cummulative.draw(expolys[i]);
svg_cummulative.draw_outline(expolys[i].contour, "black", scale_(0.05));
svg_cummulative.draw_outline(expolys[i].holes, "blue", scale_(0.05));
}
}
++ idx;
}
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
for (int n = (int)idx_layer - layerm->region()->config.bottom_solid_layers + 1; n < (int)idx_layer + layerm->region()->config.top_solid_layers; ++ n) {
if (n < 0 || n >= (int)this->layers.size())
continue;
ExPolygons &expolys = this->layers[n]->perimeter_expolygons;
for (size_t i = 0; i < expolys.size(); ++ i) {
shell.push_back(expolys[i].contour);
shell.insert(shell.end(), expolys[i].holes.begin(), expolys[i].holes.end());
}
}
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
{
static size_t idx = 0;
char path[2048];
sprintf(path, "out\\discover_vertical_shells-perimeters-before-union-%d.svg", idx ++);
SVG svg(path, get_extents(shell));
svg.draw(shell);
svg.draw_outline(shell, "black", scale_(0.05));
svg.Close();
}
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
shell = union_(shell, true);
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
shell_ex = union_ex(shell, true);
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
}
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
{
static size_t idx = 0;
char path[2048];
sprintf(path, "out\\discover_vertical_shells-perimeters-after-union-%d.svg", idx ++);
SVG svg(path, get_extents(shell));
svg.draw(shell_ex);
svg.draw_outline(shell_ex, "black", "blue", scale_(0.05));
svg.Close();
}
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
{
static size_t idx = 0;
char path[2048];
sprintf(path, "out\\discover_vertical_shells-internal-wshell-%d.svg", idx ++);
SVG svg(path, get_extents(shell));
svg.draw(layerm->fill_surfaces.filter_by_type(stInternal), "yellow", 0.5);
svg.draw_outline(layerm->fill_surfaces.filter_by_type(stInternal), "black", "blue", scale_(0.05));
svg.draw(shell_ex, "blue", 0.5);
svg.draw_outline(shell_ex, "black", "blue", scale_(0.05));
svg.Close();
}
{
static size_t idx = 0;
char path[2048];
sprintf(path, "out\\discover_vertical_shells-internalvoid-wshell-%d.svg", idx ++);
SVG svg(path, get_extents(shell));
svg.draw(layerm->fill_surfaces.filter_by_type(stInternalVoid), "yellow", 0.5);
svg.draw_outline(layerm->fill_surfaces.filter_by_type(stInternalVoid), "black", "blue", scale_(0.05));
svg.draw(shell_ex, "blue", 0.5);
svg.draw_outline(shell_ex, "black", "blue", scale_(0.05));
svg.Close();
}
{
static size_t idx = 0;
char path[2048];
sprintf(path, "out\\discover_vertical_shells-internalvoid-wshell-%d.svg", idx ++);
SVG svg(path, get_extents(shell));
svg.draw(layerm->fill_surfaces.filter_by_type(stInternalVoid), "yellow", 0.5);
svg.draw_outline(layerm->fill_surfaces.filter_by_type(stInternalVoid), "black", "blue", scale_(0.05));
svg.draw(shell_ex, "blue", 0.5);
svg.draw_outline(shell_ex, "black", "blue", scale_(0.05));
svg.Close();
}
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
// Trim the internal & internalvoid by the $shell.
Slic3r::ExPolygons new_internal = diff_ex(
to_polygons(layerm->fill_surfaces.filter_by_type(stInternal)),
shell,
false
);
Slic3r::ExPolygons new_internal_void = diff_ex(
to_polygons(layerm->fill_surfaces.filter_by_type(stInternalVoid)),
shell,
false
);
// Add shells tstInternalVoido internal & internalvoid.
const SurfaceType surfaceTypesInternal[] = { stInternal, stInternalVoid };
Slic3r::ExPolygons new_internal_solid = intersection_ex(
to_polygons(layerm->fill_surfaces.filter_by_types(surfaceTypesInternal, 2)),
shell,
true
);
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
{
static size_t idx = 0;
char path[2048];
sprintf(path, "out\\discover_vertical_shells-new_internal-%d.svg", idx);
SVG::export_expolygons(path, get_extents(shell), new_internal, "black", "blue", scale_(0.05));
sprintf(path, "out\\discover_vertical_shells-new_internal_void-%d.svg", idx);
SVG::export_expolygons(path, get_extents(shell), new_internal_void, "black", "blue", scale_(0.05));
sprintf(path, "out\\discover_vertical_shells-new_internal_solid-%d.svg", idx);
SVG::export_expolygons(path, get_extents(shell), new_internal_solid, "black", "blue", scale_(0.05));
++ idx;
}
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
// Assign resulting internal surfaces to layer.
const SurfaceType surfaceTypesKeep[] = { stTop, stBottom, stBottomBridge, stInternalSolid };
layerm->fill_surfaces.keep_types(surfaceTypesKeep, sizeof(surfaceTypesKeep)/sizeof(SurfaceType));
layerm->fill_surfaces.append(stInternal , new_internal);
layerm->fill_surfaces.append(stInternalVoid , new_internal_void);
layerm->fill_surfaces.append(stInternalSolid, new_internal_solid);
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
layerm->export_region_slices_to_svg_debug("4_discover_vertical_shells");
layerm->export_region_fill_surfaces_to_svg_debug("4_discover_vertical_shells");
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
} // for each layer
} // for each region
}
/* This method applies bridge flow to the first internal solid layer above /* This method applies bridge flow to the first internal solid layer above
sparse infill */ sparse infill */
void void
@ -415,6 +577,9 @@ PrintObject::bridge_over_infill()
} }
// there's no point in bridging too thin/short regions // there's no point in bridging 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.
{ {
double min_width = bridge_flow.scaled_width() * 3; double min_width = bridge_flow.scaled_width() * 3;
to_bridge_pp = offset2(to_bridge_pp, -min_width, +min_width); to_bridge_pp = offset2(to_bridge_pp, -min_width, +min_width);
@ -432,22 +597,17 @@ PrintObject::bridge_over_infill()
// compute the remaning internal solid surfaces as difference // compute the remaning internal solid surfaces as difference
ExPolygons not_to_bridge = diff_ex(internal_solid, to_bridge, true); ExPolygons not_to_bridge = diff_ex(internal_solid, to_bridge, true);
to_bridge = intersection_ex(to_polygons(to_bridge), internal_solid, true);
// build the new collection of fill_surfaces // build the new collection of fill_surfaces
{ {
Surfaces new_surfaces; layerm->fill_surfaces.remove_type(stInternalSolid);
for (Surfaces::const_iterator surface = layerm->fill_surfaces.surfaces.begin(); surface != layerm->fill_surfaces.surfaces.end(); ++surface) {
if (surface->surface_type != stInternalSolid)
new_surfaces.push_back(*surface);
}
for (ExPolygons::const_iterator ex = to_bridge.begin(); ex != to_bridge.end(); ++ex) for (ExPolygons::const_iterator ex = to_bridge.begin(); ex != to_bridge.end(); ++ex)
new_surfaces.push_back(Surface(stInternalBridge, *ex)); layerm->fill_surfaces.surfaces.push_back(Surface(stInternalBridge, *ex));
for (ExPolygons::const_iterator ex = not_to_bridge.begin(); ex != not_to_bridge.end(); ++ex) for (ExPolygons::const_iterator ex = not_to_bridge.begin(); ex != not_to_bridge.end(); ++ex)
new_surfaces.push_back(Surface(stInternalSolid, *ex)); layerm->fill_surfaces.surfaces.push_back(Surface(stInternalSolid, *ex));
layerm->fill_surfaces.surfaces = new_surfaces;
} }
/* /*
@ -483,6 +643,11 @@ PrintObject::bridge_over_infill()
} }
} }
*/ */
#ifdef SLIC3R_DEBUG_SLICE_PROCESSING
layerm->export_region_slices_to_svg_debug("7_bridge_over_infill");
layerm->export_region_fill_surfaces_to_svg_debug("7_bridge_over_infill");
#endif /* SLIC3R_DEBUG_SLICE_PROCESSING */
} }
} }
} }

View file

@ -62,4 +62,7 @@ void confess_at(const char *file, int line, const char *func, const char *pat, .
#define SLIC3R_CPPVER 0 #define SLIC3R_CPPVER 0
#endif #endif
// Write slices as SVG images into out directory during the 2D processing of the slices.
#define SLIC3R_DEBUG_SLICE_PROCESSING
#endif #endif

View file

@ -108,6 +108,7 @@ _constant()
%code%{ THIS->state.set_started(step); %}; %code%{ THIS->state.set_started(step); %};
void process_external_surfaces(); void process_external_surfaces();
void discover_vertical_shells();
void bridge_over_infill(); void bridge_over_infill();
int ptr() int ptr()