Ported brim generation to C++/XS

This commit is contained in:
Alessandro Ranellucci 2016-12-20 00:44:03 +01:00
parent 4724f0fb99
commit 12165c727e
7 changed files with 150 additions and 122 deletions

View File

@ -350,126 +350,8 @@ sub make_brim {
$_->generate_support_material for @{$self->objects};
$self->make_skirt;
return if $self->step_done(STEP_BRIM);
$self->set_step_started(STEP_BRIM);
# since this method must be idempotent, we clear brim paths *before*
# checking whether we need to generate them
$self->brim->clear;
if ($self->config->brim_width == 0 && $self->config->brim_connections_width == 0) {
$self->set_step_done(STEP_BRIM);
return;
}
$self->status_cb->(88, "Generating brim");
# brim is only printed on first layer and uses perimeter extruder
my $first_layer_height = $self->skirt_first_layer_height;
my $flow = $self->brim_flow;
my $mm3_per_mm = $flow->mm3_per_mm;
my $grow_distance = $flow->scaled_width / 2;
my @islands = (); # array of polygons
foreach my $obj_idx (0 .. ($self->object_count - 1)) {
my $object = $self->objects->[$obj_idx];
my $layer0 = $object->get_layer(0);
my @object_islands = (
(map $_->contour, @{$layer0->slices}),
);
if (@{ $object->support_layers }) {
my $support_layer0 = $object->support_layers->[0];
push @object_islands,
(map @{$_->polyline->grow($grow_distance)}, @{$support_layer0->support_fills})
if $support_layer0->support_fills;
push @object_islands,
(map @{$_->polyline->grow($grow_distance)}, @{$support_layer0->support_interface_fills})
if $support_layer0->support_interface_fills;
}
foreach my $copy (@{$object->_shifted_copies}) {
push @islands, map { $_->translate(@$copy); $_ } map $_->clone, @object_islands;
}
}
my @loops = ();
my $num_loops = int($self->config->brim_width / $flow->width + 0.5);
for my $i (reverse 1 .. $num_loops) {
# JT_SQUARE ensures no vertex is outside the given offset distance
# -0.5 because islands are not represented by their centerlines
# (first offset more, then step back - reverse order than the one used for
# perimeters because here we're offsetting outwards)
push @loops, @{offset2(\@islands, ($i + 0.5) * $flow->scaled_spacing, -1.0 * $flow->scaled_spacing, 100000, JT_SQUARE)};
}
$self->brim->append(map Slic3r::ExtrusionLoop->new_from_paths(
Slic3r::ExtrusionPath->new(
polyline => Slic3r::Polygon->new(@$_)->split_at_first_point,
role => EXTR_ROLE_SKIRT,
mm3_per_mm => $mm3_per_mm,
width => $flow->width,
height => $first_layer_height,
),
), reverse @{union_pt_chained(\@loops)});
if ($self->config->brim_connections_width > 0) {
# get islands to connects
@islands = map convex_hull(\@$_), @islands;
@islands = @{offset(\@islands, ($num_loops-0.2) * $flow->scaled_spacing, 10000, JT_SQUARE)};
# compute centroid for each island
my @centroids = map $_->centroid, @islands;
# in order to check visibility we need to account for the connections width,
# so let's use grown islands
my $scaled_width = scale($self->config->brim_connections_width);
my $grown = offset(\@islands, +$scaled_width/2);
# find pairs of islands having direct visibility
my @lines = ();
for my $i (0..$#islands) {
for my $j (($i+1)..$#islands) {
# check visibility
my $line = Slic3r::Line->new(@centroids[$i,$j]);
next if @{diff_pl([$line->as_polyline], $grown)} != 1;
push @lines, $line;
}
}
my $filler = Slic3r::Filler->new_from_type('rectilinear');
$filler->set_spacing($flow->spacing);
$filler->set_dont_adjust(1);
# subtract already generated connections in order to prevent crossings
# and overextrusion
my @other = ();
foreach my $line (@lines) {
my $expolygons = diff_ex(
$line->grow($scaled_width/2),
[ @islands, @other ],
);
push @other, map $_->clone, map @$_, @$expolygons;
$filler->set_angle($line->direction);
foreach my $expolygon (@$expolygons) {
my $paths = $filler->fill_surface(
Slic3r::Surface->new(expolygon => $expolygon, surface_type => S_TYPE_BOTTOM),
layer_height => $first_layer_height,
density => 1,
);
$self->brim->append(map Slic3r::ExtrusionPath->new(
polyline => $_,
role => EXTR_ROLE_SKIRT,
mm3_per_mm => $mm3_per_mm,
width => $flow->width,
height => $first_layer_height,
), @$paths);
}
}
}
$self->set_step_done(STEP_BRIM);
$self->_make_brim;
}
# this method will return the supplied input file path after expanding its

