Merge branch 'master' into sender

This commit is contained in:
Alessandro Ranellucci 2014-12-26 01:30:48 +01:00
commit 005f138ce7
102 changed files with 3245 additions and 1672 deletions

View file

@ -425,6 +425,18 @@ template void diff<Slic3r::Polygons, Slic3r::Polylines>(const Slic3r::Polygons &
template void diff<Slic3r::Polylines, Slic3r::Polylines>(const Slic3r::Polylines &subject, const Slic3r::Polygons &clip, Slic3r::Polylines* retval, bool safety_offset_);
template void diff<Slic3r::Lines, Slic3r::Lines>(const Slic3r::Lines &subject, const Slic3r::Polygons &clip, Slic3r::Lines* retval, bool safety_offset_);
template <class SubjectType, class ResultType>
void diff(const SubjectType &subject, const Slic3r::ExPolygons &clip, ResultType* retval, bool safety_offset_)
{
Slic3r::Polygons pp;
for (Slic3r::ExPolygons::const_iterator ex = clip.begin(); ex != clip.end(); ++ex) {
Slic3r::Polygons ppp = *ex;
pp.insert(pp.end(), ppp.begin(), ppp.end());
}
diff(subject, pp, retval, safety_offset_);
}
template void diff<Slic3r::Polygons, Slic3r::ExPolygons>(const Slic3r::Polygons &subject, const Slic3r::ExPolygons &clip, Slic3r::ExPolygons* retval, bool safety_offset_);
template <class SubjectType, class ResultType>
void intersection(const SubjectType &subject, const Slic3r::Polygons &clip, ResultType* retval, bool safety_offset_)
{

View file

@ -83,6 +83,9 @@ void _clipper(ClipperLib::ClipType clipType, const Slic3r::Lines &subject,
template <class SubjectType, class ResultType>
void diff(const SubjectType &subject, const Slic3r::Polygons &clip, ResultType* retval, bool safety_offset_ = false);
template <class SubjectType, class ResultType>
void diff(const SubjectType &subject, const Slic3r::ExPolygons &clip, ResultType* retval, bool safety_offset_ = false);
template <class SubjectType, class ResultType>
void intersection(const SubjectType &subject, const Slic3r::Polygons &clip, ResultType* retval, bool safety_offset_ = false);

View file

@ -76,9 +76,18 @@ ExtrusionPath::is_perimeter() const
}
bool
ExtrusionPath::is_fill() const
ExtrusionPath::is_infill() const
{
return this->role == erInternalInfill
return this->role == erBridgeInfill
|| this->role == erInternalInfill
|| this->role == erSolidInfill
|| this->role == erTopSolidInfill;
}
bool
ExtrusionPath::is_solid_infill() const
{
return this->role == erBridgeInfill
|| this->role == erSolidInfill
|| this->role == erTopSolidInfill;
}
@ -235,9 +244,6 @@ ExtrusionLoop::split_at_vertex(const Point &point)
path->polyline.points.insert(path->polyline.points.end(), path->polyline.points.begin() + 1, path->polyline.points.begin() + idx + 1);
path->polyline.points.erase(path->polyline.points.begin(), path->polyline.points.begin() + idx);
} else {
// if we have multiple paths we assume they have different types, so no need to
// check for continuity as we do for the single path case above
// new paths list starts with the second half of current path
ExtrusionPaths new_paths;
{
@ -247,10 +253,10 @@ ExtrusionLoop::split_at_vertex(const Point &point)
}
// then we add all paths until the end of current path list
new_paths.insert(new_paths.end(), this->paths.begin(), path); // not including this path
new_paths.insert(new_paths.end(), path+1, this->paths.end()); // not including this path
// then we add all paths since the beginning of current list up to the previous one
new_paths.insert(new_paths.end(), path+1, this->paths.end()); // not including this path
new_paths.insert(new_paths.end(), this->paths.begin(), path); // not including this path
// finally we add the first half of current path
{
@ -332,6 +338,31 @@ ExtrusionLoop::has_overhang_point(const Point &point) const
return false;
}
bool
ExtrusionLoop::is_perimeter() const
{
return this->paths.front().role == erPerimeter
|| this->paths.front().role == erExternalPerimeter
|| this->paths.front().role == erOverhangPerimeter;
}
bool
ExtrusionLoop::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
ExtrusionLoop::is_solid_infill() const
{
return this->paths.front().role == erBridgeInfill
|| this->paths.front().role == erSolidInfill
|| this->paths.front().role == erTopSolidInfill;
}
#ifdef SLIC3RXS
REGISTER_CLASS(ExtrusionLoop, "ExtrusionLoop");
#endif

View file

@ -64,7 +64,8 @@ class ExtrusionPath : public ExtrusionEntity
void simplify(double tolerance);
double length() const;
bool is_perimeter() const;
bool is_fill() const;
bool is_infill() const;
bool is_solid_infill() const;
bool is_bridge() const;
std::string gcode(Extruder* extruder, double e, double F,
double xofs, double yofs, std::string extrusion_axis,
@ -96,6 +97,9 @@ class ExtrusionLoop : public ExtrusionEntity
void split_at(const Point &point);
void clip_end(double distance, ExtrusionPaths* paths) const;
bool has_overhang_point(const Point &point) const;
bool is_perimeter() const;
bool is_infill() const;
bool is_solid_infill() const;
};
}

View file

@ -13,7 +13,7 @@ Flow::new_from_config_width(FlowRole role, const ConfigOptionFloatOrPercent &wid
float w;
if (bridge_flow_ratio > 0) {
// if bridge flow was requested, calculate bridge width
w = Flow::_bridge_width(nozzle_diameter, bridge_flow_ratio);
height = w = Flow::_bridge_width(nozzle_diameter, bridge_flow_ratio);
} else if (!width.percent && width.value == 0) {
// if user left option to 0, calculate a sane default width
w = Flow::_auto_width(role, nozzle_diameter, height);

View file

@ -491,6 +491,12 @@ GCodeWriter::unlift()
return gcode;
}
Pointf3
GCodeWriter::get_position() const
{
return this->_pos;
}
#ifdef SLIC3RXS
REGISTER_CLASS(GCodeWriter, "GCode::Writer");
#endif

View file

@ -45,6 +45,7 @@ class GCodeWriter {
std::string unretract();
std::string lift();
std::string unlift();
Pointf3 get_position() const;
private:
std::string _extrusion_axis;

View file

@ -120,6 +120,29 @@ Layer::make_slices()
}
}
template <class T>
bool
Layer::any_internal_region_slice_contains(const T &item) const
{
FOREACH_LAYERREGION(this, layerm) {
if ((*layerm)->slices.any_internal_contains(item)) return true;
}
return false;
}
template bool Layer::any_internal_region_slice_contains<Line>(const Line &item) const;
template <class T>
bool
Layer::any_internal_region_fill_surface_contains(const T &item) const
{
FOREACH_LAYERREGION(this, layerm) {
if ((*layerm)->fill_surfaces.any_internal_contains(item)) return true;
}
return false;
}
template bool Layer::any_internal_region_fill_surface_contains<Line>(const Line &item) const;
template bool Layer::any_internal_region_fill_surface_contains<Polyline>(const Polyline &item) const;
#ifdef SLIC3RXS
REGISTER_CLASS(Layer, "Layer");

View file

@ -40,15 +40,18 @@ class LayerRegion
// collection of expolygons representing the bridged areas (thus not
// needing support material)
// (this could be just a Polygons object)
ExPolygonCollection bridged;
// collection of polylines representing the unsupported bridge edges
PolylineCollection unsupported_bridge_edges;
// ordered collection of extrusion paths/loops to build all perimeters
// (this collection contains both ExtrusionPath and ExtrusionLoop objects)
ExtrusionEntityCollection perimeters;
// ordered collection of extrusion paths to fill surfaces
// (this collection contains only ExtrusionEntityCollection objects)
ExtrusionEntityCollection fills;
Flow flow(FlowRole role, bool bridge = false, double width = -1) const;
@ -90,6 +93,8 @@ class Layer {
LayerRegion* add_region(PrintRegion* print_region);
void make_slices();
template <class T> bool any_internal_region_slice_contains(const T &item) const;
template <class T> bool any_internal_region_fill_surface_contains(const T &item) const;
protected:
int _id; // sequential number of layer, 0-based

View file

@ -133,6 +133,12 @@ Line::vector() const
return Vector(this->b.x - this->a.x, this->b.y - this->a.y);
}
Vector
Line::normal() const
{
return Vector((this->b.y - this->a.y), -(this->b.x - this->a.x));
}
#ifdef SLIC3RXS
REGISTER_CLASS(Line, "Line");
@ -178,4 +184,18 @@ Line::to_SV_pureperl() const {
}
#endif
Pointf3
Linef3::intersect_plane(double z) const
{
return Pointf3(
this->a.x + (this->b.x - this->a.x) * (z - this->a.z) / (this->b.z - this->a.z),
this->a.y + (this->b.y - this->a.y) * (z - this->a.z) / (this->b.z - this->a.z),
z
);
}
#ifdef SLIC3RXS
REGISTER_CLASS(Linef3, "Linef3");
#endif
}

