New extrusion class: ExtrusionMultiPath

This is similar to an ExtrusionLoop, but it is open.
It may contain multiple chained paths with differing parameters.
This allows one to have a hierarchy of paths, where the ExtrusionEntityCollection
will be chained by the G-code generator, but ExtrusionMultiPath will not.
This commit is contained in:
bubnikv 2017-01-19 13:35:55 +01:00
parent e6b441eea4
commit e016c4e423
13 changed files with 151 additions and 2 deletions

View File

@ -223,6 +223,7 @@ sub thread_cleanup {
*Slic3r::ExPolygon::Collection::DESTROY = sub {};
*Slic3r::Extruder::DESTROY = sub {};
*Slic3r::ExtrusionLoop::DESTROY = sub {};
*Slic3r::ExtrusionMultiPath::DESTROY = sub {};
*Slic3r::ExtrusionPath::DESTROY = sub {};
*Slic3r::ExtrusionPath::Collection::DESTROY = sub {};
*Slic3r::ExtrusionSimulator::DESTROY = sub {};

View File

@ -488,7 +488,7 @@ sub Render {
sub _draw {
my ($self, $object, $print_z, $path) = @_;
my @paths = $path->isa('Slic3r::ExtrusionLoop')
my @paths = ($path->isa('Slic3r::ExtrusionLoop') || $path->isa('Slic3r::ExtrusionMultiPath'))
? @$path
: ($path);
@ -546,7 +546,7 @@ sub _simulate_extrusion {
push @extrusions, @$_ for @{$layerm->fills};
}
foreach my $extrusion_entity (@extrusions) {
my @paths = $extrusion_entity->isa('Slic3r::ExtrusionLoop')
my @paths = ($extrusion_entity->isa('Slic3r::ExtrusionLoop') || $extrusion_entity->isa('Slic3r::ExtrusionMultiPath'))
? @$extrusion_entity
: ($extrusion_entity);
foreach my $path (@paths) {

View File

@ -185,6 +185,7 @@ xsp/ExPolygonCollection.xsp
xsp/Extruder.xsp
xsp/ExtrusionEntityCollection.xsp
xsp/ExtrusionLoop.xsp
xsp/ExtrusionMultiPath.xsp
xsp/ExtrusionPath.xsp
xsp/ExtrusionSimulator.xsp
xsp/Filler.xsp

View File

@ -107,6 +107,11 @@ sub new_from_paths {
return $loop;
}
package Slic3r::ExtrusionMultiPath;
use overload
'@{}' => sub { $_[0]->arrayref },
'fallback' => 1;
package Slic3r::ExtrusionPath;
use overload
'@{}' => sub { $_[0]->arrayref },

View File

@ -63,6 +63,62 @@ void ExtrusionPath::polygons_covered_by_spacing(Polygons &out, const float scale
polygons_append(out, offset(this->polyline, 0.5f * float(flow.scaled_spacing()) + scaled_epsilon));
}
void ExtrusionMultiPath::reverse()
{
for (ExtrusionPaths::iterator path = this->paths.begin(); path != this->paths.end(); ++path)
path->reverse();
std::reverse(this->paths.begin(), this->paths.end());
}
double ExtrusionMultiPath::length() const
{
double len = 0;
for (ExtrusionPaths::const_iterator path = this->paths.begin(); path != this->paths.end(); ++path)
len += path->polyline.length();
return len;
}
void ExtrusionMultiPath::polygons_covered_by_width(Polygons &out, const float scaled_epsilon) const
{
for (ExtrusionPaths::const_iterator path = this->paths.begin(); path != this->paths.end(); ++path)
path->polygons_covered_by_width(out, scaled_epsilon);
}
void ExtrusionMultiPath::polygons_covered_by_spacing(Polygons &out, const float scaled_epsilon) const
{
for (ExtrusionPaths::const_iterator path = this->paths.begin(); path != this->paths.end(); ++path)
path->polygons_covered_by_spacing(out, scaled_epsilon);
}
double ExtrusionMultiPath::min_mm3_per_mm() const
{
double min_mm3_per_mm = std::numeric_limits<double>::max();
for (ExtrusionPaths::const_iterator path = this->paths.begin(); path != this->paths.end(); ++path)
min_mm3_per_mm = std::min(min_mm3_per_mm, path->mm3_per_mm);
return min_mm3_per_mm;
}
Polyline ExtrusionMultiPath::as_polyline() const
{
size_t len = 0;
for (size_t i_path = 0; i_path < paths.size(); ++ i_path) {
assert(! paths[i_path].polyline.points.empty());
assert(i_path == 0 || paths[i_path - 1].polyline.points.back() == paths[i_path].polyline.points.front());
len += paths[i_path].polyline.points.size();
}
// The connecting points between the segments are equal.
len -= paths.size() - 1;
Polyline out;
if (len > 0) {
out.points.reserve(len);
out.points.push_back(paths.front().polyline.points.front());
for (size_t i_path = 0; i_path < paths.size(); ++ i_path)
out.points.insert(out.points.end(), paths[i_path].polyline.points.begin() + 1, paths[i_path].polyline.points.end());
}
return out;
}
bool
ExtrusionLoop::make_clockwise()
{

View File

@ -133,6 +133,55 @@ public:
typedef std::vector<ExtrusionPath> ExtrusionPaths;
// Single continuous extrusion path, possibly with varying extrusion thickness, extrusion height or bridging / non bridging.
class ExtrusionMultiPath : public ExtrusionEntity
{
public:
ExtrusionPaths paths;
ExtrusionMultiPath() {};
ExtrusionMultiPath(const ExtrusionPaths &paths) : paths(paths) {};
ExtrusionMultiPath(const ExtrusionPath &path) { this->paths.push_back(path); }
bool is_loop() const { return false; }
bool can_reverse() const { return true; }
ExtrusionMultiPath* clone() const { return new ExtrusionMultiPath(*this); }
void reverse();
Point first_point() const { return this->paths.front().polyline.points.front(); }
Point last_point() const { return this->paths.back().polyline.points.back(); }
virtual double length() const;
bool is_perimeter() const {
return this->paths.front().role == erPerimeter
|| this->paths.front().role == erExternalPerimeter
|| this->paths.front().role == erOverhangPerimeter;
}
bool is_infill() const {
return this->paths.front().role == erBridgeInfill
|| this->paths.front().role == erInternalInfill
|| this->paths.front().role == erSolidInfill
|| this->paths.front().role == erTopSolidInfill;
}
bool is_solid_infill() const {
return this->paths.front().role == erBridgeInfill
|| this->paths.front().role == erSolidInfill
|| this->paths.front().role == erTopSolidInfill;
}
// Produce a list of 2D polygons covered by the extruded paths, offsetted by the extrusion width.
// Increase the offset by scaled_epsilon to achieve an overlap, so a union will produce no gaps.
void polygons_covered_by_width(Polygons &out, const float scaled_epsilon) const;
// Produce a list of 2D polygons covered by the extruded paths, offsetted by the extrusion spacing.
// Increase the offset by scaled_epsilon to achieve an overlap, so a union will produce no gaps.
// Useful to calculate area of an infill, which has been really filled in by a 100% rectilinear infill.
void polygons_covered_by_spacing(Polygons &out, const float scaled_epsilon) const;
Polygons polygons_covered_by_width(const float scaled_epsilon = 0.f) const
{ Polygons out; this->polygons_covered_by_width(out, scaled_epsilon); return out; }
Polygons polygons_covered_by_spacing(const float scaled_epsilon = 0.f) const
{ Polygons out; this->polygons_covered_by_spacing(out, scaled_epsilon); return out; }
// Minimum volumetric velocity of this extrusion entity. Used by the constant nozzle pressure algorithm.
double min_mm3_per_mm() const;
Polyline as_polyline() const;
};
// Single continuous extrusion loop, possibly with varying extrusion thickness, extrusion height or bridging / non bridging.
class ExtrusionLoop : public ExtrusionEntity
{
public:

View File

@ -766,11 +766,33 @@ GCode::extrude(ExtrusionLoop loop, std::string description, double speed)
return gcode;
}
std::string
GCode::extrude(ExtrusionMultiPath multipath, std::string description, double speed)
{
// extrude along the path
std::string gcode;
for (ExtrusionPaths::const_iterator path = multipath.paths.begin(); path != multipath.paths.end(); ++path)
// description += ExtrusionLoopRole2String(loop.role);
// description += ExtrusionRole2String(path->role);
gcode += this->_extrude(*path, description, speed);
// reset acceleration
gcode += this->writer.set_acceleration(this->config.default_acceleration.value);
//FIXME perform wipe on multi paths?
// if (this->wipe.enable)
// this->wipe.path = paths.front().polyline; // TODO: don't limit wipe to last path
return gcode;
}
std::string
GCode::extrude(const ExtrusionEntity &entity, std::string description, double speed)
{
if (const ExtrusionPath* path = dynamic_cast<const ExtrusionPath*>(&entity)) {
return this->extrude(*path, description, speed);
} else if (const ExtrusionMultiPath* multipath = dynamic_cast<const ExtrusionMultiPath*>(&entity)) {
return this->extrude(*multipath, description, speed);
} else if (const ExtrusionLoop* loop = dynamic_cast<const ExtrusionLoop*>(&entity)) {
return this->extrude(*loop, description, speed);
} else {

View File

@ -121,6 +121,7 @@ class GCode {
std::string change_layer(const Layer &layer);
std::string extrude(const ExtrusionEntity &entity, std::string description = "", double speed = -1);
std::string extrude(ExtrusionLoop loop, std::string description = "", double speed = -1);
std::string extrude(ExtrusionMultiPath multipath, std::string description = "", double speed = -1);
std::string extrude(const ExtrusionPath &path, std::string description = "", double speed = -1);
std::string travel_to(const Point &point, ExtrusionRole role, std::string comment);
bool needs_retraction(const Polyline &travel, ExtrusionRole role = erNone);

View File

@ -6,6 +6,7 @@ namespace Slic3r {
REGISTER_CLASS(ExPolygon, "ExPolygon");
REGISTER_CLASS(ExPolygonCollection, "ExPolygon::Collection");
REGISTER_CLASS(Extruder, "Extruder");
REGISTER_CLASS(ExtrusionMultiPath, "ExtrusionMultiPath");
REGISTER_CLASS(ExtrusionPath, "ExtrusionPath");
REGISTER_CLASS(ExtrusionLoop, "ExtrusionLoop");
// there is no ExtrusionLoop::Collection or ExtrusionEntity::Collection

View File

@ -53,6 +53,8 @@ ExtrusionEntityCollection::arrayref()
// return our item by reference
if (ExtrusionPath* path = dynamic_cast<ExtrusionPath*>(*it)) {
sv_setref_pv( sv, perl_class_name_ref(path), path );
} else if (ExtrusionMultiPath* multipath = dynamic_cast<ExtrusionMultiPath*>(*it)) {
sv_setref_pv( sv, perl_class_name_ref(multipath), multipath );
} else if (ExtrusionLoop* loop = dynamic_cast<ExtrusionLoop*>(*it)) {
sv_setref_pv( sv, perl_class_name_ref(loop), loop );
} else if (ExtrusionEntityCollection* collection = dynamic_cast<ExtrusionEntityCollection*>(*it)) {
@ -77,6 +79,8 @@ ExtrusionEntityCollection::append(...)
// append COPIES
if (ExtrusionPath* path = dynamic_cast<ExtrusionPath*>(entity)) {
THIS->entities.push_back( new ExtrusionPath(*path) );
} else if (ExtrusionMultiPath* multipath = dynamic_cast<ExtrusionMultiPath*>(entity)) {
THIS->entities.push_back( new ExtrusionMultiPath(*multipath) );
} else if (ExtrusionLoop* loop = dynamic_cast<ExtrusionLoop*>(entity)) {
THIS->entities.push_back( new ExtrusionLoop(*loop) );
} else if(ExtrusionEntityCollection* collection = dynamic_cast<ExtrusionEntityCollection*>(entity)) {

View File

@ -166,6 +166,8 @@
%code{% RETVAL = THIS->change_layer(*layer); %};
%name{extrude_loop} std::string extrude(ExtrusionLoop* loop, std::string description = "", double speed = -1)
%code{% RETVAL = THIS->extrude(*loop, description, speed); %};
%name{extrude_multipath} std::string extrude(ExtrusionMultiPath* multipath, std::string description = "", double speed = -1)
%code{% RETVAL = THIS->extrude(*multipath, description, speed); %};
%name{extrude_path} std::string extrude(ExtrusionPath* path, std::string description = "", double speed = -1)
%code{% RETVAL = THIS->extrude(*path, description, speed); %};
std::string travel_to(Point* point, ExtrusionRole role, std::string comment)

View File

@ -104,6 +104,10 @@ ExtrusionEntityCollection* O_OBJECT_SLIC3R
Ref<ExtrusionEntityCollection> O_OBJECT_SLIC3R_T
Clone<ExtrusionEntityCollection> O_OBJECT_SLIC3R_T
ExtrusionMultiPath* O_OBJECT_SLIC3R
Ref<ExtrusionMultiPath> O_OBJECT_SLIC3R_T
Clone<ExtrusionMultiPath> O_OBJECT_SLIC3R_T
ExtrusionPath* O_OBJECT_SLIC3R
Ref<ExtrusionPath> O_OBJECT_SLIC3R_T
Clone<ExtrusionPath> O_OBJECT_SLIC3R_T

View File

@ -78,6 +78,9 @@
%typemap{ExtrusionEntityCollection*};
%typemap{Ref<ExtrusionEntityCollection>}{simple};
%typemap{Clone<ExtrusionEntityCollection>}{simple};
%typemap{ExtrusionMultiPath*};
%typemap{Ref<ExtrusionMultiPath>}{simple};
%typemap{Clone<ExtrusionMultiPath>}{simple};
%typemap{ExtrusionPath*};
%typemap{Ref<ExtrusionPath>}{simple};
%typemap{Clone<ExtrusionPath>}{simple};