mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-08-13 07:49:03 +08:00
Ported brim generation to C++/XS
This commit is contained in:
parent
4724f0fb99
commit
12165c727e
@ -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
|
||||
|
@ -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);
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -228,6 +228,7 @@ _constant()
|
||||
double skirt_first_layer_height();
|
||||
Clone<Flow> brim_flow();
|
||||
Clone<Flow> skirt_flow();
|
||||
void _make_brim();
|
||||
%{
|
||||
|
||||
double
|
||||
|
Loading…
x
Reference in New Issue
Block a user