View file

@ -7,6 +7,7 @@
namespace Slic3r {
class Line;
class Linef3;
class Polyline;
class Line
@ -34,6 +35,7 @@ class Line
double orientation() const;
double direction() const;
Vector vector() const;
Vector normal() const;
#ifdef SLIC3RXS
void from_SV(SV* line_sv);
@ -45,6 +47,22 @@ class Line
typedef std::vector<Line> Lines;
class Linef3
{
public:
Pointf3 a;
Pointf3 b;
Linef3() {};
explicit Linef3(Pointf3 _a, Pointf3 _b): a(_a), b(_b) {};
Pointf3 intersect_plane(double z) const;
#ifdef SLIC3RXS
void from_SV(SV* line_sv);
void from_SV_check(SV* line_sv);
SV* to_SV_pureperl() const;
#endif
};
}
// start Boost

View file

@ -480,26 +480,31 @@ ModelObject::center_around_origin()
mesh.bounding_box(&bb);
}
// first align to origin on XY
double shift_x = -bb.min.x;
double shift_y = -bb.min.y;
// first align to origin on XYZ
Vectorf3 vector(-bb.min.x, -bb.min.y, -bb.min.z);
// then center it on XY
Sizef3 size = bb.size();
shift_x -= size.x/2;
shift_y -= size.y/2;
vector.x -= size.x/2;
vector.y -= size.y/2;
this->translate(shift_x, shift_y, 0);
this->origin_translation.translate(shift_x, shift_y);
this->translate(vector);
this->origin_translation.translate(vector);
if (!this->instances.empty()) {
for (ModelInstancePtrs::const_iterator i = this->instances.begin(); i != this->instances.end(); ++i) {
(*i)->offset.translate(-shift_x, -shift_y);
(*i)->offset.translate(-vector.x, -vector.y);
}
this->update_bounding_box();
}
}
void
ModelObject::translate(const Vectorf3 &vector)
{
this->translate(vector.x, vector.y, vector.z);
}
void
ModelObject::translate(coordf_t x, coordf_t y, coordf_t z)
{

View file

@ -99,7 +99,7 @@ class ModelObject
center_around_origin() method. Callers might want to apply the same translation
to new volumes before adding them to this object in order to preset alignment
when user expects that. */
Pointf origin_translation;
Pointf3 origin_translation;
// these should be private but we need to expose them via XS until all methods are ported
BoundingBoxf3 _bounding_box;
@ -126,6 +126,7 @@ class ModelObject
void raw_bounding_box(BoundingBoxf3* bb) const;
void instance_bounding_box(size_t instance_idx, BoundingBoxf3* bb) const;
void center_around_origin();
void translate(const Vectorf3 &vector);
void translate(coordf_t x, coordf_t y, coordf_t z);
void scale(const Pointf3 &versor);
size_t materials_count() const;

View file

@ -17,6 +17,8 @@ class MultiPoint
Points points;
operator Points() const;
MultiPoint() {};
explicit MultiPoint(const Points &_points): points(_points) {};
void scale(double factor);
void translate(double x, double y);
void translate(const Point &vector);

View file

@ -41,7 +41,7 @@ Point::translate(double x, double y)
}
void
Point::translate(const Point &vector)
Point::translate(const Vector &vector)
{
this->translate(vector.x, vector.y);
}
@ -160,6 +160,18 @@ Point::ccw(const Line &line) const
return this->ccw(line.a, line.b);
}
// returns the CCW angle between this-p1 and this-p2
// i.e. this assumes a CCW rotation from p1 to p2 around this
double
Point::ccw_angle(const Point &p1, const Point &p2) const
{
double angle = atan2(p1.x - this->x, p1.y - this->y)
- atan2(p2.x - this->x, p2.y - this->y);
// we only want to return only positive angles
return angle <= 0 ? angle + 2*PI : angle;
}
Point
Point::projection_onto(const MultiPoint &poly) const
{
@ -211,6 +223,12 @@ Point::negative() const
return Point(-this->x, -this->y);
}
Vector
Point::vector_to(const Point &point) const
{
return Vector(point.x - this->x, point.y - this->y);
}
Point
operator+(const Point& point1, const Point& point2)
{
@ -286,6 +304,18 @@ Pointf::rotate(double angle, const Pointf &center)
this->y = center.y + cos(angle) * (cur_y - center.y) + sin(angle) * (cur_x - center.x);
}
Pointf
Pointf::negative() const
{
return Pointf(-this->x, -this->y);
}
Vectorf
Pointf::vector_to(const Pointf &point) const
{
return Vectorf(point.x - this->x, point.y - this->y);
}
#ifdef SLIC3RXS
REGISTER_CLASS(Pointf, "Pointf");
@ -333,6 +363,12 @@ Pointf3::scale(double factor)
this->z *= factor;
}
void
Pointf3::translate(const Vectorf3 &vector)
{
this->translate(vector.x, vector.y, vector.z);
}
void
Pointf3::translate(double x, double y, double z)
{
@ -340,6 +376,27 @@ Pointf3::translate(double x, double y, double z)
this->z += z;
}
double
Pointf3::distance_to(const Pointf3 &point) const
{
double dx = ((double)point.x - this->x);
double dy = ((double)point.y - this->y);
double dz = ((double)point.z - this->z);
return sqrt(dx*dx + dy*dy + dz*dz);
}
Pointf3
Pointf3::negative() const
{
return Pointf3(-this->x, -this->y, -this->z);
}
Vectorf3
Pointf3::vector_to(const Pointf3 &point) const
{
return Vectorf3(point.x - this->x, point.y - this->y, point.z - this->z);
}
#ifdef SLIC3RXS
REGISTER_CLASS(Pointf3, "Pointf3");
#endif

