mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-08-14 05:25:58 +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};
|
$_->generate_support_material for @{$self->objects};
|
||||||
$self->make_skirt;
|
$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");
|
$self->status_cb->(88, "Generating brim");
|
||||||
|
$self->_make_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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# this method will return the supplied input file path after expanding its
|
# 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.
|
// Minimum volumetric velocity of this extrusion entity. Used by the constant nozzle pressure algorithm.
|
||||||
double min_mm3_per_mm() const;
|
double min_mm3_per_mm() const;
|
||||||
Polyline as_polyline() const { return this->polygon().split_at_first_point(); }
|
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()
|
ExtrusionEntityCollection::~ExtrusionEntityCollection()
|
||||||
|
{
|
||||||
|
this->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ExtrusionEntityCollection::clear()
|
||||||
{
|
{
|
||||||
for (ExtrusionEntitiesPtr::iterator it = this->entities.begin(); it != this->entities.end(); ++it)
|
for (ExtrusionEntitiesPtr::iterator it = this->entities.begin(); it != this->entities.end(); ++it)
|
||||||
delete *it;
|
delete *it;
|
||||||
|
this->entities.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
ExtrusionEntityCollection::operator ExtrusionPaths() const
|
ExtrusionEntityCollection::operator ExtrusionPaths() const
|
||||||
|
@ -30,9 +30,7 @@ class ExtrusionEntityCollection : public ExtrusionEntity
|
|||||||
bool empty() const {
|
bool empty() const {
|
||||||
return this->entities.empty();
|
return this->entities.empty();
|
||||||
};
|
};
|
||||||
void clear() {
|
void clear();
|
||||||
this->entities.clear();
|
|
||||||
};
|
|
||||||
void swap (ExtrusionEntityCollection &c);
|
void swap (ExtrusionEntityCollection &c);
|
||||||
void append(const ExtrusionEntity &entity);
|
void append(const ExtrusionEntity &entity);
|
||||||
void append(const ExtrusionEntitiesPtr &entities);
|
void append(const ExtrusionEntitiesPtr &entities);
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "Print.hpp"
|
#include "Print.hpp"
|
||||||
#include "BoundingBox.hpp"
|
#include "BoundingBox.hpp"
|
||||||
#include "ClipperUtils.hpp"
|
#include "ClipperUtils.hpp"
|
||||||
|
#include "Fill/Fill.hpp"
|
||||||
#include "Flow.hpp"
|
#include "Flow.hpp"
|
||||||
#include "Geometry.hpp"
|
#include "Geometry.hpp"
|
||||||
#include "SupportMaterial.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
|
PrintRegionConfig
|
||||||
Print::_region_config_from_model_volume(const ModelVolume &volume)
|
Print::_region_config_from_model_volume(const ModelVolume &volume)
|
||||||
|
@ -203,6 +203,7 @@ class Print
|
|||||||
double skirt_first_layer_height() const;
|
double skirt_first_layer_height() const;
|
||||||
Flow brim_flow() const;
|
Flow brim_flow() const;
|
||||||
Flow skirt_flow() const;
|
Flow skirt_flow() const;
|
||||||
|
void _make_brim();
|
||||||
|
|
||||||
std::set<size_t> object_extruders() const;
|
std::set<size_t> object_extruders() const;
|
||||||
std::set<size_t> support_material_extruders() const;
|
std::set<size_t> support_material_extruders() const;
|
||||||
|
@ -228,6 +228,7 @@ _constant()
|
|||||||
double skirt_first_layer_height();
|
double skirt_first_layer_height();
|
||||||
Clone<Flow> brim_flow();
|
Clone<Flow> brim_flow();
|
||||||
Clone<Flow> skirt_flow();
|
Clone<Flow> skirt_flow();
|
||||||
|
void _make_brim();
|
||||||
%{
|
%{
|
||||||
|
|
||||||
double
|
double
|
||||||
|
Loading…
x
Reference in New Issue
Block a user