Finished porting LayerRegion to C++

This commit is contained in:
Alessandro Ranellucci 2015-10-26 23:23:03 +01:00
parent 5b8ed7367a
commit 9fcec10737
28 changed files with 319 additions and 203 deletions

View file

@ -54,7 +54,6 @@ use Slic3r::GCode::VibrationLimit;
use Slic3r::Geometry qw(PI);
use Slic3r::Geometry::Clipper;
use Slic3r::Layer;
use Slic3r::Layer::Region;
use Slic3r::Line;
use Slic3r::Model;
use Slic3r::Point;
@ -77,7 +76,6 @@ use constant RESOLUTION => 0.0125;
use constant SCALED_RESOLUTION => RESOLUTION / SCALING_FACTOR;
use constant LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER => 0.15;
use constant INFILL_OVERLAP_OVER_SPACING => 0.3;
use constant EXTERNAL_INFILL_MARGIN => 3;
# keep track of threads we created
my @my_threads = ();

View file

@ -48,9 +48,9 @@ sub make_fill {
my $self = shift;
my ($layerm) = @_;
Slic3r::debugf "Filling layer %d:\n", $layerm->id;
Slic3r::debugf "Filling layer %d:\n", $layerm->layer->id;
my $fill_density = $layerm->config->fill_density;
my $fill_density = $layerm->region->config->fill_density;
my $infill_flow = $layerm->flow(FLOW_ROLE_INFILL);
my $solid_infill_flow = $layerm->flow(FLOW_ROLE_SOLID_INFILL);
my $top_solid_infill_flow = $layerm->flow(FLOW_ROLE_TOP_SOLID_INFILL);
@ -74,13 +74,13 @@ sub make_fill {
for (my $i = 0; $i <= $#groups; $i++) {
# we can only merge solid non-bridge surfaces, so discard
# non-solid surfaces
if ($groups[$i][0]->is_solid && (!$groups[$i][0]->is_bridge || $layerm->id == 0)) {
if ($groups[$i][0]->is_solid && (!$groups[$i][0]->is_bridge || $layerm->layer->id == 0)) {
$is_solid[$i] = 1;
$fw[$i] = ($groups[$i][0]->surface_type == S_TYPE_TOP)
? $top_solid_infill_flow->width
: $solid_infill_flow->width;
$pattern[$i] = $groups[$i][0]->is_external
? $layerm->config->external_fill_pattern
? $layerm->region->config->external_fill_pattern
: 'rectilinear';
} else {
$is_solid[$i] = 0;
@ -179,19 +179,19 @@ sub make_fill {
my @fills = ();
SURFACE: foreach my $surface (@surfaces) {
next if $surface->surface_type == S_TYPE_INTERNALVOID;
my $filler = $layerm->config->fill_pattern;
my $filler = $layerm->region->config->fill_pattern;
my $density = $fill_density;
my $role = ($surface->surface_type == S_TYPE_TOP) ? FLOW_ROLE_TOP_SOLID_INFILL
: $surface->is_solid ? FLOW_ROLE_SOLID_INFILL
: FLOW_ROLE_INFILL;
my $is_bridge = $layerm->id > 0 && $surface->is_bridge;
my $is_bridge = $layerm->layer->id > 0 && $surface->is_bridge;
my $is_solid = $surface->is_solid;
if ($surface->is_solid) {
$density = 100;
$filler = 'rectilinear';
if ($surface->is_external && !$is_bridge) {
$filler = $layerm->config->external_fill_pattern;
$filler = $layerm->region->config->external_fill_pattern;
}
} else {
next SURFACE unless $density > 0;
@ -201,14 +201,14 @@ sub make_fill {
my $f = $self->filler($filler);
# calculate the actual flow we'll be using for this infill
my $h = $surface->thickness == -1 ? $layerm->height : $surface->thickness;
my $h = $surface->thickness == -1 ? $layerm->layer->height : $surface->thickness;
my $flow = $layerm->region->flow(
$role,
$h,
$is_bridge || $f->use_bridge_flow,
$layerm->id == 0,
$layerm->layer->id == 0,
-1,
$layerm->object,
$layerm->layer->object,
);
# calculate flow spacing for infill pattern generation
@ -220,11 +220,11 @@ sub make_fill {
# layer height
my $internal_flow = $layerm->region->flow(
FLOW_ROLE_INFILL,
$layerm->object->config->layer_height, # TODO: handle infill_every_layers?
$layerm->layer->object->config->layer_height, # TODO: handle infill_every_layers?
0, # no bridge
0, # no first layer
-1, # auto width
$layerm->object,
$layerm->layer->object,
);
$f->spacing($internal_flow->spacing);
$using_internal_flow = 1;
@ -232,9 +232,9 @@ sub make_fill {
$f->spacing($flow->spacing);
}
$f->layer_id($layerm->id);
$f->z($layerm->print_z);
$f->angle(deg2rad($layerm->config->fill_angle));
$f->layer_id($layerm->layer->id);
$f->z($layerm->layer->print_z);
$f->angle(deg2rad($layerm->region->config->fill_angle));
$f->loop_clipping(scale($flow->nozzle_diameter) * &Slic3r::LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER);
# apply half spacing using this flow's own spacing and generate infill

View file

@ -41,24 +41,25 @@ sub make_perimeters {
for my $region_id (0..$#{$self->regions}) {
next if $done{$region_id};
my $layerm = $self->regions->[$region_id];
my $layerm = $self->get_region($region_id);
my $config = $layerm->region->config;
$done{$region_id} = 1;
# find compatible regions
my @layerms = ($layerm);
for my $i (($region_id+1)..$#{$self->regions}) {
my $config = $self->regions->[$i]->config;
my $layerm_config = $layerm->config;
my $other_layerm = $self->get_region($i);
my $other_config = $other_layerm->region->config;
if ($config->perimeter_extruder == $layerm_config->perimeter_extruder
&& $config->perimeters == $layerm_config->perimeters
&& $config->perimeter_speed == $layerm_config->perimeter_speed
&& $config->gap_fill_speed == $layerm_config->gap_fill_speed
&& $config->overhangs == $layerm_config->overhangs
&& $config->perimeter_extrusion_width == $layerm_config->perimeter_extrusion_width
&& $config->thin_walls == $layerm_config->thin_walls
&& $config->external_perimeters_first == $layerm_config->external_perimeters_first) {
push @layerms, $self->regions->[$i];
if ($config->perimeter_extruder == $other_config->perimeter_extruder
&& $config->perimeters == $other_config->perimeters
&& $config->perimeter_speed == $other_config->perimeter_speed
&& $config->gap_fill_speed == $other_config->gap_fill_speed
&& $config->overhangs == $other_config->overhangs
&& $config->perimeter_extrusion_width == $other_config->perimeter_extrusion_width
&& $config->thin_walls == $other_config->thin_walls
&& $config->external_perimeters_first == $other_config->external_perimeters_first) {
push @layerms, $other_layerm;
$done{$i} = 1;
}
}

View file

@ -1,103 +0,0 @@
package Slic3r::Layer::Region;
use strict;
use warnings;
use Slic3r::ExtrusionPath ':roles';
use Slic3r::Flow ':roles';
use Slic3r::Geometry qw(scale);
use Slic3r::Geometry::Clipper qw(diff_ex intersection_ex
);
use Slic3r::Surface ':types';
# TODO: lazy
sub infill_area_threshold {
my $self = shift;
return $self->flow(FLOW_ROLE_SOLID_INFILL)->scaled_spacing ** 2;
}
sub id { return $_[0]->layer->id; }
sub slice_z { return $_[0]->layer->slice_z; }
sub print_z { return $_[0]->layer->print_z; }
sub height { return $_[0]->layer->height; }
sub object { return $_[0]->layer->object; }
sub print { return $_[0]->layer->print; }
sub config { return $_[0]->region->config; }
sub process_external_surfaces {
my ($self, $lower_layer) = @_;
my @surfaces = @{$self->fill_surfaces};
my $margin = scale &Slic3r::EXTERNAL_INFILL_MARGIN;
my @bottom = ();
foreach my $surface (grep $_->is_bottom, @surfaces) {
my $grown = $surface->expolygon->offset_ex(+$margin);
# detect bridge direction before merging grown surfaces otherwise adjacent bridges
# would get merged into a single one while they need different directions
# also, supply the original expolygon instead of the grown one, because in case
# of very thin (but still working) anchors, the grown expolygon would go beyond them
my $angle;
if ($lower_layer) {
my $bridge_detector = Slic3r::BridgeDetector->new(
$surface->expolygon,
$lower_layer->slices,
$self->flow(FLOW_ROLE_INFILL, $self->height, 1)->scaled_width,
);
Slic3r::debugf "Processing bridge at layer %d:\n", $self->id;
$bridge_detector->detect_angle;
$angle = $bridge_detector->angle;
if (defined $angle && $self->object->config->support_material) {
$self->bridged->append(Slic3r::ExPolygon->new($_))
for @{ $bridge_detector->coverage_by_angle($angle) };
$self->unsupported_bridge_edges->append($_) for @{ $bridge_detector->unsupported_edges };
}
}
push @bottom, map $surface->clone(expolygon => $_, bridge_angle => $angle), @$grown;
}
my @top = ();
foreach my $surface (grep $_->surface_type == S_TYPE_TOP, @surfaces) {
# give priority to bottom surfaces
my $grown = diff_ex(
$surface->expolygon->offset(+$margin),
[ map $_->p, @bottom ],
);
push @top, map $surface->clone(expolygon => $_), @$grown;
}
# if we're slicing with no infill, we can't extend external surfaces
# over non-existent infill
my @fill_boundaries = $self->config->fill_density > 0
? @surfaces
: grep $_->surface_type != S_TYPE_INTERNAL, @surfaces;
# intersect the grown surfaces with the actual fill boundaries
my @new_surfaces = ();
foreach my $group (@{Slic3r::Surface::Collection->new(@top, @bottom)->group}) {
push @new_surfaces,
map $group->[0]->clone(expolygon => $_),
@{intersection_ex(
[ map $_->p, @$group ],
[ map $_->p, @fill_boundaries ],
1, # to ensure adjacent expolygons are unified
)};
}
# subtract the new top surfaces from the other non-top surfaces and re-add them
my @other = grep $_->surface_type != S_TYPE_TOP && !$_->is_bottom, @surfaces;
foreach my $group (@{Slic3r::Surface::Collection->new(@other)->group}) {
push @new_surfaces, map $group->[0]->clone(expolygon => $_), @{diff_ex(
[ map $_->p, @$group ],
[ map $_->p, @new_surfaces ],
)};
}
$self->fill_surfaces->clear;
$self->fill_surfaces->append($_) for @new_surfaces;
}
1;

View file

@ -357,7 +357,7 @@ sub process_layer {
$self->_spiral_vase->enable(
($layer->id > 0 || $self->print->config->brim_width == 0)
&& ($layer->id >= $self->print->config->skirt_height && !$self->print->has_infinite_skirt)
&& !defined(first { $_->config->bottom_solid_layers > $layer->id } @{$layer->regions})
&& !defined(first { $_->region->config->bottom_solid_layers > $layer->id } @{$layer->regions})
&& !defined(first { $_->perimeters->items_count > 1 } @{$layer->regions})
&& !defined(first { $_->fills->items_count > 0 } @{$layer->regions})
);

View file

@ -830,17 +830,6 @@ sub clip_fill_surfaces {
}
}
sub process_external_surfaces {
my ($self) = @_;
for my $region_id (0 .. ($self->print->region_count-1)) {
$self->get_layer(0)->regions->[$region_id]->process_external_surfaces(undef);
for my $i (1 .. ($self->layer_count - 1)) {
$self->get_layer($i)->regions->[$region_id]->process_external_surfaces($self->get_layer($i-1));
}
}
}
sub discover_horizontal_shells {
my $self = shift;
@ -850,8 +839,8 @@ sub discover_horizontal_shells {
for (my $i = 0; $i < $self->layer_count; $i++) {
my $layerm = $self->get_layer($i)->regions->[$region_id];
if ($layerm->config->solid_infill_every_layers && $layerm->config->fill_density > 0
&& ($i % $layerm->config->solid_infill_every_layers) == 0) {
if ($layerm->region->config->solid_infill_every_layers && $layerm->region->config->fill_density > 0
&& ($i % $layerm->region->config->solid_infill_every_layers) == 0) {
$_->surface_type(S_TYPE_INTERNALSOLID) for @{$layerm->fill_surfaces->filter_by_type(S_TYPE_INTERNAL)};
}
@ -873,8 +862,8 @@ sub discover_horizontal_shells {
Slic3r::debugf "Layer %d has %s surfaces\n", $i, ($type == S_TYPE_TOP) ? 'top' : 'bottom';
my $solid_layers = ($type == S_TYPE_TOP)
? $layerm->config->top_solid_layers
: $layerm->config->bottom_solid_layers;
? $layerm->region->config->top_solid_layers
: $layerm->region->config->bottom_solid_layers;
NEIGHBOR: for (my $n = ($type == S_TYPE_TOP) ? $i-1 : $i+1;
abs($n - $i) <= $solid_layers-1;
($type == S_TYPE_TOP) ? $n-- : $n++) {
@ -902,7 +891,7 @@ sub discover_horizontal_shells {
);
next EXTERNAL if !@$new_internal_solid;
if ($layerm->config->fill_density == 0) {
if ($layerm->region->config->fill_density == 0) {
# if we're printing a hollow object we discard any solid shell thinner
# than a perimeter width, since it's probably just crossing a sloping wall
# and it's not wanted in a hollow print even if it would make sense when
@ -1100,12 +1089,12 @@ sub combine_infill {
)};
# apply surfaces back with adjusted depth to the uppermost layer
if ($layerm->id == $self->get_layer($layer_idx)->id) {
if ($layerm->layer->id == $self->get_layer($layer_idx)->id) {
push @new_this_type,
map Slic3r::Surface->new(
expolygon => $_,
surface_type => $type,
thickness => sum(map $_->height, @layerms),
thickness => sum(map $_->layer->height, @layerms),
thickness_layers => scalar(@layerms),
),
@$intersection;

View file

@ -235,7 +235,7 @@ sub contact_area {
# just remove bridged areas
$diff = diff(
$diff,
[ map @$_, @{$layerm->bridged} ],
$layerm->bridged,
1,
);
}
@ -267,7 +267,7 @@ sub contact_area {
# get the average nozzle diameter used on this layer
my @nozzle_diameters = map $self->print_config->get_at('nozzle_diameter', $_),
map { $_->config->perimeter_extruder-1, $_->config->infill_extruder-1, $_->config->solid_infill_extruder-1 }
@{$layer->regions};
map $_->region, @{$layer->regions};
my $nozzle_diameter = sum(@nozzle_diameters)/@nozzle_diameters;
my $contact_z = $layer->print_z - $self->contact_distance($layer->height, $nozzle_diameter);

View file

@ -185,16 +185,12 @@ BridgeDetector::detect_angle()
return true;
}
void
BridgeDetector::coverage(Polygons* coverage) const
{
if (this->angle == -1) return;
return this->coverage(angle, coverage);
}
void
BridgeDetector::coverage(double angle, Polygons* coverage) const
{
if (angle == -1) angle = this->angle;
if (angle == -1) return;
// Clone our expolygon and rotate it so that we work with vertical lines.
ExPolygon expolygon = this->expolygon;
expolygon.rotate(PI/2.0 - angle, Point(0,0));
@ -263,19 +259,23 @@ BridgeDetector::coverage(double angle, Polygons* coverage) const
*/
}
Polygons
BridgeDetector::coverage(double angle) const
{
Polygons pp;
this->coverage(angle, &pp);
return pp;
}
/* This method returns the bridge edges (as polylines) that are not supported
but would allow the entire bridge area to be bridged with detected angle
if supported too */
void
BridgeDetector::unsupported_edges(Polylines* unsupported) const
{
if (this->angle == -1) return;
return this->unsupported_edges(this->angle, unsupported);
}
void
BridgeDetector::unsupported_edges(double angle, Polylines* unsupported) const
{
if (angle == -1) angle = this->angle;
if (angle == -1) return;
// get bridge edges (both contour and holes)
Polylines bridge_edges;
{
@ -319,6 +319,14 @@ BridgeDetector::unsupported_edges(double angle, Polylines* unsupported) const
*/
}
Polylines
BridgeDetector::unsupported_edges(double angle) const
{
Polylines pp;
this->unsupported_edges(angle, &pp);
return pp;
}
#ifdef SLIC3RXS
REGISTER_CLASS(BridgeDetector, "BridgeDetector");
#endif

View file

@ -18,10 +18,10 @@ class BridgeDetector {
BridgeDetector(const ExPolygon &_expolygon, const ExPolygonCollection &_lower_slices, coord_t _extrusion_width);
bool detect_angle();
void coverage(Polygons* coverage) const;
void coverage(double angle, Polygons* coverage) const;
void unsupported_edges(Polylines* unsupported) const;
Polygons coverage(double angle = -1) const;
void unsupported_edges(double angle, Polylines* unsupported) const;
Polylines unsupported_edges(double angle = -1) const;
private:
Polylines _edges; // representing the supporting edges

View file

@ -212,6 +212,15 @@ offset(const Slic3r::Polygons &polygons, Slic3r::ExPolygons* retval, const float
ClipperPaths_to_Slic3rExPolygons(output, retval);
}
Slic3r::ExPolygons
offset_ex(const Slic3r::Polygons &polygons, const float delta,
double scale, ClipperLib::JoinType joinType, double miterLimit)
{
Slic3r::ExPolygons expp;
offset(polygons, &expp, delta, scale, joinType, miterLimit);
return expp;
}
void
offset2(const Slic3r::Polygons &polygons, ClipperLib::Paths* retval, const float delta1,
const float delta2, const double scale, const ClipperLib::JoinType joinType, const double miterLimit)
@ -472,13 +481,16 @@ diff(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool safety_
return pp;
}
template <class SubjectType, class ClipType>
Slic3r::ExPolygons
diff_ex(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool safety_offset_)
diff_ex(const SubjectType &subject, const ClipType &clip, bool safety_offset_)
{
Slic3r::ExPolygons expp;
diff(subject, clip, &expp, safety_offset_);
return expp;
}
template Slic3r::ExPolygons diff_ex<Slic3r::Polygons, Slic3r::Polygons>(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool safety_offset_);
template Slic3r::ExPolygons diff_ex<Slic3r::Polygons, Slic3r::ExPolygons>(const Slic3r::Polygons &subject, const Slic3r::ExPolygons &clip, bool safety_offset_);
template <class SubjectType, class ResultType>
void intersection(const SubjectType &subject, const Slic3r::Polygons &clip, ResultType* retval, bool safety_offset_)
@ -507,6 +519,14 @@ intersection(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip, boo
return pp;
}
Slic3r::ExPolygons
intersection_ex(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool safety_offset_)
{
Slic3r::ExPolygons expp;
intersection(subject, clip, &expp, safety_offset_);
return expp;
}
template <class SubjectType>
bool intersects(const SubjectType &subject, const Slic3r::Polygons &clip, bool safety_offset_)
{

View file

@ -58,6 +58,9 @@ void offset(const Slic3r::Surface &surface, Slic3r::Surfaces* retval, const floa
void offset(const Slic3r::Polygons &polygons, Slic3r::ExPolygons* retval, const float delta,
double scale = 100000, ClipperLib::JoinType joinType = ClipperLib::jtMiter,
double miterLimit = 3);
Slic3r::ExPolygons offset_ex(const Slic3r::Polygons &polygons, const float delta,
double scale = 100000, ClipperLib::JoinType joinType = ClipperLib::jtMiter,
double miterLimit = 3);
void offset2(const Slic3r::Polygons &polygons, ClipperLib::Paths* retval, const float delta1,
const float delta2, double scale = 100000, ClipperLib::JoinType joinType = ClipperLib::jtMiter,
@ -96,13 +99,16 @@ template <class SubjectType, class ResultType>
void diff(const SubjectType &subject, const Slic3r::ExPolygons &clip, ResultType* retval, bool safety_offset_ = false);
Slic3r::Polygons diff(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool safety_offset_ = false);
Slic3r::ExPolygons diff_ex(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool safety_offset_ = false);
template <class SubjectType, class ClipType>
Slic3r::ExPolygons diff_ex(const SubjectType &subject, const ClipType &clip, bool safety_offset_ = false);
template <class SubjectType, class ResultType>
void intersection(const SubjectType &subject, const Slic3r::Polygons &clip, ResultType* retval, bool safety_offset_ = false);
Slic3r::Polygons intersection(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool safety_offset_ = false);
Slic3r::Polylines intersection(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip, bool safety_offset_ = false);
Slic3r::ExPolygons intersection_ex(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, bool safety_offset_ = false);
template <class SubjectType>
bool intersects(const SubjectType &subject, const Slic3r::Polygons &clip, bool safety_offset_ = false);

View file

@ -122,6 +122,12 @@ ExPolygonCollection::contours() const
return contours;
}
void
ExPolygonCollection::append(const ExPolygons &expp)
{
this->expolygons.insert(this->expolygons.end(), expp.begin(), expp.end());
}
#ifdef SLIC3RXS
REGISTER_CLASS(ExPolygonCollection, "ExPolygon::Collection");
#endif

View file

@ -31,6 +31,7 @@ class ExPolygonCollection
Polygon convex_hull() const;
Lines lines() const;
Polygons contours() const;
void append(const ExPolygons &expolygons);
};
}

View file

@ -40,8 +40,7 @@ class LayerRegion
// collection of expolygons representing the bridged areas (thus not
// needing support material)
// (this could be just a Polygons object)
ExPolygonCollection bridged;
Polygons bridged;
// collection of polylines representing the unsupported bridge edges
PolylineCollection unsupported_bridge_edges;
@ -58,6 +57,8 @@ class LayerRegion
void merge_slices();
void prepare_fill_surfaces();
void make_perimeters(const SurfaceCollection &slices, SurfaceCollection* fill_surfaces);
void process_external_surfaces(const Layer* lower_layer);
double infill_area_threshold() const;
private:
Layer *_layer;

View file

@ -1,4 +1,5 @@
#include "Layer.hpp"
#include "BridgeDetector.hpp"
#include "ClipperUtils.hpp"
#include "PerimeterGenerator.hpp"
#include "Print.hpp"
@ -86,6 +87,146 @@ LayerRegion::make_perimeters(const SurfaceCollection &slices, SurfaceCollection*
g.process();
}
void
LayerRegion::process_external_surfaces(const Layer* lower_layer)
{
const Surfaces &surfaces = this->fill_surfaces.surfaces;
const double margin = scale_(EXTERNAL_INFILL_MARGIN);
SurfaceCollection bottom;
for (Surfaces::const_iterator surface = surfaces.begin(); surface != surfaces.end(); ++surface) {
if (!surface->is_bottom()) continue;
ExPolygons grown = offset_ex(surface->expolygon, +margin);
/* detect bridge direction before merging grown surfaces otherwise adjacent bridges
would get merged into a single one while they need different directions
also, supply the original expolygon instead of the grown one, because in case
of very thin (but still working) anchors, the grown expolygon would go beyond them */
double angle = -1;
if (lower_layer != NULL) {
BridgeDetector bd(
surface->expolygon,
lower_layer->slices,
this->flow(frInfill, this->layer()->height, true).scaled_width()
);
#ifdef SLIC3R_DEBUG
printf("Processing bridge at layer %zu:\n", this->layer()->id();
#endif
if (bd.detect_angle() && this->layer()->object()->config.support_material) {
angle = bd.angle;
Polygons coverage = bd.coverage();
this->bridged.insert(this->bridged.end(), coverage.begin(), coverage.end());
this->unsupported_bridge_edges.append(bd.unsupported_edges());
}
}
for (ExPolygons::const_iterator it = grown.begin(); it != grown.end(); ++it) {
Surface s = *surface;
s.expolygon = *it;
s.bridge_angle = angle;
bottom.surfaces.push_back(s);
}
}
SurfaceCollection top;
for (Surfaces::const_iterator surface = surfaces.begin(); surface != surfaces.end(); ++surface) {
if (surface->surface_type != stTop) continue;
// give priority to bottom surfaces
ExPolygons grown = diff_ex(
offset(surface->expolygon, +margin),
(Polygons)bottom
);
for (ExPolygons::const_iterator it = grown.begin(); it != grown.end(); ++it) {
Surface s = *surface;
s.expolygon = *it;
top.surfaces.push_back(s);
}
}
/* if we're slicing with no infill, we can't extend external surfaces
over non-existent infill */
SurfaceCollection fill_boundaries;
if (this->region()->config.fill_density.value > 0) {
fill_boundaries = SurfaceCollection(surfaces);
} else {
for (Surfaces::const_iterator it = surfaces.begin(); it != surfaces.end(); ++it) {
if (it->surface_type != stInternal)
fill_boundaries.surfaces.push_back(*it);
}
}
// intersect the grown surfaces with the actual fill boundaries
SurfaceCollection new_surfaces;
{
// merge top and bottom in a single collection
SurfaceCollection tb = top;
tb.surfaces.insert(tb.surfaces.end(), bottom.surfaces.begin(), bottom.surfaces.end());
// group surfaces
std::vector<SurfacesPtr> groups;
tb.group(&groups);
for (std::vector<SurfacesPtr>::const_iterator g = groups.begin(); g != groups.end(); ++g) {
Polygons subject;
for (SurfacesPtr::const_iterator s = g->begin(); s != g->end(); ++s) {
Polygons pp = **s;
subject.insert(subject.end(), pp.begin(), pp.end());
}
ExPolygons expp = intersection_ex(
subject,
(Polygons)fill_boundaries,
true // to ensure adjacent expolygons are unified
);
for (ExPolygons::const_iterator ex = expp.begin(); ex != expp.end(); ++ex) {
Surface s = *g->front();
s.expolygon = *ex;
new_surfaces.surfaces.push_back(s);
}
}
}
/* subtract the new top surfaces from the other non-top surfaces and re-add them */
{
SurfaceCollection other;
for (Surfaces::const_iterator s = surfaces.begin(); s != surfaces.end(); ++s) {
if (s->surface_type != stTop && !s->is_bottom())
other.surfaces.push_back(*s);
}
// group surfaces
std::vector<SurfacesPtr> groups;
other.group(&groups);
for (std::vector<SurfacesPtr>::const_iterator g = groups.begin(); g != groups.end(); ++g) {
Polygons subject;
for (SurfacesPtr::const_iterator s = g->begin(); s != g->end(); ++s) {
Polygons pp = **s;
subject.insert(subject.end(), pp.begin(), pp.end());
}
ExPolygons expp = diff_ex(
subject,
(Polygons)new_surfaces
);
for (ExPolygons::const_iterator ex = expp.begin(); ex != expp.end(); ++ex) {
Surface s = *g->front();
s.expolygon = *ex;
new_surfaces.surfaces.push_back(s);
}
}
}
this->fill_surfaces = new_surfaces;
}
void
LayerRegion::prepare_fill_surfaces()
{
@ -123,6 +264,13 @@ LayerRegion::prepare_fill_surfaces()
}
}
double
LayerRegion::infill_area_threshold() const
{
double ss = this->flow(frSolidInfill).scaled_spacing();
return ss*ss;
}
#ifdef SLIC3RXS
REGISTER_CLASS(LayerRegion, "Layer::Region");
#endif

View file

@ -47,7 +47,7 @@ PerimeterGenerator::process()
for (Surfaces::const_iterator surface = this->slices->surfaces.begin();
surface != this->slices->surfaces.end(); ++surface) {
// detect how many perimeters must be generated for this island
short loop_number = this->config->perimeters + surface->extra_perimeters;
signed short loop_number = this->config->perimeters + surface->extra_perimeters;
loop_number--; // 0-indexed loops
Polygons gaps;
@ -60,7 +60,7 @@ PerimeterGenerator::process()
Polylines thin_walls;
// we loop one time more than needed in order to find gaps after the last perimeter was applied
for (unsigned short i = 0; i <= loop_number+1; ++i) { // outer loop is 0
for (signed short i = 0; i <= loop_number+1; ++i) { // outer loop is 0
Polygons offsets;
if (i == 0) {
// the minimum thickness of a single loop is:
@ -166,16 +166,16 @@ PerimeterGenerator::process()
}
// nest loops: holes first
for (unsigned short d = 0; d <= loop_number; ++d) {
for (signed short d = 0; d <= loop_number; ++d) {
PerimeterGeneratorLoops &holes_d = holes[d];
// loop through all holes having depth == d
for (unsigned short i = 0; i < holes_d.size(); ++i) {
for (signed short i = 0; i < holes_d.size(); ++i) {
const PerimeterGeneratorLoop &loop = holes_d[i];
// find the hole loop that contains this one, if any
for (unsigned short t = d+1; t <= loop_number; ++t) {
for (unsigned short j = 0; j < holes[t].size(); ++j) {
for (signed short t = d+1; t <= loop_number; ++t) {
for (signed short j = 0; j < holes[t].size(); ++j) {
PerimeterGeneratorLoop &candidate_parent = holes[t][j];
if (candidate_parent.polygon.contains(loop.polygon.first_point())) {
candidate_parent.children.push_back(loop);
@ -187,8 +187,8 @@ PerimeterGenerator::process()
}
// if no hole contains this hole, find the contour loop that contains it
for (short t = loop_number; t >= 0; --t) {
for (unsigned short j = 0; j < contours[t].size(); ++j) {
for (signed short t = loop_number; t >= 0; --t) {
for (signed short j = 0; j < contours[t].size(); ++j) {
PerimeterGeneratorLoop &candidate_parent = contours[t][j];
if (candidate_parent.polygon.contains(loop.polygon.first_point())) {
candidate_parent.children.push_back(loop);
@ -203,16 +203,16 @@ PerimeterGenerator::process()
}
// nest contour loops
for (short d = loop_number; d >= 1; --d) {
for (signed short d = loop_number; d >= 1; --d) {
PerimeterGeneratorLoops &contours_d = contours[d];
// loop through all contours having depth == d
for (unsigned short i = 0; i < contours_d.size(); ++i) {
for (signed short i = 0; i < contours_d.size(); ++i) {
const PerimeterGeneratorLoop &loop = contours_d[i];
// find the contour loop that contains it
for (short t = d-1; t >= 0; --t) {
for (unsigned short j = 0; j < contours[t].size(); ++j) {
for (signed short t = d-1; t >= 0; --t) {
for (signed short j = 0; j < contours[t].size(); ++j) {
PerimeterGeneratorLoop &candidate_parent = contours[t][j];
if (candidate_parent.polygon.contains(loop.polygon.first_point())) {
candidate_parent.children.push_back(loop);

View file

@ -50,6 +50,12 @@ PolylineCollection::leftmost_point() const
return p;
}
void
PolylineCollection::append(const Polylines &pp)
{
this->polylines.insert(this->polylines.end(), pp.begin(), pp.end());
}
#ifdef SLIC3RXS
REGISTER_CLASS(PolylineCollection, "Polyline::Collection");
#endif

View file

@ -13,6 +13,7 @@ class PolylineCollection
void chained_path(PolylineCollection* retval, bool no_reverse = false) const;
void chained_path_from(Point start_near, PolylineCollection* retval, bool no_reverse = false) const;
Point leftmost_point() const;
void append(const Polylines &polylines);
};
}

View file

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

View file

@ -340,14 +340,32 @@ PrintObject::has_support_material() const
|| this->config.support_material_enforce_layers > 0;
}
void
PrintObject::process_external_surfaces()
{
FOREACH_REGION(this->_print, region) {
size_t region_id = region - this->_print->regions.begin();
FOREACH_LAYER(this, layer_it) {
const Layer* lower_layer = (layer_it == this->layers.begin())
? NULL
: *(layer_it-1);
(*layer_it)->get_region(region_id)->process_external_surfaces(lower_layer);
}
}
}
/* This method applies bridge flow to the first internal solid layer above
sparse infill */
void
PrintObject::bridge_over_infill()
{
FOREACH_REGION(this->_print, region) {
size_t region_id = region - this->_print->regions.begin();
double fill_density = (*region)->config.fill_density.value;
if (fill_density == 100) continue;
// skip bridging in case there are no voids
if ((*region)->config.fill_density.value == 100) continue;
// get bridge flow
Flow bridge_flow = (*region)->flow(
@ -360,6 +378,7 @@ PrintObject::bridge_over_infill()
);
FOREACH_LAYER(this, layer_it) {
// skip first layer
if (layer_it == this->layers.begin()) continue;
Layer* layer = *layer_it;
@ -379,7 +398,7 @@ PrintObject::bridge_over_infill()
// iterate through lower layers spanned by bridge_flow
double bottom_z = layer->print_z - bridge_flow.height;
for (int i = (layer_it - this->layers.begin()) - 1; i >= 0; --i) {
Layer* lower_layer = this->layers[i];
const Layer* lower_layer = this->layers[i];
// stop iterating if layer is lower than bottom_z
if (lower_layer->print_z < bottom_z) break;
@ -390,19 +409,19 @@ PrintObject::bridge_over_infill()
(*lower_layerm_it)->fill_surfaces.filter_by_type(stInternal, &lower_internal);
// intersect such lower internal surfaces with the candidate solid surfaces
intersection(to_bridge_pp, lower_internal, &to_bridge_pp);
to_bridge_pp = intersection(to_bridge_pp, lower_internal);
}
// there's no point in bridging too thin/short regions
{
double min_width = bridge_flow.scaled_width() * 3;
offset2(to_bridge_pp, &to_bridge_pp, -min_width, +min_width);
to_bridge_pp = offset2(to_bridge_pp, -min_width, +min_width);
}
if (to_bridge_pp.empty()) continue;
// convert into ExPolygons
union_(to_bridge_pp, &to_bridge);
to_bridge = union_ex(to_bridge_pp);
}
#ifdef SLIC3R_DEBUG
@ -410,8 +429,7 @@ PrintObject::bridge_over_infill()
#endif
// compute the remaning internal solid surfaces as difference
ExPolygons not_to_bridge;
diff(internal_solid, to_bridge, &not_to_bridge, true);
ExPolygons not_to_bridge = diff_ex(internal_solid, to_bridge, true);
// build the new collection of fill_surfaces
{

View file

@ -2,6 +2,11 @@
namespace Slic3r {
Surface::operator Polygons() const
{
return this->expolygon;
}
double
Surface::area() const
{

View file

@ -21,6 +21,7 @@ class Surface
: surface_type(_surface_type), expolygon(_expolygon),
thickness(-1), thickness_layers(1), bridge_angle(-1), extra_perimeters(0)
{};
operator Polygons() const;
double area() const;
bool is_solid() const;
bool is_external() const;

View file

@ -111,6 +111,12 @@ SurfaceCollection::filter_by_type(SurfaceType type, Polygons* polygons)
}
}
void
SurfaceCollection::append(const SurfaceCollection &coll)
{
this->surfaces.insert(this->surfaces.end(), coll.surfaces.begin(), coll.surfaces.end());
}
#ifdef SLIC3RXS
REGISTER_CLASS(SurfaceCollection, "Surface::Collection");
#endif

View file

@ -11,6 +11,9 @@ class SurfaceCollection
public:
Surfaces surfaces;
SurfaceCollection() {};
SurfaceCollection(const Surfaces &_surfaces)
: surfaces(_surfaces) {};
operator Polygons() const;
operator ExPolygons() const;
void simplify(double tolerance);
@ -19,6 +22,7 @@ class SurfaceCollection
template <class T> bool any_bottom_contains(const T &item) const;
SurfacesPtr filter_by_type(SurfaceType type);
void filter_by_type(SurfaceType type, Polygons* polygons);
void append(const SurfaceCollection &coll);
};
}

View file

@ -16,6 +16,7 @@
#define LOOP_CLIPPING_LENGTH_OVER_NOZZLE_DIAMETER 0.15
#define SMALL_PERIMETER_LENGTH (6.5 / SCALING_FACTOR) * 2 * PI
#define INSET_OVERLAP_TOLERANCE 0.4
#define EXTERNAL_INFILL_MARGIN 3
#define scale_(val) (val / SCALING_FACTOR)
#define unscale(val) (val * SCALING_FACTOR)
#define SCALED_EPSILON scale_(EPSILON)

View file

@ -9,14 +9,10 @@
~BridgeDetector();
bool detect_angle();
Polygons coverage()
%code{% THIS->coverage(&RETVAL); %};
Polygons coverage_by_angle(double angle)
%code{% THIS->coverage(angle, &RETVAL); %};
Polylines unsupported_edges()
%code{% THIS->unsupported_edges(&RETVAL); %};
Polylines unsupported_edges_by_angle(double angle)
%code{% THIS->unsupported_edges(angle, &RETVAL); %};
Polygons coverage();
%name{coverage_by_angle} Polygons coverage(double angle);
Polylines unsupported_edges();
%name{unsupported_edges_by_angle} Polylines unsupported_edges(double angle);
double angle()
%code{% RETVAL = THIS->angle; %};
double resolution()

View file

@ -17,8 +17,8 @@
%code%{ RETVAL = &THIS->thin_fills; %};
Ref<SurfaceCollection> fill_surfaces()
%code%{ RETVAL = &THIS->fill_surfaces; %};
Ref<ExPolygonCollection> bridged()
%code%{ RETVAL = &THIS->bridged; %};
Polygons bridged()
%code%{ RETVAL = THIS->bridged; %};
Ref<PolylineCollection> unsupported_bridge_edges()
%code%{ RETVAL = &THIS->unsupported_bridge_edges; %};
Ref<ExtrusionEntityCollection> perimeters()
@ -32,6 +32,7 @@
void prepare_fill_surfaces();
void make_perimeters(SurfaceCollection* slices, SurfaceCollection* fill_surfaces)
%code%{ THIS->make_perimeters(*slices, fill_surfaces); %};
double infill_area_threshold();
};
%name{Slic3r::Layer} class Layer {

View file

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