View file

@ -14,6 +14,8 @@ class Point;
class Pointf;
class Pointf3;
typedef Point Vector;
typedef Pointf Vectorf;
typedef Pointf3 Vectorf3;
typedef std::vector<Point> Points;
typedef std::vector<Point*> PointPtrs;
typedef std::vector<const Point*> PointConstPtrs;
@ -36,7 +38,7 @@ class Point
std::string wkt() const;
void scale(double factor);
void translate(double x, double y);
void translate(const Point &vector);
void translate(const Vector &vector);
void rotate(double angle, const Point &center);
bool coincides_with(const Point &point) const;
bool coincides_with_epsilon(const Point &point) const;
@ -48,9 +50,11 @@ class Point
double distance_to(const Line &line) const;
double ccw(const Point &p1, const Point &p2) const;
double ccw(const Line &line) const;
double ccw_angle(const Point &p1, const Point &p2) const;
Point projection_onto(const MultiPoint &poly) const;
Point projection_onto(const Line &line) const;
Point negative() const;
Vector vector_to(const Point &point) const;
#ifdef SLIC3RXS
void from_SV(SV* point_sv);
@ -78,6 +82,8 @@ class Pointf
void scale(double factor);
void translate(double x, double y);
void rotate(double angle, const Pointf &center);
Pointf negative() const;
Vectorf vector_to(const Pointf &point) const;
#ifdef SLIC3RXS
bool from_SV(SV* point_sv);
@ -92,7 +98,11 @@ class Pointf3 : public Pointf
coordf_t z;
explicit Pointf3(coordf_t _x = 0, coordf_t _y = 0, coordf_t _z = 0): Pointf(_x, _y), z(_z) {};
void scale(double factor);
void translate(const Vectorf3 &vector);
void translate(double x, double y, double z);
double distance_to(const Pointf3 &point) const;
Pointf3 negative() const;
Vectorf3 vector_to(const Pointf3 &point) const;
};
}

View file

@ -158,8 +158,12 @@ Polygon::contains(const Point &point) const
Polygons
Polygon::simplify(double tolerance) const
{
Polygon p = *this;
p.points = MultiPoint::_douglas_peucker(p.points, tolerance);
// repeat first point at the end in order to apply Douglas-Peucker
// on the whole polygon
Points points = this->points;
points.push_back(points.front());
Polygon p(MultiPoint::_douglas_peucker(points, tolerance));
p.points.pop_back();
Polygons pp;
pp.push_back(p);
@ -222,6 +226,58 @@ Polygon::wkt() const
return wkt.str();
}
// find all concave vertices (i.e. having an internal angle greater than the supplied angle) */
void
Polygon::concave_points(double angle, Points* points) const
{
angle = 2*PI - angle;
// check whether first point forms a concave angle
if (this->points.front().ccw_angle(this->points.back(), *(this->points.begin()+1)) <= angle)
points->push_back(this->points.front());
// check whether points 1..(n-1) form concave angles
for (Points::const_iterator p = this->points.begin()+1; p != this->points.end()-1; ++p) {
if (p->ccw_angle(*(p-1), *(p+1)) <= angle) points->push_back(*p);
}
// check whether last point forms a concave angle
if (this->points.back().ccw_angle(*(this->points.end()-2), this->points.front()) <= angle)
points->push_back(this->points.back());
}
void
Polygon::concave_points(Points* points) const
{
this->concave_points(PI, points);
}
// find all convex vertices (i.e. having an internal angle smaller than the supplied angle) */
void
Polygon::convex_points(double angle, Points* points) const
{
angle = 2*PI - angle;
// check whether first point forms a convex angle
if (this->points.front().ccw_angle(this->points.back(), *(this->points.begin()+1)) >= angle)
points->push_back(this->points.front());
// check whether points 1..(n-1) form convex angles
for (Points::const_iterator p = this->points.begin()+1; p != this->points.end()-1; ++p) {
if (p->ccw_angle(*(p-1), *(p+1)) >= angle) points->push_back(*p);
}
// check whether last point forms a convex angle
if (this->points.back().ccw_angle(*(this->points.end()-2), this->points.front()) >= angle)
points->push_back(this->points.back());
}
void
Polygon::convex_points(Points* points) const
{
this->convex_points(PI, points);
}
#ifdef SLIC3RXS
REGISTER_CLASS(Polygon, "Polygon");

View file

@ -19,6 +19,9 @@ class Polygon : public MultiPoint {
operator Polyline() const;
Point& operator[](Points::size_type idx);
const Point& operator[](Points::size_type idx) const;
Polygon() {};
explicit Polygon(const Points &points): MultiPoint(points) {};
Point last_point() const;
Lines lines() const;
void lines(Lines* lines) const;
@ -38,6 +41,10 @@ class Polygon : public MultiPoint {
void triangulate_convex(Polygons* polygons) const;
Point centroid() const;
std::string wkt() const;
void concave_points(double angle, Points* points) const;
void concave_points(Points* points) const;
void convex_points(double angle, Points* points) const;
void convex_points(Points* points) const;
#ifdef SLIC3RXS
void from_SV_check(SV* poly_sv);

View file

@ -1,7 +1,9 @@
#include "Print.hpp"
#include "BoundingBox.hpp"
#include "ClipperUtils.hpp"
#include "Flow.hpp"
#include "Geometry.hpp"
#include "SupportMaterial.hpp"
#include <algorithm>
namespace Slic3r {
@ -74,46 +76,20 @@ Print::get_object(size_t idx)
return objects.at(idx);
}
PrintObject*
Print::add_object(ModelObject *model_object, const BoundingBoxf3 &modobj_bbox)
{
PrintObject *object = new PrintObject(this, model_object, modobj_bbox);
objects.push_back(object);
// invalidate steps
this->invalidate_step(psSkirt);
this->invalidate_step(psBrim);
return object;
}
PrintObject*
Print::set_new_object(size_t idx, ModelObject *model_object, const BoundingBoxf3 &modobj_bbox)
{
if (idx >= this->objects.size()) throw "bad idx";
PrintObjectPtrs::iterator old_it = this->objects.begin() + idx;
// before deleting object, invalidate all of its steps in order to
// invalidate all of the dependent ones in Print
(*old_it)->invalidate_all_steps();
delete *old_it;
PrintObject *object = new PrintObject(this, model_object, modobj_bbox);
this->objects[idx] = object;
return object;
}
void
Print::delete_object(size_t idx)
{
PrintObjectPtrs::iterator i = this->objects.begin() + idx;
// before deleting object, invalidate all of its steps in order to
// invalidate all of the dependent ones in Print
(*i)->invalidate_all_steps();
// destroy object and remove it from our container
delete *i;
this->objects.erase(i);
// TODO: purge unused regions
this->state.invalidate(psSkirt);
this->state.invalidate(psBrim);
}
void
@ -173,6 +149,7 @@ bool
Print::invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys)
{
std::set<PrintStep> steps;
std::set<PrintObjectStep> osteps;
// this method only accepts PrintConfig option keys
for (std::vector<t_config_option_key>::const_iterator opt_key = opt_keys.begin(); opt_key != opt_keys.end(); ++opt_key) {
@ -223,6 +200,7 @@ Print::invalidate_state_by_config_options(const std::vector<t_config_option_key>
|| *opt_key == "output_filename_format"
|| *opt_key == "perimeter_acceleration"
|| *opt_key == "post_process"
|| *opt_key == "pressure_advance"
|| *opt_key == "retract_before_travel"
|| *opt_key == "retract_layer_change"
|| *opt_key == "retract_length"
@ -245,6 +223,12 @@ Print::invalidate_state_by_config_options(const std::vector<t_config_option_key>
|| *opt_key == "wipe"
|| *opt_key == "z_offset") {
// these options only affect G-code export, so nothing to invalidate
} else if (*opt_key == "first_layer_extrusion_width") {
osteps.insert(posPerimeters);
osteps.insert(posInfill);
osteps.insert(posSupportMaterial);
steps.insert(psSkirt);
steps.insert(psBrim);
} else {
// for legacy, if we can't handle this option let's invalidate all steps
return this->invalidate_all_steps();
@ -255,6 +239,11 @@ Print::invalidate_state_by_config_options(const std::vector<t_config_option_key>
for (std::set<PrintStep>::const_iterator step = steps.begin(); step != steps.end(); ++step) {
if (this->invalidate_step(*step)) invalidated = true;
}
for (std::set<PrintObjectStep>::const_iterator ostep = osteps.begin(); ostep != osteps.end(); ++ostep) {
FOREACH_OBJECT(this, object) {
if ((*object)->invalidate_step(*ostep)) invalidated = true;
}
}
return invalidated;
}
@ -290,6 +279,19 @@ Print::invalidate_all_steps()
return invalidated;
}
// returns true if an object step is done on all objects
// and there's at least one object
bool
Print::step_done(PrintObjectStep step) const
{
if (this->objects.empty()) return false;
FOREACH_OBJECT(this, object) {
if (!(*object)->state.is_done(step))
return false;
}
return true;
}
// returns 0-based indices of used extruders
std::set<size_t>
Print::extruders() const
@ -299,6 +301,7 @@ Print::extruders() const
FOREACH_REGION(this, region) {
extruders.insert((*region)->config.perimeter_extruder - 1);
extruders.insert((*region)->config.infill_extruder - 1);
extruders.insert((*region)->config.solid_infill_extruder - 1);
}
FOREACH_OBJECT(this, object) {
extruders.insert((*object)->config.support_material_extruder - 1);
@ -347,9 +350,23 @@ Print::add_model_object(ModelObject* model_object, int idx)
{
BoundingBoxf3 bb;
model_object->raw_bounding_box(&bb);
o = (idx != -1)
? this->set_new_object(idx, model_object, bb)
: this->add_object(model_object, bb);
if (idx != -1) {
// replacing existing object
PrintObjectPtrs::iterator old_it = this->objects.begin() + idx;
// before deleting object, invalidate all of its steps in order to
// invalidate all of the dependent ones in Print
(*old_it)->invalidate_all_steps();
delete *old_it;
this->objects[idx] = o = new PrintObject(this, model_object, bb);
} else {
o = new PrintObject(this, model_object, bb);
objects.push_back(o);
// invalidate steps
this->invalidate_step(psSkirt);
this->invalidate_step(psBrim);
}
}
for (ModelVolumePtrs::const_iterator v_i = model_object->volumes.begin(); v_i != model_object->volumes.end(); ++v_i) {
@ -446,7 +463,7 @@ Print::apply_config(DynamicPrintConfig config)
std::vector<int> &region_volumes = object->region_volumes[region_id];
for (std::vector<int>::const_iterator volume_id = region_volumes.begin(); volume_id != region_volumes.end(); ++volume_id) {
ModelVolume* volume = object->model_object()->volumes[*volume_id];
ModelVolume* volume = object->model_object()->volumes.at(*volume_id);
PrintRegionConfig new_config = this->_region_config_from_model_volume(*volume);
@ -615,6 +632,112 @@ Print::validate() const
}
}
// the bounding box of objects placed in copies position
// (without taking skirt/brim/support material into account)
BoundingBox
Print::bounding_box() const
{
BoundingBox bb;
FOREACH_OBJECT(this, object) {
for (Points::const_iterator copy = (*object)->_shifted_copies.begin(); copy != (*object)->_shifted_copies.end(); ++copy) {
bb.merge(*copy);
Point p = *copy;
p.translate((*object)->size);
bb.merge(p);
}
}
return bb;
}
// the total bounding box of extrusions, including skirt/brim/support material
// this methods needs to be called even when no steps were processed, so it should
// only use configuration values
BoundingBox
Print::total_bounding_box() const
{
// get objects bounding box
BoundingBox bb = this->bounding_box();
// we need to offset the objects bounding box by at least half the perimeters extrusion width
Flow perimeter_flow = this->objects.front()->get_layer(0)->get_region(0)->flow(frPerimeter);
double extra = perimeter_flow.width/2;
// consider support material
if (this->has_support_material()) {
extra = std::max(extra, SUPPORT_MATERIAL_MARGIN);
}
// consider brim and skirt
if (this->config.brim_width.value > 0) {
Flow brim_flow = this->brim_flow();
extra = std::max(extra, this->config.brim_width.value + brim_flow.width/2);
}
if (this->config.skirts.value > 0) {
Flow skirt_flow = this->skirt_flow();
extra = std::max(
extra,
this->config.brim_width.value
+ this->config.skirt_distance.value
+ this->config.skirts.value * skirt_flow.spacing()
+ skirt_flow.width/2
);
}
if (extra > 0)
bb.offset(scale_(extra));
return bb;
}
double
Print::skirt_first_layer_height() const
{
if (this->objects.empty()) CONFESS("skirt_first_layer_height() can't be called without PrintObjects");
return this->objects.front()->config.get_abs_value("first_layer_height");
}
Flow
Print::brim_flow() const
{
ConfigOptionFloatOrPercent width = this->config.first_layer_extrusion_width;
if (width.value == 0) width = this->regions.front()->config.perimeter_extrusion_width;
/* We currently use a random region's perimeter extruder.
While this works for most cases, we should probably consider all of the perimeter
extruders and take the one with, say, the smallest index.
The same logic should be applied to the code that selects the extruder during G-code
generation as well. */
return Flow::new_from_config_width(
frPerimeter,
width,
this->config.nozzle_diameter.get_at(this->regions.front()->config.perimeter_extruder-1),
this->skirt_first_layer_height(),
0
);
}
Flow
Print::skirt_flow() const
{
ConfigOptionFloatOrPercent width = this->config.first_layer_extrusion_width;
if (width.value == 0) width = this->regions.front()->config.perimeter_extrusion_width;
/* We currently use a random object's support material extruder.
While this works for most cases, we should probably consider all of the support material
extruders and take the one with, say, the smallest index;
The same logic should be applied to the code that selects the extruder during G-code
generation as well. */
return Flow::new_from_config_width(
frPerimeter,
width,
this->config.nozzle_diameter.get_at(this->objects.front()->config.support_material_extruder-1),
this->skirt_first_layer_height(),
0
);
}
PrintRegionConfig
Print::_region_config_from_model_volume(const ModelVolume &volume)
{

View file

@ -5,6 +5,7 @@
#include <set>
#include <vector>
#include <stdexcept>
#include "BoundingBox.hpp"
#include "Flow.hpp"
#include "PrintConfig.hpp"
#include "Point.hpp"
@ -75,8 +76,10 @@ class PrintObject
friend class Print;
public:
// vector of (vectors of volume ids), indexed by region_id
std::vector<std::vector<int> > region_volumes;
// map of (vectors of volume ids), indexed by region_id
/* (we use map instead of vector so that we don't have to worry about
resizing it and the [] operator adds new items automagically) */
std::map< size_t,std::vector<int> > region_volumes;
PrintObjectConfig config;
t_layer_height_ranges layer_height_ranges;
@ -108,17 +111,19 @@ class PrintObject
bool delete_all_copies();
bool set_copies(const Points &points);
bool reload_model_instances();
void bounding_box(BoundingBox* bb) const;
// adds region_id, too, if necessary
void add_region_volume(int region_id, int volume_id);
size_t layer_count();
size_t total_layer_count() const;
size_t layer_count() const;
void clear_layers();
Layer* get_layer(int idx);
Layer* add_layer(int id, coordf_t height, coordf_t print_z, coordf_t slice_z);
void delete_layer(int idx);
size_t support_layer_count();
size_t support_layer_count() const;
void clear_support_layers();
SupportLayer* get_support_layer(int idx);
SupportLayer* add_support_layer(int id, coordf_t height, coordf_t print_z, coordf_t slice_z);
@ -129,6 +134,8 @@ class PrintObject
bool invalidate_step(PrintObjectStep step);
bool invalidate_all_steps();
void bridge_over_infill();
private:
Print* _print;
ModelObject* _model_object;
@ -165,8 +172,6 @@ class Print
// methods for handling objects
void clear_objects();
PrintObject* get_object(size_t idx);
PrintObject* add_object(ModelObject *model_object, const BoundingBoxf3 &modobj_bbox);
PrintObject* set_new_object(size_t idx, ModelObject *model_object, const BoundingBoxf3 &modobj_bbox);
void delete_object(size_t idx);
void reload_object(size_t idx);
@ -178,11 +183,17 @@ class Print
bool invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys);
bool invalidate_step(PrintStep step);
bool invalidate_all_steps();
bool step_done(PrintObjectStep step) const;
void add_model_object(ModelObject* model_object, int idx = -1);
bool apply_config(DynamicPrintConfig config);
void init_extruders();
void validate() const;
BoundingBox bounding_box() const;
BoundingBox total_bounding_box() const;
double skirt_first_layer_height() const;
Flow brim_flow() const;
Flow skirt_flow() const;
std::set<size_t> extruders() const;
void _simplify_slices(double distance);

View file

@ -115,6 +115,24 @@ PrintConfigDef::build_def() {
Options["end_gcode"].full_width = true;
Options["end_gcode"].height = 120;
Options["external_fill_pattern"].type = coEnum;
Options["external_fill_pattern"].label = "Top/bottom fill pattern";
Options["external_fill_pattern"].category = "Infill";
Options["external_fill_pattern"].tooltip = "Fill pattern for top/bottom infill. This only affects the external visible layer, and not its adjacent solid shells.";
Options["external_fill_pattern"].cli = "external-fill-pattern=s";
Options["external_fill_pattern"].enum_keys_map = ConfigOptionEnum<InfillPattern>::get_enum_values();
Options["external_fill_pattern"].enum_values.push_back("rectilinear");
Options["external_fill_pattern"].enum_values.push_back("concentric");
Options["external_fill_pattern"].enum_values.push_back("hilbertcurve");
Options["external_fill_pattern"].enum_values.push_back("archimedeanchords");
Options["external_fill_pattern"].enum_values.push_back("octagramspiral");
Options["external_fill_pattern"].enum_labels.push_back("rectilinear");
Options["external_fill_pattern"].enum_labels.push_back("concentric");
Options["external_fill_pattern"].enum_labels.push_back("hilbertcurve (slow)");
Options["external_fill_pattern"].enum_labels.push_back("archimedeanchords (slow)");
Options["external_fill_pattern"].enum_labels.push_back("octagramspiral (slow)");
Options["external_fill_pattern"].aliases.push_back("solid_fill_pattern");
Options["external_perimeter_extrusion_width"].type = coFloatOrPercent;
Options["external_perimeter_extrusion_width"].label = "External perimeters";
Options["external_perimeter_extrusion_width"].category = "Extrusion Width";
@ -280,9 +298,9 @@ PrintConfigDef::build_def() {
Options["fill_pattern"].enum_labels.push_back("concentric");
Options["fill_pattern"].enum_labels.push_back("honeycomb");
Options["fill_pattern"].enum_labels.push_back("3D honeycomb");
Options["fill_pattern"].enum_labels.push_back("hilbertcurve (slow)");
Options["fill_pattern"].enum_labels.push_back("archimedeanchords (slow)");
Options["fill_pattern"].enum_labels.push_back("octagramspiral (slow)");
Options["fill_pattern"].enum_labels.push_back("hilbertcurve");
Options["fill_pattern"].enum_labels.push_back("archimedeanchords");
Options["fill_pattern"].enum_labels.push_back("octagramspiral");
Options["first_layer_acceleration"].type = coFloat;
Options["first_layer_acceleration"].label = "First layer";
@ -511,7 +529,7 @@ PrintConfigDef::build_def() {
Options["perimeter_extruder"].type = coInt;
Options["perimeter_extruder"].label = "Perimeter extruder";
Options["perimeter_extruder"].category = "Extruders";
Options["perimeter_extruder"].tooltip = "The extruder to use when printing perimeters. First extruder is 1.";
Options["perimeter_extruder"].tooltip = "The extruder to use when printing perimeters and brim. First extruder is 1.";
Options["perimeter_extruder"].cli = "perimeter-extruder=i";
Options["perimeter_extruder"].aliases.push_back("perimeters_extruder");
Options["perimeter_extruder"].min = 1;
@ -534,9 +552,10 @@ PrintConfigDef::build_def() {
Options["perimeter_speed"].min = 0;
Options["perimeters"].type = coInt;
Options["perimeters"].label = "Perimeters (minimum)";
Options["perimeters"].label = "Perimeters";
Options["perimeters"].category = "Layers and Perimeters";
Options["perimeters"].tooltip = "This option sets the number of perimeters to generate for each layer. Note that Slic3r may increase this number automatically when it detects sloping surfaces which benefit from a higher number of perimeters if the Extra Perimeters option is enabled.";
Options["perimeters"].sidetext = "(minimum)";
Options["perimeters"].cli = "perimeters=i";
Options["perimeters"].aliases.push_back("perimeter_offsets");
Options["perimeters"].min = 0;
@ -646,8 +665,8 @@ PrintConfigDef::build_def() {
Options["skirt_height"].cli = "skirt-height=i";
Options["skirts"].type = coInt;
Options["skirts"].label = "Loops";
Options["skirts"].tooltip = "Number of loops for this skirt, in other words its thickness. Set this to zero to disable skirt.";
Options["skirts"].label = "Loops (minimum)";
Options["skirts"].tooltip = "Number of loops for the skirt. If the Minimum Extrusion Length option is set, the number of loops might be greater than the one configured here. Set this to zero to disable skirt completely.";
Options["skirts"].cli = "skirts=i";
Options["skirts"].min = 0;
@ -668,23 +687,6 @@ PrintConfigDef::build_def() {
Options["small_perimeter_speed"].cli = "small-perimeter-speed=s";
Options["small_perimeter_speed"].ratio_over = "perimeter_speed";
Options["solid_fill_pattern"].type = coEnum;
Options["solid_fill_pattern"].label = "Top/bottom fill pattern";
Options["solid_fill_pattern"].category = "Infill";
Options["solid_fill_pattern"].tooltip = "Fill pattern for top/bottom infill.";
Options["solid_fill_pattern"].cli = "solid-fill-pattern=s";
Options["solid_fill_pattern"].enum_keys_map = ConfigOptionEnum<InfillPattern>::get_enum_values();
Options["solid_fill_pattern"].enum_values.push_back("rectilinear");
Options["solid_fill_pattern"].enum_values.push_back("concentric");
Options["solid_fill_pattern"].enum_values.push_back("hilbertcurve");
Options["solid_fill_pattern"].enum_values.push_back("archimedeanchords");
Options["solid_fill_pattern"].enum_values.push_back("octagramspiral");
Options["solid_fill_pattern"].enum_labels.push_back("rectilinear");
Options["solid_fill_pattern"].enum_labels.push_back("concentric");
Options["solid_fill_pattern"].enum_labels.push_back("hilbertcurve (slow)");
Options["solid_fill_pattern"].enum_labels.push_back("archimedeanchords (slow)");
Options["solid_fill_pattern"].enum_labels.push_back("octagramspiral (slow)");
Options["solid_infill_below_area"].type = coFloat;
Options["solid_infill_below_area"].label = "Solid infill threshold area";
Options["solid_infill_below_area"].category = "Infill";
@ -693,6 +695,13 @@ PrintConfigDef::build_def() {
Options["solid_infill_below_area"].cli = "solid-infill-below-area=f";
Options["solid_infill_below_area"].min = 0;
Options["solid_infill_extruder"].type = coInt;
Options["solid_infill_extruder"].label = "Solid infill extruder";
Options["solid_infill_extruder"].category = "Extruders";
Options["solid_infill_extruder"].tooltip = "The extruder to use when printing solid infill.";
Options["solid_infill_extruder"].cli = "solid-infill-extruder=i";
Options["solid_infill_extruder"].min = 1;
Options["solid_infill_every_layers"].type = coInt;
Options["solid_infill_every_layers"].label = "Solid infill every";
Options["solid_infill_every_layers"].category = "Infill";
@ -771,9 +780,9 @@ PrintConfigDef::build_def() {
Options["support_material_enforce_layers"].min = 0;
Options["support_material_extruder"].type = coInt;
Options["support_material_extruder"].label = "Support material extruder";
Options["support_material_extruder"].label = "Support material/raft/skirt extruder";
Options["support_material_extruder"].category = "Extruders";
Options["support_material_extruder"].tooltip = "The extruder to use when printing support material. This affects brim and raft too.";
Options["support_material_extruder"].tooltip = "The extruder to use when printing support material, raft and skirt.";
Options["support_material_extruder"].cli = "support-material-extruder=i";
Options["support_material_extruder"].min = 1;
@ -785,7 +794,7 @@ PrintConfigDef::build_def() {
Options["support_material_extrusion_width"].cli = "support-material-extrusion-width=s";
Options["support_material_interface_extruder"].type = coInt;
Options["support_material_interface_extruder"].label = "Support material interface extruder";
Options["support_material_interface_extruder"].label = "Support material/raft interface extruder";
Options["support_material_interface_extruder"].category = "Extruders";
Options["support_material_interface_extruder"].tooltip = "The extruder to use when printing support material interface. This affects raft too.";
Options["support_material_interface_extruder"].cli = "support-material-interface-extruder=i";
@ -871,8 +880,7 @@ PrintConfigDef::build_def() {
Options["threads"].type = coInt;
Options["threads"].label = "Threads";
Options["threads"].tooltip = "Threads are used to parallelize long-running tasks. Optimal threads number is slightly above the number of available cores/processors. Beware that more threads consume more memory.";
Options["threads"].sidetext = "(more speed but more memory usage)";
Options["threads"].tooltip = "Threads are used to parallelize long-running tasks. Optimal threads number is slightly above the number of available cores/processors.";
Options["threads"].cli = "threads|j=i";
Options["threads"].readonly = true;
Options["threads"].min = 1;

View file

@ -93,6 +93,10 @@ class DynamicPrintConfig : public DynamicConfig
this->option("support_material_interface_extruder", true)->setInt(extruder);
}
}
if (!this->has("solid_infill_extruder") && this->has("infill_extruder"))
this->option("solid_infill_extruder", true)->setInt(this->option("infill_extruder")->getInt());
if (this->has("spiral_vase") && this->opt<ConfigOptionBool>("spiral_vase", true)->value) {
{
// this should be actually done only on the spiral layers instead of all
@ -205,6 +209,7 @@ class PrintRegionConfig : public virtual StaticPrintConfig
ConfigOptionInt bottom_solid_layers;
ConfigOptionFloat bridge_flow_ratio;
ConfigOptionFloat bridge_speed;
ConfigOptionEnum<InfillPattern> external_fill_pattern;
ConfigOptionFloatOrPercent external_perimeter_extrusion_width;
ConfigOptionFloatOrPercent external_perimeter_speed;
ConfigOptionBool external_perimeters_first;
@ -223,8 +228,8 @@ class PrintRegionConfig : public virtual StaticPrintConfig
ConfigOptionFloat perimeter_speed;
ConfigOptionInt perimeters;
ConfigOptionFloatOrPercent small_perimeter_speed;
ConfigOptionEnum<InfillPattern> solid_fill_pattern;
ConfigOptionFloat solid_infill_below_area;
ConfigOptionInt solid_infill_extruder;
ConfigOptionFloatOrPercent solid_infill_extrusion_width;
ConfigOptionInt solid_infill_every_layers;
ConfigOptionFloatOrPercent solid_infill_speed;
@ -237,6 +242,7 @@ class PrintRegionConfig : public virtual StaticPrintConfig
this->bottom_solid_layers.value = 3;
this->bridge_flow_ratio.value = 1;
this->bridge_speed.value = 60;
this->external_fill_pattern.value = ipRectilinear;
this->external_perimeter_extrusion_width.value = 0;
this->external_perimeter_extrusion_width.percent = false;
this->external_perimeter_speed.value = 70;
@ -258,9 +264,9 @@ class PrintRegionConfig : public virtual StaticPrintConfig
this->perimeter_extrusion_width.percent = false;
this->perimeter_speed.value = 30;
this->perimeters.value = 3;
this->solid_infill_extruder.value = 1;
this->small_perimeter_speed.value = 30;
this->small_perimeter_speed.percent = false;
this->solid_fill_pattern.value = ipRectilinear;
this->solid_infill_below_area.value = 70;
this->solid_infill_extrusion_width.value = 0;
this->solid_infill_extrusion_width.percent = false;
@ -279,6 +285,7 @@ class PrintRegionConfig : public virtual StaticPrintConfig
if (opt_key == "bottom_solid_layers") return &this->bottom_solid_layers;
if (opt_key == "bridge_flow_ratio") return &this->bridge_flow_ratio;
if (opt_key == "bridge_speed") return &this->bridge_speed;
if (opt_key == "external_fill_pattern") return &this->external_fill_pattern;
if (opt_key == "external_perimeter_extrusion_width") return &this->external_perimeter_extrusion_width;
if (opt_key == "external_perimeter_speed") return &this->external_perimeter_speed;
if (opt_key == "external_perimeters_first") return &this->external_perimeters_first;
@ -297,8 +304,8 @@ class PrintRegionConfig : public virtual StaticPrintConfig
if (opt_key == "perimeter_speed") return &this->perimeter_speed;
if (opt_key == "perimeters") return &this->perimeters;
if (opt_key == "small_perimeter_speed") return &this->small_perimeter_speed;
if (opt_key == "solid_fill_pattern") return &this->solid_fill_pattern;
if (opt_key == "solid_infill_below_area") return &this->solid_infill_below_area;
if (opt_key == "solid_infill_extruder") return &this->solid_infill_extruder;
if (opt_key == "solid_infill_extrusion_width") return &this->solid_infill_extrusion_width;
if (opt_key == "solid_infill_every_layers") return &this->solid_infill_every_layers;
if (opt_key == "solid_infill_speed") return &this->solid_infill_speed;

View file

@ -1,5 +1,6 @@
#include "Print.hpp"
#include "BoundingBox.hpp"
#include "ClipperUtils.hpp"
#include "Geometry.hpp"
namespace Slic3r {
@ -9,8 +10,6 @@ PrintObject::PrintObject(Print* print, ModelObject* model_object, const Bounding
_model_object(model_object),
typed_slices(false)
{
region_volumes.resize(this->_print->regions.size());
// Compute the translation to be applied to our meshes so that we work with smaller coordinates
{
// Translate meshes so that our toolpath generation algorithms work with smaller
@ -111,18 +110,33 @@ PrintObject::reload_model_instances()
return this->set_copies(copies);
}
void
PrintObject::bounding_box(BoundingBox* bb) const
{
// since the object is aligned to origin, bounding box coincides with size
Points pp;
pp.push_back(Point(0,0));
pp.push_back(this->size);
*bb = BoundingBox(pp);
}
void
PrintObject::add_region_volume(int region_id, int volume_id)
{
if (region_id >= region_volumes.size()) {
region_volumes.resize(region_id + 1);
}
region_volumes[region_id].push_back(volume_id);
}
/* This is the *total* layer count (including support layers)
this value is not supposed to be compared with Layer::id
since they have different semantics */
size_t
PrintObject::layer_count()
PrintObject::total_layer_count() const
{
return this->layer_count() + this->support_layer_count();
}
size_t
PrintObject::layer_count() const
{
return this->layers.size();
}
@ -157,7 +171,7 @@ PrintObject::delete_layer(int idx)
}
size_t
PrintObject::support_layer_count()
PrintObject::support_layer_count() const
{
return this->support_layers.size();
}
@ -203,6 +217,7 @@ PrintObject::invalidate_state_by_config_options(const std::vector<t_config_optio
|| *opt_key == "extra_perimeters"
|| *opt_key == "gap_fill_speed"
|| *opt_key == "overhangs"
|| *opt_key == "first_layer_extrusion_width"
|| *opt_key == "perimeter_extrusion_width"
|| *opt_key == "thin_walls"
|| *opt_key == "external_perimeters_first") {
@ -224,22 +239,25 @@ PrintObject::invalidate_state_by_config_options(const std::vector<t_config_optio
|| *opt_key == "support_material_pattern"
|| *opt_key == "support_material_spacing"
|| *opt_key == "support_material_threshold"
|| *opt_key == "dont_support_bridges") {
|| *opt_key == "dont_support_bridges"
|| *opt_key == "first_layer_extrusion_width") {
steps.insert(posSupportMaterial);
} else if (*opt_key == "interface_shells"
|| *opt_key == "infill_only_where_needed"
|| *opt_key == "infill_every_layers"
|| *opt_key == "solid_infill_every_layers"
|| *opt_key == "bottom_solid_layers"
|| *opt_key == "top_solid_layers"
|| *opt_key == "solid_infill_below_area"
|| *opt_key == "infill_extruder"
|| *opt_key == "solid_infill_extruder"
|| *opt_key == "infill_extrusion_width") {
steps.insert(posPrepareInfill);
} else if (*opt_key == "fill_angle"
} else if (*opt_key == "external_fill_pattern"
|| *opt_key == "fill_angle"
|| *opt_key == "fill_pattern"
|| *opt_key == "solid_fill_pattern"
|| *opt_key == "infill_every_layers"
|| *opt_key == "solid_infill_every_layers"
|| *opt_key == "top_infill_extrusion_width") {
|| *opt_key == "top_infill_extrusion_width"
|| *opt_key == "first_layer_extrusion_width") {
steps.insert(posInfill);
} else if (*opt_key == "fill_density"
|| *opt_key == "solid_infill_extrusion_width") {
@ -315,6 +333,93 @@ PrintObject::invalidate_all_steps()
return invalidated;
}
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 || fill_density == 0) continue;
FOREACH_LAYER(this, layer_it) {
if (layer_it == this->layers.begin()) continue;
Layer* layer = *layer_it;
Layer* lower_layer = *(layer_it - 1);
LayerRegion* layerm = layer->get_region(region_id);
// compute the areas needing bridge math
Polygons internal_solid, lower_internal;
layerm->fill_surfaces.filter_by_type(stInternalSolid, &internal_solid);
FOREACH_LAYERREGION(lower_layer, lower_layerm_it)
(*lower_layerm_it)->fill_surfaces.filter_by_type(stInternal, &lower_internal);
ExPolygons to_bridge;
intersection(internal_solid, lower_internal, &to_bridge);
if (to_bridge.empty()) continue;
ExPolygons not_to_bridge;
diff(internal_solid, to_bridge, &not_to_bridge, true);
#ifdef SLIC3R_DEBUG
printf("Bridging %zu internal areas at layer %d\n", to_bridge.size(), layer->id());
#endif
// build the new collection of fill_surfaces
{
Surfaces new_surfaces;
for (Surfaces::const_iterator surface = layerm->fill_surfaces.surfaces.begin(); surface != layerm->fill_surfaces.surfaces.end(); ++surface) {
if (surface->surface_type != stInternalSolid)
new_surfaces.push_back(*surface);
}
for (ExPolygons::const_iterator ex = to_bridge.begin(); ex != to_bridge.end(); ++ex)
new_surfaces.push_back(Surface(stInternalBridge, *ex));
for (ExPolygons::const_iterator ex = not_to_bridge.begin(); ex != not_to_bridge.end(); ++ex)
new_surfaces.push_back(Surface(stInternalSolid, *ex));
layerm->fill_surfaces.surfaces = new_surfaces;
}
/*
# exclude infill from the layers below if needed
# see discussion at https://github.com/alexrj/Slic3r/issues/240
# Update: do not exclude any infill. Sparse infill is able to absorb the excess material.
if (0) {
my $excess = $layerm->extruders->{infill}->bridge_flow->width - $layerm->height;
for (my $i = $layer_id-1; $excess >= $self->get_layer($i)->height; $i--) {
Slic3r::debugf " skipping infill below those areas at layer %d\n", $i;
foreach my $lower_layerm (@{$self->get_layer($i)->regions}) {
my @new_surfaces = ();
# subtract the area from all types of surfaces
foreach my $group (@{$lower_layerm->fill_surfaces->group}) {
push @new_surfaces, map $group->[0]->clone(expolygon => $_),
@{diff_ex(
[ map $_->p, @$group ],
[ map @$_, @$to_bridge ],
)};
push @new_surfaces, map Slic3r::Surface->new(
expolygon => $_,
surface_type => S_TYPE_INTERNALVOID,
), @{intersection_ex(
[ map $_->p, @$group ],
[ map @$_, @$to_bridge ],
)};
}
$lower_layerm->fill_surfaces->clear;
$lower_layerm->fill_surfaces->append($_) for @new_surfaces;
}
$excess -= $self->get_layer($i)->height;
}
}
*/
}
}
}
#ifdef SLIC3RXS
REGISTER_CLASS(PrintObject, "Print::Object");

View file

@ -53,8 +53,10 @@ PrintRegion::flow(FlowRole role, double layer_height, bool bridge, bool first_la
size_t extruder; // 1-based
if (role == frPerimeter || role == frExternalPerimeter) {
extruder = this->config.perimeter_extruder;
} else if (role == frInfill || role == frSolidInfill || role == frTopSolidInfill) {
} else if (role == frInfill) {
extruder = this->config.infill_extruder;
} else if (role == frSolidInfill || role == frTopSolidInfill) {
extruder = this->config.solid_infill_extruder;
} else {
CONFESS("Unknown role $role");
}

View file

@ -0,0 +1,11 @@
#ifndef slic3r_SupportMaterial_hpp_
#define slic3r_SupportMaterial_hpp_
namespace Slic3r {
// how much we extend support around the actual contact area
#define SUPPORT_MATERIAL_MARGIN 1.5
}
#endif

View file

@ -14,7 +14,8 @@ Surface::is_solid() const
return this->surface_type == stTop
|| this->surface_type == stBottom
|| this->surface_type == stBottomBridge
|| this->surface_type == stInternalSolid;
|| this->surface_type == stInternalSolid
|| this->surface_type == stInternalBridge;
}
bool
@ -25,6 +26,15 @@ Surface::is_external() const
|| this->surface_type == stBottomBridge;
}
bool
Surface::is_internal() const
{
return this->surface_type == stInternal
|| this->surface_type == stInternalBridge
|| this->surface_type == stInternalSolid
|| this->surface_type == stInternalVoid;
}
bool
Surface::is_bottom() const
{

View file

@ -24,6 +24,7 @@ class Surface
double area() const;
bool is_solid() const;
bool is_external() const;
bool is_internal() const;
bool is_bottom() const;
bool is_bridge() const;

View file

@ -68,6 +68,39 @@ SurfaceCollection::group(std::vector<SurfacesPtr> *retval)
}
}
template <class T>
bool
SurfaceCollection::any_internal_contains(const T &item) const
{
for (Surfaces::const_iterator surface = this->surfaces.begin(); surface != this->surfaces.end(); ++surface) {
if (surface->is_internal() && surface->expolygon.contains(item)) return true;
}
return false;
}
template bool SurfaceCollection::any_internal_contains<Line>(const Line &item) const;
template bool SurfaceCollection::any_internal_contains<Polyline>(const Polyline &item) const;
SurfacesPtr
SurfaceCollection::filter_by_type(SurfaceType type)
{
SurfacesPtr ss;
for (Surfaces::iterator surface = this->surfaces.begin(); surface != this->surfaces.end(); ++surface) {
if (surface->surface_type == type) ss.push_back(&*surface);
}
return ss;
}
void
SurfaceCollection::filter_by_type(SurfaceType type, Polygons* polygons)
{
for (Surfaces::iterator surface = this->surfaces.begin(); surface != this->surfaces.end(); ++surface) {
if (surface->surface_type == type) {
Polygons pp = surface->expolygon;
polygons->insert(polygons->end(), pp.begin(), pp.end());
}
}
}
#ifdef SLIC3RXS
REGISTER_CLASS(SurfaceCollection, "Surface::Collection");
#endif

View file

@ -15,6 +15,9 @@ class SurfaceCollection
operator ExPolygons() const;
void simplify(double tolerance);
void group(std::vector<SurfacesPtr> *retval);
template <class T> bool any_internal_contains(const T &item) const;
SurfacesPtr filter_by_type(SurfaceType type);
void filter_by_type(SurfaceType type, Polygons* polygons);
};
}