View File

@ -165,6 +165,9 @@ class ExtrusionLoop : public ExtrusionEntity
// Minimum volumetric velocity of this extrusion entity. Used by the constant nozzle pressure algorithm.
double min_mm3_per_mm() const;
Polyline as_polyline() const { return this->polygon().split_at_first_point(); }
void append(const ExtrusionPath &path) {
this->paths.push_back(path);
};
};
}

View File

@ -33,9 +33,16 @@ ExtrusionEntityCollection::swap (ExtrusionEntityCollection &c)
}
ExtrusionEntityCollection::~ExtrusionEntityCollection()
{
this->clear();
}
void
ExtrusionEntityCollection::clear()
{
for (ExtrusionEntitiesPtr::iterator it = this->entities.begin(); it != this->entities.end(); ++it)
delete *it;
this->entities.clear();
}
ExtrusionEntityCollection::operator ExtrusionPaths() const

View File

@ -30,9 +30,7 @@ class ExtrusionEntityCollection : public ExtrusionEntity
bool empty() const {
return this->entities.empty();
};
void clear() {
this->entities.clear();
};
void clear();
void swap (ExtrusionEntityCollection &c);
void append(const ExtrusionEntity &entity);
void append(const ExtrusionEntitiesPtr &entities);

View File

@ -1,6 +1,7 @@
#include "Print.hpp"
#include "BoundingBox.hpp"
#include "ClipperUtils.hpp"
#include "Fill/Fill.hpp"
#include "Flow.hpp"
#include "Geometry.hpp"
#include "SupportMaterial.hpp"
@ -787,6 +788,141 @@ Print::skirt_flow() const
);
}
void
Print::_make_brim()
{
if (this->state.is_done(psBrim)) return;
this->state.set_started(psBrim);
// since this method must be idempotent, we clear brim paths *before*
// checking whether we need to generate them
this->brim.clear();
if (this->config.brim_width == 0 && this->config.brim_connections_width == 0) {
this->state.set_done(psBrim);
return;
}
// brim is only printed on first layer and uses perimeter extruder
const double first_layer_height = this->skirt_first_layer_height();
const Flow flow = this->brim_flow();
const double mm3_per_mm = flow.mm3_per_mm();
const coord_t grow_distance = flow.scaled_width()/2;
Polygons islands;
FOREACH_OBJECT(this, object) {
const Layer &layer0 = *(*object)->get_layer(0);
Polygons object_islands = layer0.slices.contours();
if (!(*object)->support_layers.empty()) {
const SupportLayer &support_layer0 = *(*object)->get_support_layer(0);
for (ExtrusionEntitiesPtr::const_iterator it = support_layer0.support_fills.entities.begin();
it != support_layer0.support_fills.entities.end(); ++it)
append_to(object_islands, offset((*it)->as_polyline(), grow_distance));
for (ExtrusionEntitiesPtr::const_iterator it = support_layer0.support_interface_fills.entities.begin();
it != support_layer0.support_interface_fills.entities.end(); ++it)
append_to(object_islands, offset((*it)->as_polyline(), grow_distance));
}
for (Points::const_iterator copy = (*object)->_shifted_copies.begin(); copy != (*object)->_shifted_copies.end();
++copy) {
for (Polygons::const_iterator p = object_islands.begin(); p != object_islands.end(); ++p) {
Polygon p2 = *p;
p2.translate(*copy);
islands.push_back(p2);
}
}
}
Polygons loops;
const int num_loops = floor(this->config.brim_width / flow.width + 0.5);
for (int i = num_loops; i >= 1; --i) {
// JT_SQUARE ensures no vertex is outside the given offset distance
// -0.5 because islands are not represented by their centerlines
// (first offset more, then step back - reverse order than the one used for
// perimeters because here we're offsetting outwards)
append_to(loops, offset2(
islands,
flow.scaled_spacing() * (i + 0.5),
flow.scaled_spacing() * -1.0,
100000,
ClipperLib::jtSquare
));
}
{
Polygons chained = union_pt_chained(loops);
for (Polygons::const_reverse_iterator p = chained.rbegin(); p != chained.rend(); ++p) {
ExtrusionPath path(erSkirt, mm3_per_mm, flow.width, first_layer_height);
path.polyline = p->split_at_first_point();
this->brim.append(ExtrusionLoop(path));
}
}
if (this->config.brim_connections_width > 0) {
// get islands to connects
for (Polygons::iterator p = islands.begin(); p != islands.end(); ++p)
*p = Geometry::convex_hull(p->points);
islands = offset(islands, flow.scaled_spacing() * (num_loops-0.2), 10000, jtSquare);
// compute centroid for each island
Points centroids;
centroids.reserve(islands.size());
for (Polygons::const_iterator p = islands.begin(); p != islands.end(); ++p)
centroids.push_back(p->centroid());
// in order to check visibility we need to account for the connections width,
// so let's use grown islands
const double scaled_width = scale_(this->config.brim_connections_width);
const Polygons grown = offset(islands, +scaled_width/2);
// find pairs of islands having direct visibility
Lines lines;
for (size_t i = 0; i < islands.size(); ++i) {
for (size_t j = (i+1); j < islands.size(); ++j) {
// check visibility
Line line(centroids[i], centroids[j]);
if (diff_pl((Polyline)line, grown).size() != 1) continue;
lines.push_back(line);
}
}
std::auto_ptr<Fill> filler(Fill::new_from_type(ipRectilinear));
filler->spacing = flow.spacing();
filler->dont_adjust = true;
filler->density = 1;
// subtract already generated connections in order to prevent crossings
// and overextrusion
Polygons other;
for (Lines::const_iterator line = lines.begin(); line != lines.end(); ++line) {
ExPolygons expp = diff_ex(
offset((Polyline)*line, scaled_width/2),
islands + other
);
filler->angle = line->direction();
for (ExPolygons::const_iterator ex = expp.begin(); ex != expp.end(); ++ex) {
append_to(other, (Polygons)*ex);
const Polylines paths = filler->fill_surface(Surface(stBottom, *ex));
for (Polylines::const_iterator pl = paths.begin(); pl != paths.end(); ++pl) {
ExtrusionPath path(erSkirt, mm3_per_mm, flow.width, first_layer_height);
path.polyline = *pl;
this->brim.append(path);
}
}
}
}
this->state.set_done(psBrim);
}
PrintRegionConfig
Print::_region_config_from_model_volume(const ModelVolume &volume)

View File

@ -203,6 +203,7 @@ class Print
double skirt_first_layer_height() const;
Flow brim_flow() const;
Flow skirt_flow() const;
void _make_brim();
std::set<size_t> object_extruders() const;
std::set<size_t> support_material_extruders() const;

View File

@ -228,6 +228,7 @@ _constant()
double skirt_first_layer_height();
Clone<Flow> brim_flow();
Clone<Flow> skirt_flow();
void _make_brim();
%{
double