mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-10-22 16:21:24 -06:00
Merge branch 'master' into sender
This commit is contained in:
commit
005f138ce7
102 changed files with 3245 additions and 1672 deletions
|
@ -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_)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -491,6 +491,12 @@ GCodeWriter::unlift()
|
|||
return gcode;
|
||||
}
|
||||
|
||||
Pointf3
|
||||
GCodeWriter::get_position() const
|
||||
{
|
||||
return this->_pos;
|
||||
}
|
||||
|
||||
#ifdef SLIC3RXS
|
||||
REGISTER_CLASS(GCodeWriter, "GCode::Writer");
|
||||
#endif
|
||||
|
|
|
@ -45,6 +45,7 @@ class GCodeWriter {
|
|||
std::string unretract();
|
||||
std::string lift();
|
||||
std::string unlift();
|
||||
Pointf3 get_position() const;
|
||||
|
||||
private:
|
||||
std::string _extrusion_axis;
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 ¢er)
|
|||
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
|
||||
|
|
|
@ -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 ¢er);
|
||||
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 ¢er);
|
||||
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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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> ®ion_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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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, ¬_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");
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
11
xs/src/libslic3r/SupportMaterial.hpp
Normal file
11
xs/src/libslic3r/SupportMaterial.hpp
Normal 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
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue