Disabled asserts in the release build (-DNDEBUG).
Added a safe variant of offset(const Slic3r::ExPolygon...), which offsets each loop separately. New functions "remove_sticks" to remove zero area parts of polygons. New functions "remove_small" and "remove_degenerate" for polygon clean up. Extended the C++ supports, those are not finalized yet though.
This commit is contained in:
parent
53907a9cfe
commit
f788f50b5a
@ -180,6 +180,9 @@ if ($ENV{SLIC3R_DEBUG}) {
|
||||
# only on newer GCCs: -ftemplate-backtrace-limit=0
|
||||
push @cflags, '-DSLIC3R_DEBUG';
|
||||
push @cflags, $cpp_guess->is_msvc ? '-Gd' : '-g';
|
||||
} else {
|
||||
# Disable asserts in the release builds.
|
||||
push @cflags, '-DNDEBUG';
|
||||
}
|
||||
if ($cpp_guess->is_gcc) {
|
||||
# check whether we're dealing with a buggy GCC version
|
||||
|
@ -39,9 +39,9 @@ void
|
||||
ClipperPath_to_Slic3rMultiPoint(const ClipperLib::Path &input, T* output)
|
||||
{
|
||||
output->points.clear();
|
||||
for (ClipperLib::Path::const_iterator pit = input.begin(); pit != input.end(); ++pit) {
|
||||
output->points.reserve(input.size());
|
||||
for (ClipperLib::Path::const_iterator pit = input.begin(); pit != input.end(); ++pit)
|
||||
output->points.push_back(Slic3r::Point( (*pit).X, (*pit).Y ));
|
||||
}
|
||||
}
|
||||
template void ClipperPath_to_Slic3rMultiPoint<Slic3r::Polygon>(const ClipperLib::Path &input, Slic3r::Polygon* output);
|
||||
|
||||
@ -50,6 +50,7 @@ void
|
||||
ClipperPaths_to_Slic3rMultiPoints(const ClipperLib::Paths &input, T* output)
|
||||
{
|
||||
output->clear();
|
||||
output->reserve(input.size());
|
||||
for (ClipperLib::Paths::const_iterator it = input.begin(); it != input.end(); ++it) {
|
||||
typename T::value_type p;
|
||||
ClipperPath_to_Slic3rMultiPoint(*it, &p);
|
||||
@ -78,9 +79,18 @@ void
|
||||
Slic3rMultiPoint_to_ClipperPath(const Slic3r::MultiPoint &input, ClipperLib::Path* output)
|
||||
{
|
||||
output->clear();
|
||||
for (Slic3r::Points::const_iterator pit = input.points.begin(); pit != input.points.end(); ++pit) {
|
||||
output->reserve(input.points.size());
|
||||
for (Slic3r::Points::const_iterator pit = input.points.begin(); pit != input.points.end(); ++pit)
|
||||
output->push_back(ClipperLib::IntPoint( (*pit).x, (*pit).y ));
|
||||
}
|
||||
|
||||
void
|
||||
Slic3rMultiPoint_to_ClipperPath_reversed(const Slic3r::MultiPoint &input, ClipperLib::Path* output)
|
||||
{
|
||||
output->clear();
|
||||
output->reserve(input.points.size());
|
||||
for (Slic3r::Points::const_reverse_iterator pit = input.points.rbegin(); pit != input.points.rend(); ++pit)
|
||||
output->push_back(ClipperLib::IntPoint( (*pit).x, (*pit).y ));
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
@ -88,18 +98,33 @@ void
|
||||
Slic3rMultiPoints_to_ClipperPaths(const T &input, ClipperLib::Paths* output)
|
||||
{
|
||||
output->clear();
|
||||
output->reserve(input.size());
|
||||
for (typename T::const_iterator it = input.begin(); it != input.end(); ++it) {
|
||||
// std::vector< IntPoint >, IntPoint is a pair of int64_t
|
||||
ClipperLib::Path p;
|
||||
Slic3rMultiPoint_to_ClipperPath(*it, &p);
|
||||
output->push_back(p);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
scaleClipperPolygon(ClipperLib::Path &polygon, const double scale)
|
||||
{
|
||||
for (ClipperLib::Path::iterator pit = polygon.begin(); pit != polygon.end(); ++pit) {
|
||||
//FIXME multiplication of int64_t by double!
|
||||
// Replace by bit shifts?
|
||||
(*pit).X *= scale;
|
||||
(*pit).Y *= scale;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
scaleClipperPolygons(ClipperLib::Paths &polygons, const double scale)
|
||||
{
|
||||
for (ClipperLib::Paths::iterator it = polygons.begin(); it != polygons.end(); ++it) {
|
||||
for (ClipperLib::Path::iterator pit = (*it).begin(); pit != (*it).end(); ++pit) {
|
||||
//FIXME multiplication of int64_t by double!
|
||||
// Replace by bit shifts?
|
||||
(*pit).X *= scale;
|
||||
(*pit).Y *= scale;
|
||||
}
|
||||
@ -219,6 +244,76 @@ offset(const Slic3r::Polygons &polygons, Slic3r::ExPolygons* retval, const float
|
||||
ClipperPaths_to_Slic3rExPolygons(output, retval);
|
||||
}
|
||||
|
||||
// This is a safe variant of the polygon offset, tailored for a single ExPolygon:
|
||||
// a single polygon with multiple non-overlapping holes.
|
||||
// Each contour and hole is offsetted separately, then the holes are subtracted from the outer contours.
|
||||
void offset(const Slic3r::ExPolygon &expolygon, ClipperLib::Paths* retval, const float delta,
|
||||
double scale, ClipperLib::JoinType joinType, double miterLimit)
|
||||
{
|
||||
// printf("new ExPolygon offset\n");
|
||||
// 1) Offset the outer contour.
|
||||
const float delta_scaled = float(delta * scale);
|
||||
ClipperLib::Paths contours;
|
||||
{
|
||||
ClipperLib::Path input;
|
||||
Slic3rMultiPoint_to_ClipperPath(expolygon.contour, &input);
|
||||
scaleClipperPolygon(input, scale);
|
||||
ClipperLib::ClipperOffset co;
|
||||
if (joinType == jtRound)
|
||||
co.ArcTolerance = miterLimit;
|
||||
else
|
||||
co.MiterLimit = miterLimit;
|
||||
co.AddPath(input, joinType, ClipperLib::etClosedPolygon);
|
||||
co.Execute(contours, delta_scaled);
|
||||
}
|
||||
|
||||
// 2) Offset the holes one by one, collect the results.
|
||||
ClipperLib::Paths holes;
|
||||
{
|
||||
holes.reserve(expolygon.holes.size());
|
||||
for (Polygons::const_iterator it_hole = expolygon.holes.begin(); it_hole != expolygon.holes.end(); ++ it_hole) {
|
||||
ClipperLib::Path input;
|
||||
Slic3rMultiPoint_to_ClipperPath_reversed(*it_hole, &input);
|
||||
scaleClipperPolygon(input, scale);
|
||||
ClipperLib::ClipperOffset co;
|
||||
if (joinType == jtRound)
|
||||
co.ArcTolerance = miterLimit;
|
||||
else
|
||||
co.MiterLimit = miterLimit;
|
||||
co.AddPath(input, joinType, ClipperLib::etClosedPolygon);
|
||||
ClipperLib::Paths out;
|
||||
co.Execute(out, - delta_scaled);
|
||||
holes.insert(holes.end(), out.begin(), out.end());
|
||||
}
|
||||
}
|
||||
|
||||
// 3) Subtract holes from the contours.
|
||||
ClipperLib::Paths output;
|
||||
{
|
||||
ClipperLib::Clipper clipper;
|
||||
clipper.Clear();
|
||||
clipper.AddPaths(contours, ClipperLib::ptSubject, true);
|
||||
clipper.AddPaths(holes, ClipperLib::ptClip, true);
|
||||
clipper.Execute(ClipperLib::ctDifference, *retval, ClipperLib::pftNonZero, ClipperLib::pftNonZero);
|
||||
}
|
||||
|
||||
// 4) Unscale the output.
|
||||
scaleClipperPolygons(*retval, 1/scale);
|
||||
}
|
||||
|
||||
Slic3r::Polygons offset(const Slic3r::ExPolygon &expolygon, const float delta,
|
||||
double scale, ClipperLib::JoinType joinType, double miterLimit)
|
||||
{
|
||||
// perform offset
|
||||
ClipperLib::Paths output;
|
||||
offset(expolygon, &output, delta, scale, joinType, miterLimit);
|
||||
|
||||
// convert into ExPolygons
|
||||
Slic3r::Polygons retval;
|
||||
ClipperPaths_to_Slic3rMultiPoints(output, &retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
Slic3r::ExPolygons
|
||||
offset_ex(const Slic3r::Polygons &polygons, const float delta,
|
||||
double scale, ClipperLib::JoinType joinType, double miterLimit)
|
||||
|
@ -49,6 +49,16 @@ Slic3r::Polygons offset(const Slic3r::Polygons &polygons, const float delta,
|
||||
double scale = CLIPPER_OFFSET_SCALE, ClipperLib::JoinType joinType = ClipperLib::jtMiter,
|
||||
double miterLimit = 3);
|
||||
|
||||
// This is a safe variant of the polygon offset, tailored for a single ExPolygon:
|
||||
// a single polygon with multiple non-overlapping holes.
|
||||
// Each contour and hole is offsetted separately, then the holes are subtracted from the outer contours.
|
||||
void offset(const Slic3r::ExPolygon &expolygon, ClipperLib::Paths* retval, const float delta,
|
||||
double scale = CLIPPER_OFFSET_SCALE, ClipperLib::JoinType joinType = ClipperLib::jtMiter,
|
||||
double miterLimit = 3);
|
||||
Slic3r::Polygons offset(const Slic3r::ExPolygon &expolygon, const float delta,
|
||||
double scale = CLIPPER_OFFSET_SCALE, ClipperLib::JoinType joinType = ClipperLib::jtMiter,
|
||||
double miterLimit = 3);
|
||||
|
||||
// offset Polylines
|
||||
void offset(const Slic3r::Polylines &polylines, ClipperLib::Paths* retval, const float delta,
|
||||
double scale = CLIPPER_OFFSET_SCALE, ClipperLib::JoinType joinType = ClipperLib::jtSquare,
|
||||
|
@ -585,4 +585,9 @@ BoundingBox get_extents(const ExPolygons &expolygons)
|
||||
return bbox;
|
||||
}
|
||||
|
||||
bool remove_sticks(ExPolygon &poly)
|
||||
{
|
||||
return remove_sticks(poly.contour) || remove_sticks(poly.holes);
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
|
@ -86,6 +86,8 @@ inline Polygons to_polygons(ExPolygons &&src)
|
||||
extern BoundingBox get_extents(const ExPolygon &expolygon);
|
||||
extern BoundingBox get_extents(const ExPolygons &expolygons);
|
||||
|
||||
extern bool remove_sticks(ExPolygon &poly);
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
// start Boost
|
||||
|
@ -86,12 +86,34 @@ Polygon::equally_spaced_points(double distance) const
|
||||
return this->split_at_first_point().equally_spaced_points(distance);
|
||||
}
|
||||
|
||||
double
|
||||
Polygon::area() const
|
||||
/*
|
||||
int64_t Polygon::area2x() const
|
||||
{
|
||||
ClipperLib::Path p;
|
||||
Slic3rMultiPoint_to_ClipperPath(*this, &p);
|
||||
return ClipperLib::Area(p);
|
||||
size_t n = poly.size();
|
||||
if (n < 3)
|
||||
return 0;
|
||||
|
||||
int64_t a = 0;
|
||||
for (size_t i = 0, j = n - 1; i < n; ++i)
|
||||
a += int64_t(poly[j].x + poly[i].x) * int64_t(poly[j].y - poly[i].y);
|
||||
j = i;
|
||||
}
|
||||
return -a * 0.5;
|
||||
}
|
||||
*/
|
||||
|
||||
double Polygon::area() const
|
||||
{
|
||||
size_t n = points.size();
|
||||
if (n < 3)
|
||||
return 0.;
|
||||
|
||||
double a = 0.;
|
||||
for (size_t i = 0, j = n - 1; i < n; ++i) {
|
||||
a += double(points[j].x + points[i].x) * double(points[i].y - points[j].y);
|
||||
j = i;
|
||||
}
|
||||
return 0.5 * a;
|
||||
}
|
||||
|
||||
bool
|
||||
@ -297,4 +319,103 @@ BoundingBox get_extents(const Polygons &polygons)
|
||||
return bb;
|
||||
}
|
||||
|
||||
static inline bool is_stick(const Point &p1, const Point &p2, const Point &p3)
|
||||
{
|
||||
Point v1 = p2 - p1;
|
||||
Point v2 = p3 - p2;
|
||||
int64_t dir = int64_t(v1.x) * int64_t(v2.x) + int64_t(v1.y) * int64_t(v2.y);
|
||||
if (dir > 0)
|
||||
// p3 does not turn back to p1. Do not remove p2.
|
||||
return false;
|
||||
double l2_1 = double(v1.x) * double(v1.x) + double(v1.y) * double(v1.y);
|
||||
double l2_2 = double(v2.x) * double(v2.x) + double(v2.y) * double(v2.y);
|
||||
if (dir == 0)
|
||||
// p1, p2, p3 may make a perpendicular corner, or there is a zero edge length.
|
||||
// Remove p2 if it is coincident with p1 or p2.
|
||||
return l2_1 == 0 || l2_2 == 0;
|
||||
// p3 turns back to p1 after p2. Are p1, p2, p3 collinear?
|
||||
// Calculate distance from p3 to a segment (p1, p2) or from p1 to a segment(p2, p3),
|
||||
// whichever segment is longer
|
||||
double cross = double(v1.x) * double(v2.y) - double(v2.x) * double(v1.y);
|
||||
double dist2 = cross * cross / std::max(l2_1, l2_2);
|
||||
return dist2 < EPSILON * EPSILON;
|
||||
}
|
||||
|
||||
bool remove_sticks(Polygon &poly)
|
||||
{
|
||||
bool modified = false;
|
||||
size_t j = 1;
|
||||
for (size_t i = 1; i + 1 < poly.points.size(); ++ i) {
|
||||
if (! is_stick(poly[j-1], poly[i], poly[i+1])) {
|
||||
// Keep the point.
|
||||
if (j < i)
|
||||
poly.points[j] = poly.points[i];
|
||||
++ j;
|
||||
}
|
||||
}
|
||||
if (++ j < poly.points.size()) {
|
||||
poly.points[j-1] = poly.points.back();
|
||||
poly.points.erase(poly.points.begin() + j, poly.points.end());
|
||||
modified = true;
|
||||
}
|
||||
while (poly.points.size() >= 3 && is_stick(poly.points[poly.points.size()-2], poly.points.back(), poly.points.front())) {
|
||||
poly.points.pop_back();
|
||||
modified = true;
|
||||
}
|
||||
while (poly.points.size() >= 3 && is_stick(poly.points.back(), poly.points.front(), poly.points[1]))
|
||||
poly.points.erase(poly.points.begin());
|
||||
return modified;
|
||||
}
|
||||
|
||||
bool remove_sticks(Polygons &polys)
|
||||
{
|
||||
bool modified = false;
|
||||
size_t j = 0;
|
||||
for (size_t i = 0; i < polys.size(); ++ i) {
|
||||
modified |= remove_sticks(polys[i]);
|
||||
if (polys[i].points.size() >= 3) {
|
||||
if (j < i)
|
||||
std::swap(polys[i].points, polys[j].points);
|
||||
++ j;
|
||||
}
|
||||
}
|
||||
if (j < polys.size())
|
||||
polys.erase(polys.begin() + j, polys.end());
|
||||
return modified;
|
||||
}
|
||||
|
||||
bool remove_degenerate(Polygons &polys)
|
||||
{
|
||||
bool modified = false;
|
||||
size_t j = 0;
|
||||
for (size_t i = 0; i < polys.size(); ++ i) {
|
||||
if (polys[i].points.size() >= 3) {
|
||||
if (j < i)
|
||||
std::swap(polys[i].points, polys[j].points);
|
||||
++ j;
|
||||
} else
|
||||
modified = true;
|
||||
}
|
||||
if (j < polys.size())
|
||||
polys.erase(polys.begin() + j, polys.end());
|
||||
return modified;
|
||||
}
|
||||
|
||||
bool remove_small(Polygons &polys, double min_area)
|
||||
{
|
||||
bool modified = false;
|
||||
size_t j = 0;
|
||||
for (size_t i = 0; i < polys.size(); ++ i) {
|
||||
if (polys[i].area() >= min_area) {
|
||||
if (j < i)
|
||||
std::swap(polys[i].points, polys[j].points);
|
||||
++ j;
|
||||
} else
|
||||
modified = true;
|
||||
}
|
||||
if (j < polys.size())
|
||||
polys.erase(polys.begin() + j, polys.end());
|
||||
return modified;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -51,6 +51,13 @@ class Polygon : public MultiPoint {
|
||||
extern BoundingBox get_extents(const Polygon &poly);
|
||||
extern BoundingBox get_extents(const Polygons &polygons);
|
||||
|
||||
// Remove sticks (tentacles with zero area) from the polygon.
|
||||
extern bool remove_sticks(Polygon &poly);
|
||||
extern bool remove_sticks(Polygons &polys);
|
||||
|
||||
// Remove polygons with less than 3 edges.
|
||||
extern bool remove_degenerate(Polygons &polys);
|
||||
extern bool remove_small(Polygons &polys, double min_area);
|
||||
}
|
||||
|
||||
// start Boost
|
||||
|
@ -103,10 +103,12 @@ public:
|
||||
// TODO: Fill* fill_maker => (is => 'lazy');
|
||||
PrintState<PrintObjectStep> state;
|
||||
|
||||
Print* print();
|
||||
ModelObject* model_object();
|
||||
|
||||
Points copies() const;
|
||||
Print* print() { return this->_print; }
|
||||
const Print* print() const { return this->_print; }
|
||||
ModelObject* model_object() { return this->_model_object; }
|
||||
const ModelObject* model_object() const { return this->_model_object; }
|
||||
|
||||
Points copies() const { return this->_copies; }
|
||||
bool add_copy(const Pointf &point);
|
||||
bool delete_last_copy();
|
||||
bool delete_all_copies();
|
||||
@ -151,7 +153,7 @@ private:
|
||||
// TODO: call model_object->get_bounding_box() instead of accepting
|
||||
// parameter
|
||||
PrintObject(Print* print, ModelObject* model_object, const BoundingBoxf3 &modobj_bbox);
|
||||
~PrintObject();
|
||||
~PrintObject() {}
|
||||
};
|
||||
|
||||
typedef std::vector<PrintObject*> PrintObjectPtrs;
|
||||
|
@ -31,28 +31,6 @@ PrintObject::PrintObject(Print* print, ModelObject* model_object, const Bounding
|
||||
this->layer_height_ranges = model_object->layer_height_ranges;
|
||||
}
|
||||
|
||||
PrintObject::~PrintObject()
|
||||
{
|
||||
}
|
||||
|
||||
Print*
|
||||
PrintObject::print()
|
||||
{
|
||||
return this->_print;
|
||||
}
|
||||
|
||||
ModelObject*
|
||||
PrintObject::model_object()
|
||||
{
|
||||
return this->_model_object;
|
||||
}
|
||||
|
||||
Points
|
||||
PrintObject::copies() const
|
||||
{
|
||||
return this->_copies;
|
||||
}
|
||||
|
||||
bool
|
||||
PrintObject::add_copy(const Pointf &point)
|
||||
{
|
||||
|
@ -326,7 +326,7 @@ SVG::Close()
|
||||
fprintf(this->f, "</svg>\n");
|
||||
fclose(this->f);
|
||||
this->f = NULL;
|
||||
printf("SVG written to %s\n", this->filename.c_str());
|
||||
// printf("SVG written to %s\n", this->filename.c_str());
|
||||
}
|
||||
|
||||
void SVG::export_expolygons(const char *path, const BoundingBox &bbox, const Slic3r::ExPolygons &expolygons, std::string stroke_outer, std::string stroke_holes, coordf_t stroke_width)
|
||||
|
@ -19,17 +19,156 @@ namespace Slic3r {
|
||||
#define PILLAR_SIZE (2.5)
|
||||
#define PILLAR_SPACING 10
|
||||
|
||||
PrintObjectSupportMaterial::PrintObjectSupportMaterial(const PrintObject *object) :
|
||||
m_object (object),
|
||||
m_print_config (&object->print()->config),
|
||||
m_object_config (&object->config),
|
||||
|
||||
m_first_layer_flow (0, 0, 0, false), // First layer flow will be set in the constructor code.
|
||||
m_support_material_flow (Flow::new_from_config_width(
|
||||
frSupportMaterial,
|
||||
object->config.support_material_extrusion_width, // object->config.extrusion_width.value
|
||||
object->print()->config.nozzle_diameter.get_at(object->config.support_material_extruder-1),
|
||||
object->config.layer_height.value,
|
||||
false)),
|
||||
m_support_material_interface_flow(Flow::new_from_config_width(
|
||||
frSupportMaterialInterface,
|
||||
object->config.support_material_extrusion_width, // object->config.extrusion_width.value
|
||||
object->print()->config.nozzle_diameter.get_at(object->config.support_material_interface_extruder-1),
|
||||
object->config.layer_height.value,
|
||||
false)),
|
||||
m_soluble_interface (object->config.support_material_contact_distance.value == 0),
|
||||
|
||||
m_support_material_raft_base_flow(0, 0, 0, false),
|
||||
m_support_material_raft_interface_flow(0, 0, 0, false),
|
||||
m_support_material_raft_contact_flow(0, 0, 0, false),
|
||||
|
||||
m_has_raft (object->config.raft_layers.value > 0),
|
||||
m_num_base_raft_layers (0),
|
||||
m_num_interface_raft_layers (0),
|
||||
m_num_contact_raft_layers (0),
|
||||
|
||||
// If set, the raft contact layer is laid with round strings, which are easily detachable
|
||||
// from both the below and above layes.
|
||||
// Otherwise a normal flow is used and the strings are squashed against the layer below,
|
||||
// creating a firm bond with the layer below and making the interface top surface flat.
|
||||
#if 1
|
||||
// This is the standard Slic3r behavior.
|
||||
m_raft_contact_layer_bridging(false),
|
||||
m_object_1st_layer_bridging (true),
|
||||
#else
|
||||
// This is more akin to what Simplify3D or Zortrax do.
|
||||
m_raft_contact_layer_bridging(true),
|
||||
m_object_1st_layer_bridging (false),
|
||||
#endif
|
||||
|
||||
m_raft_height (0.),
|
||||
m_raft_base_height (0.),
|
||||
m_raft_interface_height (0.),
|
||||
m_raft_contact_height (0.),
|
||||
|
||||
// 50 mirons layer
|
||||
m_support_layer_height_min (0.05),
|
||||
m_support_layer_height_max (0.),
|
||||
m_support_interface_layer_height_max(0.),
|
||||
|
||||
m_gap_extra_above (0.2),
|
||||
m_gap_extra_below (0.2),
|
||||
m_gap_xy (0.2),
|
||||
|
||||
// If enabled, the support layers will be synchronized with object layers.
|
||||
// This does not prevent the support layers to be combined.
|
||||
m_synchronize_support_layers_with_object(false),
|
||||
// If disabled and m_synchronize_support_layers_with_object,
|
||||
// the support layers will be synchronized with the object layers exactly, no layer will be combined.
|
||||
m_combine_support_layers (true)
|
||||
{
|
||||
// Based on the raft style and size, initialize the raft layers and the 1st object layer attributes.
|
||||
|
||||
size_t num_raft_layers = m_object_config->raft_layers.value;
|
||||
|
||||
//FIXME better to draw thin strings, which are easier to remove from the object.
|
||||
if (m_has_raft)
|
||||
{
|
||||
if (m_raft_contact_layer_bridging)
|
||||
m_support_material_raft_contact_flow = Flow::new_from_spacing(
|
||||
m_support_material_raft_interface_flow.spacing(),
|
||||
m_support_material_raft_interface_flow.nozzle_diameter,
|
||||
m_support_material_raft_interface_flow.height,
|
||||
true);
|
||||
|
||||
if (m_raft_contact_layer_bridging && num_raft_layers == 1)
|
||||
// The bridging contact layer will not bond to the bed well on its own.
|
||||
// Ensure there is at least the 1st layer printed with a firm squash.
|
||||
++ num_raft_layers;
|
||||
|
||||
// Split the raft layers into a single contact layer
|
||||
// and an equal number of interface and base layers,
|
||||
// with m_num_interface_raft_layers >= m_num_base_raft_layers.
|
||||
m_num_contact_raft_layers = 1;
|
||||
m_num_interface_raft_layers = num_raft_layers / 2;
|
||||
m_num_base_raft_layers = num_raft_layers - m_num_contact_raft_layers - m_num_interface_raft_layers;
|
||||
assert(m_num_interface_raft_layers >= m_num_base_raft_layers);
|
||||
assert(m_num_contact_raft_layers + m_num_base_raft_layers + m_num_interface_raft_layers == num_raft_layers);
|
||||
|
||||
m_raft_contact_height = m_num_contact_raft_layers * m_support_material_raft_contact_flow.height;
|
||||
if (m_num_base_raft_layers > 0) {
|
||||
m_raft_base_height = first_layer_height() + (m_num_base_raft_layers - 1) * m_support_material_raft_base_flow.height;
|
||||
m_raft_interface_height = m_num_interface_raft_layers * m_support_material_raft_interface_flow.height;
|
||||
} else if (m_num_interface_raft_layers > 0) {
|
||||
m_raft_base_height = 0;
|
||||
m_raft_interface_height = first_layer_height() + (m_num_interface_raft_layers - 1) * m_support_material_raft_interface_flow.height;
|
||||
} else {
|
||||
m_raft_base_height = 0;
|
||||
m_raft_interface_height = 0;
|
||||
}
|
||||
m_raft_height = m_raft_base_height + m_raft_interface_height + m_raft_contact_height;
|
||||
|
||||
// Find the layer height of the 1st object layer.
|
||||
if (m_object_1st_layer_bridging) {
|
||||
// Use an average nozzle diameter.
|
||||
std::set<size_t> extruders = m_object->print()->object_extruders();
|
||||
coordf_t nozzle_dmr = 0;
|
||||
for (std::set<size_t>::const_iterator it = extruders.begin(); it != extruders.end(); ++ it) {
|
||||
nozzle_dmr += m_object->print()->config.nozzle_diameter.get_at(*it);
|
||||
}
|
||||
nozzle_dmr /= extruders.size();
|
||||
m_object_1st_layer_height = nozzle_dmr;
|
||||
} else {
|
||||
m_object_1st_layer_height = m_object->config.layer_height.value;
|
||||
for (t_layer_height_ranges::const_iterator it = m_object->layer_height_ranges.begin(); it != m_object->layer_height_ranges.end(); ++ it) {
|
||||
if (m_object_1st_layer_height >= it->first.first && m_object_1st_layer_height <= it->first.second) {
|
||||
m_object_1st_layer_height = it->second;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_object_1st_layer_gap = m_soluble_interface ? 0 : m_object_config->support_material_contact_distance;
|
||||
m_object_1st_layer_print_z = m_raft_height + m_object_1st_layer_gap + m_object_1st_layer_height;
|
||||
}
|
||||
else
|
||||
{
|
||||
// No raft.
|
||||
m_raft_contact_layer_bridging = false;
|
||||
m_object_1st_layer_bridging = false;
|
||||
m_object_1st_layer_height = m_first_layer_flow.height;
|
||||
m_object_1st_layer_gap = 0;
|
||||
m_object_1st_layer_print_z = m_object_1st_layer_height;
|
||||
}
|
||||
}
|
||||
|
||||
// Using the std::deque as an allocator.
|
||||
inline PrintSupportMaterial::MyLayer& layer_allocate(
|
||||
std::deque<PrintSupportMaterial::MyLayer> &layer_storage,
|
||||
PrintSupportMaterial::SupporLayerType layer_type)
|
||||
inline PrintObjectSupportMaterial::MyLayer& layer_allocate(
|
||||
std::deque<PrintObjectSupportMaterial::MyLayer> &layer_storage,
|
||||
PrintObjectSupportMaterial::SupporLayerType layer_type)
|
||||
{
|
||||
layer_storage.push_back(PrintSupportMaterial::MyLayer());
|
||||
layer_storage.push_back(PrintObjectSupportMaterial::MyLayer());
|
||||
layer_storage.back().layer_type = layer_type;
|
||||
return layer_storage.back();
|
||||
}
|
||||
|
||||
inline void layers_append(PrintSupportMaterial::MyLayersPtr &dst, const PrintSupportMaterial::MyLayersPtr &src)
|
||||
inline void layers_append(PrintObjectSupportMaterial::MyLayersPtr &dst, const PrintObjectSupportMaterial::MyLayersPtr &src)
|
||||
{
|
||||
dst.insert(dst.end(), src.begin(), src.end());
|
||||
}
|
||||
@ -39,16 +178,16 @@ inline void polygons_append(Polygons &dst, const Polygons &src)
|
||||
dst.insert(dst.end(), src.begin(), src.end());
|
||||
}
|
||||
|
||||
void PrintSupportMaterial::generate(PrintObject &object)
|
||||
void PrintObjectSupportMaterial::generate(PrintObject &object)
|
||||
{
|
||||
coordf_t max_object_layer_height = 0.;
|
||||
for (size_t i = 0; i < object.layer_count(); ++ i)
|
||||
max_object_layer_height = std::max(max_object_layer_height, object.get_layer(i)->height);
|
||||
|
||||
if (m_support_layer_height_max == 0)
|
||||
m_support_layer_height_max = std::max(max_object_layer_height, 0.75 * m_flow.nozzle_diameter);
|
||||
m_support_layer_height_max = std::max(max_object_layer_height, 0.75 * m_support_material_flow.nozzle_diameter);
|
||||
if (m_support_interface_layer_height_max == 0)
|
||||
m_support_interface_layer_height_max = std::max(max_object_layer_height, 0.75 * m_interface_flow.nozzle_diameter);
|
||||
m_support_interface_layer_height_max = std::max(max_object_layer_height, 0.75 * m_support_material_interface_flow.nozzle_diameter);
|
||||
|
||||
// Layer instances will be allocated by std::deque and they will be kept until the end of this function call.
|
||||
// The layers will be referenced by various LayersPtr (of type std::vector<Layer*>)
|
||||
@ -59,6 +198,7 @@ void PrintSupportMaterial::generate(PrintObject &object)
|
||||
// This method is responsible for identifying what contact surfaces
|
||||
// should the support material expose to the object in order to guarantee
|
||||
// that it will be effective, regardless of how it's built below.
|
||||
// If raft is to be generated, the 1st top_contact layer will contain the 1st object layer silhouette without holes.
|
||||
MyLayersPtr top_contacts = this->top_contact_layers(object, layer_storage);
|
||||
if (top_contacts.empty())
|
||||
// Nothing is supported, no supports are generated.
|
||||
@ -73,14 +213,23 @@ void PrintSupportMaterial::generate(PrintObject &object)
|
||||
// Rather trim the top contacts by their overlapping bottom contacts to leave a gap instead of over extruding.
|
||||
this->trim_top_contacts_by_bottom_contacts(object, bottom_contacts, top_contacts);
|
||||
|
||||
// Generate intermediate layers between the top / bottom support contact layers,
|
||||
// trimmed by the object.
|
||||
// Generate empty intermediate layers between the top / bottom support contact layers,
|
||||
// The layers may or may not be synchronized with the object layers, depending on the configuration.
|
||||
// For example, a single nozzle multi material printing will need to generate a waste tower, which in turn
|
||||
// wastes less material, if there are as little layers as possible, therefore minimizing the material swaps.
|
||||
MyLayersPtr intermediate_layers = this->raft_and_intermediate_support_layers(
|
||||
object, bottom_contacts, top_contacts, layer_storage, max_object_layer_height);
|
||||
|
||||
// Fill in intermediate layers between the top / bottom support contact layers, trimmed by the object.
|
||||
this->generate_base_layers(object, bottom_contacts, top_contacts, intermediate_layers);
|
||||
|
||||
// If raft is to be generated, the 1st top_contact layer will contain the 1st object layer silhouette without holes.
|
||||
// Add the bottom contacts to the raft, inflate the support bases.
|
||||
// There is a contact layer below the 1st object layer in the bottom contacts.
|
||||
// There is also a 1st intermediate layer containing bases of support columns.
|
||||
// Extend the bases of the support columns and create the raft base.
|
||||
Polygons raft = this->generate_raft_base(object, bottom_contacts, intermediate_layers);
|
||||
|
||||
/*
|
||||
// If we wanted to apply some special logic to the first support layers lying on
|
||||
// object's top surfaces this is the place to detect them
|
||||
@ -129,7 +278,7 @@ void PrintSupportMaterial::generate(PrintObject &object)
|
||||
}
|
||||
|
||||
// Generate the actual toolpaths and save them into each layer.
|
||||
this->generate_toolpaths(object, bottom_contacts, top_contacts, intermediate_layers, interface_layers);
|
||||
this->generate_toolpaths(object, raft, bottom_contacts, top_contacts, intermediate_layers, interface_layers);
|
||||
}
|
||||
|
||||
void collect_region_slices_by_type(const Layer &layer, SurfaceType surface_type, Polygons &out)
|
||||
@ -196,7 +345,7 @@ Polygons collect_region_slices_outer(const Layer &layer)
|
||||
}
|
||||
|
||||
// Find the top contact surfaces of the support or the raft.
|
||||
PrintSupportMaterial::MyLayersPtr PrintSupportMaterial::top_contact_layers(const PrintObject &object, MyLayerStorage &layer_storage) const
|
||||
PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::top_contact_layers(const PrintObject &object, MyLayerStorage &layer_storage) const
|
||||
{
|
||||
// Output layers, sorte by top Z.
|
||||
MyLayersPtr contact_out;
|
||||
@ -218,14 +367,14 @@ PrintSupportMaterial::MyLayersPtr PrintSupportMaterial::top_contact_layers(const
|
||||
for (size_t layer_id = 0; layer_id < object.layer_count(); ++ layer_id) {
|
||||
// Note that layer_id < layer->id when raft_layers > 0 as the layer->id incorporates the raft layers.
|
||||
// So layer_id == 0 means first object layer and layer->id == 0 means first print layer if there are no explicit raft layers.
|
||||
if (m_object_config->raft_layers == 0) {
|
||||
if (layer_id == 0)
|
||||
// No raft, 1st object layer cannot be supported by a support contact layer.
|
||||
continue;
|
||||
} else if (! m_object_config->support_material) {
|
||||
// If we are only going to generate raft. Just check the 'overhangs' of the first object layer.
|
||||
if (layer_id > 0)
|
||||
if (this->has_raft()) {
|
||||
if (! this->has_support() && layer_id > 0)
|
||||
// If we are only going to generate raft. Just check for the 'overhangs' of the first object layer.
|
||||
break;
|
||||
// Check for the overhangs at any object layer including the 1st layer.
|
||||
} else if (layer_id == 0) {
|
||||
// No raft, 1st object layer cannot be supported by a support contact layer as it sticks directly to print bed.
|
||||
continue;
|
||||
}
|
||||
|
||||
const Layer &layer = *object.get_layer(layer_id);
|
||||
@ -240,8 +389,8 @@ PrintSupportMaterial::MyLayersPtr PrintSupportMaterial::top_contact_layers(const
|
||||
// but don't apply the safety offset during the union operation as it would
|
||||
// inflate the polygons over and over.
|
||||
projection_new = offset(projection_new, scale_(0.01));
|
||||
buildplate_only_top_surfaces.insert(buildplate_only_top_surfaces.end(), projection_new.begin(), projection_new.end());
|
||||
buildplate_only_top_surfaces = union_(buildplate_only_top_surfaces, false);
|
||||
polygons_append(buildplate_only_top_surfaces, projection_new);
|
||||
buildplate_only_top_surfaces = union_(buildplate_only_top_surfaces, false); // don't apply the safety offset.
|
||||
}
|
||||
}
|
||||
|
||||
@ -249,13 +398,14 @@ PrintSupportMaterial::MyLayersPtr PrintSupportMaterial::top_contact_layers(const
|
||||
Polygons overhang_polygons;
|
||||
Polygons contact_polygons;
|
||||
if (layer_id == 0) {
|
||||
// This is the first object layer, so we're here just to get the object footprint for the raft.
|
||||
// This is the first object layer, so the object is being printed on a raft and
|
||||
// we're here just to get the object footprint for the raft.
|
||||
// We only consider contours and discard holes to get a more continuous raft.
|
||||
overhang_polygons = collect_region_slices_outer(layer);
|
||||
// Extend by SUPPORT_MATERIAL_MARGIN, which is 1.5mm
|
||||
contact_polygons = offset(overhang_polygons, scale_(SUPPORT_MATERIAL_MARGIN));
|
||||
} else {
|
||||
// Generate overhang/contact_polygons for non-raft layers.
|
||||
// Generate overhang / contact_polygons for non-raft layers.
|
||||
const Layer &lower_layer = *object.get_layer(int(layer_id)-1);
|
||||
for (LayerRegionPtrs::const_iterator it_layerm = layer.regions.begin(); it_layerm != layer.regions.end(); ++ it_layerm) {
|
||||
const LayerRegion &layerm = *(*it_layerm);
|
||||
@ -271,6 +421,7 @@ PrintSupportMaterial::MyLayersPtr PrintSupportMaterial::top_contact_layers(const
|
||||
scale_(lower_layer.height * cos(threshold_rad) / sin(threshold_rad)) :
|
||||
// Overhang defined by half the extrusion width.
|
||||
0.5 * fw);
|
||||
// Overhang polygons for this layer and region.
|
||||
Polygons diff_polygons;
|
||||
if (lower_layer_offset == 0.) {
|
||||
diff_polygons = diff(
|
||||
@ -373,7 +524,7 @@ PrintSupportMaterial::MyLayersPtr PrintSupportMaterial::top_contact_layers(const
|
||||
|
||||
if (buildplate_only) {
|
||||
// Don't support overhangs above the top surfaces.
|
||||
// This step is done before the contact surface is calcuated by growing the overhang region.
|
||||
// This step is done before the contact surface is calculated by growing the overhang region.
|
||||
diff_polygons = diff(diff_polygons, buildplate_only_top_surfaces);
|
||||
}
|
||||
|
||||
@ -387,12 +538,14 @@ PrintSupportMaterial::MyLayersPtr PrintSupportMaterial::top_contact_layers(const
|
||||
// We increment the area in steps because we don't want our support to overflow
|
||||
// on the other side of the object (if it's very thin).
|
||||
{
|
||||
//FIMXE 1) Make the offset configurable, 2) Make the Z span configurable.
|
||||
Polygons slices_margin = offset((Polygons)lower_layer.slices, float(0.5*fw));
|
||||
if (buildplate_only) {
|
||||
// Trim the inflated contact surfaces by the top surfaces as well.
|
||||
polygons_append(slices_margin, buildplate_only_top_surfaces);
|
||||
slices_margin = union_(slices_margin);
|
||||
}
|
||||
// Offset the contact polygons outside.
|
||||
for (size_t i = 0; i < NUM_MARGIN_STEPS; ++ i) {
|
||||
diff_polygons = diff(
|
||||
offset(
|
||||
@ -416,12 +569,12 @@ PrintSupportMaterial::MyLayersPtr PrintSupportMaterial::top_contact_layers(const
|
||||
new_layer.idx_object_layer_above = layer_id;
|
||||
if (m_soluble_interface) {
|
||||
// Align the contact surface height with a layer immediately below the supported layer.
|
||||
new_layer.print_z = new_layer.print_z - new_layer.height;
|
||||
new_layer.height = (layer_id > 0) ?
|
||||
// Interface layer will be synchronized with the object.
|
||||
object.get_layer(layer_id - 1)->height :
|
||||
// Don't know the thickness of the raft layer yet.
|
||||
0.;
|
||||
new_layer.print_z = layer.print_z - layer.height;
|
||||
new_layer.bottom_z = new_layer.print_z - new_layer.height;
|
||||
} else {
|
||||
// Contact layer will be printed with a normal flow, but
|
||||
@ -450,10 +603,12 @@ PrintSupportMaterial::MyLayersPtr PrintSupportMaterial::top_contact_layers(const
|
||||
// Don't want to print a layer below the first layer height as it may not stick well.
|
||||
//FIXME there may be a need for a single layer support, then one may decide to print it either as a bottom contact or a top contact
|
||||
// and it may actually make sense to do it with a thinner layer than the first layer height.
|
||||
if (new_layer.print_z < m_object_config->first_layer_height + EPSILON)
|
||||
if (new_layer.print_z < this->first_layer_height() + m_support_layer_height_min)
|
||||
continue;
|
||||
|
||||
new_layer.polygons.swap(contact_polygons);
|
||||
// Store the overhang polygons as the aux_polygons.
|
||||
// The overhang polygons are used in the path generator for planning of the contact circles.
|
||||
new_layer.aux_polygons = new Polygons();
|
||||
new_layer.aux_polygons->swap(overhang_polygons);
|
||||
contact_out.push_back(&new_layer);
|
||||
@ -471,7 +626,7 @@ PrintSupportMaterial::MyLayersPtr PrintSupportMaterial::top_contact_layers(const
|
||||
return contact_out;
|
||||
}
|
||||
|
||||
PrintSupportMaterial::MyLayersPtr PrintSupportMaterial::bottom_contact_layers(
|
||||
PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::bottom_contact_layers(
|
||||
const PrintObject &object, const MyLayersPtr &top_contacts, MyLayerStorage &layer_storage) const
|
||||
{
|
||||
// find object top surfaces
|
||||
@ -507,13 +662,14 @@ PrintSupportMaterial::MyLayersPtr PrintSupportMaterial::bottom_contact_layers(
|
||||
// Align the interface layer with the object's layer height.
|
||||
object.get_layer(layer_id + 1)->height :
|
||||
// Place a bridge flow interface layer over the top surface.
|
||||
m_interface_flow.nozzle_diameter;
|
||||
m_support_material_interface_flow.nozzle_diameter;
|
||||
layer_new.print_z = layer.print_z + layer_new.height +
|
||||
(m_soluble_interface ? 0. : m_object_config->support_material_contact_distance.value);
|
||||
layer_new.bottom_z = layer.print_z;
|
||||
layer_new.idx_object_layer_below = layer_id;
|
||||
layer_new.bridging = ! m_soluble_interface;
|
||||
Polygons poly_new = offset(touching, float(m_flow.scaled_width()));
|
||||
//FIXME how much to inflate the top surface?
|
||||
Polygons poly_new = offset(touching, float(m_support_material_flow.scaled_width()));
|
||||
layer_new.polygons.swap(poly_new);
|
||||
// Remove the areas that touched from the projection that will continue on next, lower, top surfaces.
|
||||
projection = diff(projection, touching);
|
||||
@ -523,11 +679,10 @@ PrintSupportMaterial::MyLayersPtr PrintSupportMaterial::bottom_contact_layers(
|
||||
}
|
||||
|
||||
// Trim the top_contacts layers with the bottom_contacts layers if they overlap, so there would not be enough vertical space for both of them.
|
||||
void PrintSupportMaterial::trim_top_contacts_by_bottom_contacts(
|
||||
void PrintObjectSupportMaterial::trim_top_contacts_by_bottom_contacts(
|
||||
const PrintObject &object, const MyLayersPtr &bottom_contacts, MyLayersPtr &top_contacts) const
|
||||
{
|
||||
size_t idx_top_first = 0;
|
||||
coordf_t min_layer_height = 0.05;
|
||||
// For all bottom contact layers:
|
||||
for (size_t idx_bottom = 0; idx_bottom < bottom_contacts.size() && idx_top_first < top_contacts.size(); ++ idx_bottom) {
|
||||
const MyLayer &layer_bottom = *bottom_contacts[idx_bottom];
|
||||
@ -539,7 +694,7 @@ void PrintSupportMaterial::trim_top_contacts_by_bottom_contacts(
|
||||
MyLayer &layer_top = *top_contacts[idx_top];
|
||||
coordf_t interface_z = m_soluble_interface ?
|
||||
(layer_top.bottom_z + EPSILON) :
|
||||
(layer_top.bottom_z - min_layer_height);
|
||||
(layer_top.bottom_z - m_support_layer_height_min);
|
||||
if (interface_z < layer_bottom.print_z) {
|
||||
// Layers overlap. Trim layer_top with layer_bottom.
|
||||
layer_top.polygons = diff(layer_top.polygons, layer_bottom.polygons);
|
||||
@ -549,45 +704,88 @@ void PrintSupportMaterial::trim_top_contacts_by_bottom_contacts(
|
||||
}
|
||||
}
|
||||
|
||||
PrintSupportMaterial::MyLayersPtr PrintSupportMaterial::raft_and_intermediate_support_layers(
|
||||
PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::raft_and_intermediate_support_layers(
|
||||
const PrintObject &object,
|
||||
const MyLayersPtr &bottom_contacts,
|
||||
const MyLayersPtr &top_contacts,
|
||||
MyLayerStorage &layer_storage,
|
||||
const coordf_t max_object_layer_height) const
|
||||
{
|
||||
MyLayersPtr intermediate_layers;
|
||||
|
||||
// Collect and sort the extremes (bottoms of the top contacts and tops of the bottom contacts).
|
||||
std::vector<LayerExtreme> extremes;
|
||||
extremes.reserve(top_contacts.size() + bottom_contacts.size());
|
||||
for (size_t i = 0; i < top_contacts.size(); ++ i)
|
||||
// Bottoms of the top contact layers. In case of non-soluble supports,
|
||||
// the top contact layer thickness is not known yet.
|
||||
extremes.push_back(LayerExtreme(top_contacts[i], false));
|
||||
for (size_t i = 0; i < bottom_contacts.size(); ++ i)
|
||||
// Tops of the bottom contact layers.
|
||||
extremes.push_back(LayerExtreme(bottom_contacts[i], true));
|
||||
if (extremes.empty())
|
||||
return intermediate_layers;
|
||||
std::sort(extremes.begin(), extremes.end());
|
||||
|
||||
// Top of the 0th layer.
|
||||
coordf_t top_z_0th = this->raft_base_height() + this->raft_interface_height();
|
||||
assert(extremes.front().z() > top_z_0th && extremes.front().z() >= this->first_layer_height());
|
||||
|
||||
// Generate intermediate layers.
|
||||
MyLayersPtr intermediate_layers;
|
||||
for (size_t idx_extreme = 0; idx_extreme + 1 < extremes.size(); ++ idx_extreme) {
|
||||
LayerExtreme &extr1 = extremes[idx_extreme];
|
||||
LayerExtreme &extr2 = extremes[idx_extreme+1];
|
||||
coordf_t dist = extr2.z() - extr1.z();
|
||||
// The first intermediate layer is the same as the 1st layer if there is no raft,
|
||||
// or the bottom of the first intermediate layer is aligned with the bottom of the raft contact layer.
|
||||
// Intermediate layers are always printed with a normal etrusion flow (non-bridging).
|
||||
for (size_t idx_extreme = 0; idx_extreme < extremes.size(); ++ idx_extreme) {
|
||||
LayerExtreme *extr1 = (idx_extreme == 0) ? NULL : &extremes[idx_extreme-1];
|
||||
coordf_t extr1z = (extr1 == NULL) ? top_z_0th : extr1->z();
|
||||
LayerExtreme &extr2 = extremes[idx_extreme];
|
||||
coordf_t extr2z = extr2.z();
|
||||
coordf_t dist = extr2z - extr1z;
|
||||
assert(dist > 0.);
|
||||
// Insert intermediate layers.
|
||||
size_t n_layers_extra = size_t(ceil(dist / m_support_layer_height_max));
|
||||
coordf_t step = dist / coordf_t(n_layers_extra);
|
||||
size_t n_layers_extra = size_t(ceil(dist / m_support_layer_height_max));
|
||||
coordf_t step = dist / coordf_t(n_layers_extra);
|
||||
if (! m_soluble_interface && extr2.layer->layer_type == sltTopContact) {
|
||||
assert(extr2.layer->height == 0.);
|
||||
// This is a top interface layer, which does not have a height assigned yet. Do it now.
|
||||
if (m_synchronize_support_layers_with_object) {
|
||||
//FIXME
|
||||
// Find the
|
||||
}
|
||||
extr2.layer->height = step;
|
||||
extr2.layer->bottom_z = extr2.layer->print_z - step;
|
||||
-- n_layers_extra;
|
||||
if (extr2.layer->bottom_z < this->first_layer_height()) {
|
||||
// Split the span into two layers: the top layer up to the first layer height,
|
||||
// and the new intermediate layer below.
|
||||
// 1) Adjust the bottom of this top layer.
|
||||
assert(n_layers_extra == 0);
|
||||
extr2.layer->bottom_z = extr2z = this->first_layer_height();
|
||||
extr2.layer->height = extr2.layer->print_z - extr2.layer->bottom_z;
|
||||
// 2) Insert a new intermediate layer.
|
||||
MyLayer &layer_new = layer_allocate(layer_storage, stlIntermediate);
|
||||
layer_new.bottom_z = extr1z;
|
||||
layer_new.print_z = this->first_layer_height();
|
||||
layer_new.height = layer_new.print_z - layer_new.bottom_z;
|
||||
intermediate_layers.push_back(&layer_new);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (n_layers_extra > 0 && extr1z + step < this->first_layer_height()) {
|
||||
MyLayer &layer_new = layer_allocate(layer_storage, stlIntermediate);
|
||||
layer_new.bottom_z = extr1z;
|
||||
layer_new.print_z = extr1z = this->first_layer_height();
|
||||
layer_new.height = layer_new.print_z - layer_new.bottom_z;
|
||||
intermediate_layers.push_back(&layer_new);
|
||||
dist = extr2z - extr1z;
|
||||
assert(dist >= 0.);
|
||||
n_layers_extra = size_t(ceil(dist / m_support_layer_height_max));
|
||||
coordf_t step = dist / coordf_t(n_layers_extra);
|
||||
}
|
||||
for (size_t i = 0; i < n_layers_extra; ++ i) {
|
||||
MyLayer &layer_new = layer_allocate(layer_storage, stlIntermediate);
|
||||
layer_new.height = step;
|
||||
layer_new.bottom_z = extr1.z() + i * step;
|
||||
layer_new.bottom_z = (i + 1 == n_layers_extra) ? extr2z : extr1z + i * step;
|
||||
layer_new.print_z = layer_new.bottom_z + step;
|
||||
intermediate_layers.push_back(&layer_new);
|
||||
}
|
||||
@ -598,7 +796,7 @@ PrintSupportMaterial::MyLayersPtr PrintSupportMaterial::raft_and_intermediate_su
|
||||
|
||||
// At this stage there shall be intermediate_layers allocated between bottom_contacts and top_contacts, but they have no polygons assigned.
|
||||
// Also the bottom/top_contacts shall have a thickness assigned already.
|
||||
void PrintSupportMaterial::generate_base_layers(
|
||||
void PrintObjectSupportMaterial::generate_base_layers(
|
||||
const PrintObject &object,
|
||||
const MyLayersPtr &bottom_contacts,
|
||||
const MyLayersPtr &top_contacts,
|
||||
@ -610,8 +808,8 @@ void PrintSupportMaterial::generate_base_layers(
|
||||
|
||||
// coordf_t fillet_radius_scaled = scale_(m_object_config->support_material_spacing);
|
||||
//FIXME make configurable:
|
||||
coordf_t overlap_extra_above = 0.2;
|
||||
coordf_t overlap_extra_below = 0.2;
|
||||
coordf_t overlap_extra_above = 0.01;
|
||||
coordf_t overlap_extra_below = 0.01;
|
||||
|
||||
int idx_top_contact_above = int(top_contacts.size()) - 1;
|
||||
int idx_top_contact_overlapping = int(top_contacts.size()) - 1;
|
||||
@ -690,7 +888,7 @@ void PrintSupportMaterial::generate_base_layers(
|
||||
//FIXME This could be parallelized.
|
||||
const coordf_t gap_extra_above = 0.1f;
|
||||
const coordf_t gap_extra_below = 0.1f;
|
||||
const coord_t gap_xy_scaled = m_flow.scaled_width();
|
||||
const coord_t gap_xy_scaled = m_support_material_flow.scaled_width();
|
||||
size_t idx_object_layer_overlapping = 0;
|
||||
// For all intermediate layers:
|
||||
for (MyLayersPtr::iterator it_layer = intermediate_layers.begin(); it_layer != intermediate_layers.end(); ++ it_layer) {
|
||||
@ -720,8 +918,46 @@ void PrintSupportMaterial::generate_base_layers(
|
||||
}
|
||||
}
|
||||
|
||||
Polygons PrintObjectSupportMaterial::generate_raft_base(
|
||||
const PrintObject &object,
|
||||
const MyLayersPtr &bottom_contacts,
|
||||
MyLayersPtr &intermediate_layers) const
|
||||
{
|
||||
assert(! bottom_contacts.empty());
|
||||
MyLayer &contacts = *bottom_contacts.front();
|
||||
MyLayer &columns_base = *intermediate_layers.front();
|
||||
|
||||
Polygons raft_polygons;
|
||||
#if 0
|
||||
const float inflate_factor = scale_(3.);
|
||||
if (this->has_raft()) {
|
||||
if (m_num_base_raft_layers == 0 && m_num_interface_raft_layers == 0 && m_num_contact_raft_layers == 1) {
|
||||
// Having only the contact layer, which has the height of the 1st layer.
|
||||
// We are free to merge the contacts with the columns_base, they will be printed the same way.
|
||||
polygons_append(contacts.polygons, offset(columns_base.polygons, inflate_factor));
|
||||
contacts.polygons = union_(contacts.polygons);
|
||||
} else {
|
||||
// Having multiple raft layers.
|
||||
assert(m_num_interface_raft_layers > 0);
|
||||
// Extend the raft base by the bases of the support columns, add the raft contacts.
|
||||
raft_polygons = raft_interface_polygons;
|
||||
//FIXME make the offset configurable.
|
||||
polygons_append(raft_polygons, offset(columns_base.polygons, inflate_factor));
|
||||
raft_polygons = union_(raft_polygons);
|
||||
}
|
||||
} else {
|
||||
// No raft. The 1st intermediate layer contains the bases of the support columns.
|
||||
// Expand the polygons, but trim with the object.
|
||||
columns_base.polygons = diff(
|
||||
offset(columns_base.polygons, inflate_factor),
|
||||
offset(m_object->get_layer(0), safety_factor);
|
||||
}
|
||||
#endif
|
||||
return raft_polygons;
|
||||
}
|
||||
|
||||
// Convert some of the intermediate layers into top/bottom interface layers.
|
||||
PrintSupportMaterial::MyLayersPtr PrintSupportMaterial::generate_interface_layers(
|
||||
PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::generate_interface_layers(
|
||||
const PrintObject &object,
|
||||
const MyLayersPtr &bottom_contacts,
|
||||
const MyLayersPtr &top_contacts,
|
||||
@ -799,8 +1035,9 @@ PrintSupportMaterial::MyLayersPtr PrintSupportMaterial::generate_interface_layer
|
||||
return interface_layers;
|
||||
}
|
||||
|
||||
void PrintSupportMaterial::generate_toolpaths(
|
||||
void PrintObjectSupportMaterial::generate_toolpaths(
|
||||
const PrintObject &object,
|
||||
const Polygons &raft,
|
||||
const MyLayersPtr &bottom_contacts,
|
||||
const MyLayersPtr &top_contacts,
|
||||
const MyLayersPtr &intermediate_layers,
|
||||
@ -808,7 +1045,7 @@ void PrintSupportMaterial::generate_toolpaths(
|
||||
{
|
||||
// Shape of the top contact area.
|
||||
int n_contact_loops = 1;
|
||||
coordf_t circle_radius = 1.5 * m_interface_flow.scaled_width();
|
||||
coordf_t circle_radius = 1.5 * m_support_material_interface_flow.scaled_width();
|
||||
coordf_t circle_distance = 3. * circle_radius;
|
||||
Polygon circle;
|
||||
circle.points.reserve(6);
|
||||
@ -846,10 +1083,10 @@ void PrintSupportMaterial::generate_toolpaths(
|
||||
}
|
||||
|
||||
coordf_t interface_angle = m_object_config->support_material_angle + 90.;
|
||||
coordf_t interface_spacing = m_object_config->support_material_interface_spacing.value + m_interface_flow.spacing();
|
||||
coordf_t interface_density = (interface_spacing == 0.) ? 1. : (m_interface_flow.spacing() / interface_spacing);
|
||||
coordf_t support_spacing = m_object_config->support_material_spacing.value + m_flow.spacing();
|
||||
coordf_t support_density = (support_spacing == 0.) ? 1. : (m_flow.spacing() / support_spacing);
|
||||
coordf_t interface_spacing = m_object_config->support_material_interface_spacing.value + m_support_material_interface_flow.spacing();
|
||||
coordf_t interface_density = (interface_spacing == 0.) ? 1. : (m_support_material_interface_flow.spacing() / interface_spacing);
|
||||
coordf_t support_spacing = m_object_config->support_material_spacing.value + m_support_material_flow.spacing();
|
||||
coordf_t support_density = (support_spacing == 0.) ? 1. : (m_support_material_flow.spacing() / support_spacing);
|
||||
|
||||
//FIXME Parallelize the support generator:
|
||||
/*
|
||||
@ -898,8 +1135,8 @@ void PrintSupportMaterial::generate_toolpaths(
|
||||
base_polygons = intermediate_layers[idx_layer_intermediate]->polygons;
|
||||
|
||||
// We redefine flows locally by applying this layer's height.
|
||||
Flow flow = m_flow;
|
||||
Flow interface_flow = m_interface_flow;
|
||||
Flow flow = m_support_material_flow;
|
||||
Flow interface_flow = m_support_material_interface_flow;
|
||||
flow.height = support_layer.height;
|
||||
interface_flow.height = support_layer.height;
|
||||
|
||||
@ -1216,7 +1453,7 @@ void PrintSupportMaterial::generate_toolpaths(
|
||||
}
|
||||
|
||||
/*
|
||||
void PrintSupportMaterial::clip_by_pillars(
|
||||
void PrintObjectSupportMaterial::clip_by_pillars(
|
||||
const PrintObject &object,
|
||||
LayersPtr &bottom_contacts,
|
||||
LayersPtr &top_contacts,
|
||||
|
@ -12,8 +12,11 @@ class PrintObjectConfig;
|
||||
// how much we extend support around the actual contact area
|
||||
#define SUPPORT_MATERIAL_MARGIN 1.5
|
||||
|
||||
// This class manages raft and supports for a single PrintObject.
|
||||
// Instantiated by Slic3r::Print::Object->_support_material()
|
||||
class PrintSupportMaterial
|
||||
// This class is instantiated before the slicing starts as Object.pm will query
|
||||
// the parameters of the raft to determine the 1st layer height and thickness.
|
||||
class PrintObjectSupportMaterial
|
||||
{
|
||||
public:
|
||||
enum SupporLayerType {
|
||||
@ -113,44 +116,41 @@ public:
|
||||
typedef std::deque<MyLayer> MyLayerStorage;
|
||||
|
||||
public:
|
||||
PrintSupportMaterial(
|
||||
const PrintConfig *print_config,
|
||||
const PrintObjectConfig *object_config,
|
||||
const Flow &flow,
|
||||
const Flow &first_layer_flow,
|
||||
const Flow &interface_flow,
|
||||
bool soluble_interface) :
|
||||
m_print_config(print_config),
|
||||
m_object_config(object_config),
|
||||
m_flow(flow),
|
||||
m_first_layer_flow(first_layer_flow),
|
||||
m_interface_flow(interface_flow),
|
||||
m_soluble_interface(soluble_interface),
|
||||
m_support_layer_height_max(0.),
|
||||
m_support_interface_layer_height_max(0.)
|
||||
{}
|
||||
PrintObjectSupportMaterial(const PrintObject *object);
|
||||
|
||||
PrintSupportMaterial(
|
||||
PrintConfig *print_config,
|
||||
PrintObjectConfig *object_config,
|
||||
Flow *flow,
|
||||
Flow *first_layer_flow,
|
||||
Flow *interface_flow,
|
||||
bool soluble_interface) :
|
||||
m_print_config(print_config),
|
||||
m_object_config(object_config),
|
||||
m_flow(*flow),
|
||||
m_first_layer_flow(*first_layer_flow),
|
||||
m_interface_flow(*interface_flow),
|
||||
m_soluble_interface(soluble_interface),
|
||||
m_support_layer_height_max(0.),
|
||||
m_support_interface_layer_height_max(0.)
|
||||
{}
|
||||
// Height of the 1st layer is user configured as it is important for the print
|
||||
// to stick to he print bed.
|
||||
coordf_t first_layer_height() const { return m_object_config->first_layer_height.value; }
|
||||
|
||||
// Is raft enabled?
|
||||
bool has_raft() const { return m_has_raft; }
|
||||
// Has any support?
|
||||
bool has_support() const { return m_object_config->support_material.value; }
|
||||
|
||||
// How many raft layers are there below the 1st object layer?
|
||||
// The 1st object layer_id will be offsetted by this number.
|
||||
size_t num_raft_layers() const { return m_object_config->raft_layers.value; }
|
||||
// num_raft_layers() == num_raft_base_layers() + num_raft_interface_layers() + num_raft_contact_layers().
|
||||
size_t num_raft_base_layers() const { return m_num_base_raft_layers; }
|
||||
size_t num_raft_interface_layers() const { return m_num_interface_raft_layers; }
|
||||
size_t num_raft_contact_layers() const { return m_num_contact_raft_layers; }
|
||||
|
||||
coordf_t raft_height() const { return m_raft_height; }
|
||||
coordf_t raft_base_height() const { return m_raft_base_height; }
|
||||
coordf_t raft_interface_height() const { return m_raft_interface_height; }
|
||||
coordf_t raft_contact_height() const { return m_raft_contact_height; }
|
||||
bool raft_bridging() const { return m_raft_contact_layer_bridging; }
|
||||
|
||||
// 1st layer of the object will be printed depeding on the raft settings.
|
||||
coordf_t first_object_layer_print_z() const { return m_object_1st_layer_print_z; }
|
||||
coordf_t first_object_layer_height() const { return m_object_1st_layer_height; }
|
||||
coordf_t first_object_layer_gap() const { return m_object_1st_layer_gap; }
|
||||
bool first_object_layer_bridging() const { return m_object_1st_layer_bridging; }
|
||||
|
||||
// Generate support material for the object.
|
||||
// New support layers will be added to the object,
|
||||
// with extrusion paths and islands filled in for each support layer.
|
||||
void generate(PrintObject &object);
|
||||
void generate(PrintObject &object);
|
||||
|
||||
private:
|
||||
// Generate top contact layers supporting overhangs.
|
||||
@ -180,6 +180,11 @@ private:
|
||||
const MyLayersPtr &top_contacts,
|
||||
MyLayersPtr &intermediate_layers) const;
|
||||
|
||||
Polygons generate_raft_base(
|
||||
const PrintObject &object,
|
||||
const MyLayersPtr &bottom_contacts,
|
||||
MyLayersPtr &intermediate_layers) const;
|
||||
|
||||
MyLayersPtr generate_interface_layers(
|
||||
const PrintObject &object,
|
||||
const MyLayersPtr &bottom_contacts,
|
||||
@ -195,21 +200,59 @@ private:
|
||||
// Produce the actual G-code.
|
||||
void generate_toolpaths(
|
||||
const PrintObject &object,
|
||||
const Polygons &raft,
|
||||
const MyLayersPtr &bottom_contacts,
|
||||
const MyLayersPtr &top_contacts,
|
||||
const MyLayersPtr &intermediate_layers,
|
||||
const MyLayersPtr &interface_layers) const;
|
||||
|
||||
const PrintObject *m_object;
|
||||
const PrintConfig *m_print_config;
|
||||
const PrintObjectConfig *m_object_config;
|
||||
Flow m_flow;
|
||||
|
||||
Flow m_first_layer_flow;
|
||||
Flow m_interface_flow;
|
||||
Flow m_support_material_flow;
|
||||
Flow m_support_material_interface_flow;
|
||||
bool m_soluble_interface;
|
||||
|
||||
Flow m_support_material_raft_base_flow;
|
||||
Flow m_support_material_raft_interface_flow;
|
||||
Flow m_support_material_raft_contact_flow;
|
||||
|
||||
bool m_has_raft;
|
||||
size_t m_num_base_raft_layers;
|
||||
size_t m_num_interface_raft_layers;
|
||||
size_t m_num_contact_raft_layers;
|
||||
// If set, the raft contact layer is laid with round strings, which are easily detachable
|
||||
// from both the below and above layes.
|
||||
// Otherwise a normal flow is used and the strings are squashed against the layer below,
|
||||
// creating a firm bond with the layer below and making the interface top surface flat.
|
||||
coordf_t m_raft_height;
|
||||
coordf_t m_raft_base_height;
|
||||
coordf_t m_raft_interface_height;
|
||||
coordf_t m_raft_contact_height;
|
||||
bool m_raft_contact_layer_bridging;
|
||||
|
||||
coordf_t m_object_1st_layer_print_z;
|
||||
coordf_t m_object_1st_layer_height;
|
||||
coordf_t m_object_1st_layer_gap;
|
||||
bool m_object_1st_layer_bridging;
|
||||
|
||||
coordf_t m_object_layer_height_max;
|
||||
coordf_t m_support_layer_height_min;
|
||||
coordf_t m_support_layer_height_max;
|
||||
coordf_t m_support_interface_layer_height_max;
|
||||
|
||||
coordf_t m_gap_extra_above;
|
||||
coordf_t m_gap_extra_below;
|
||||
coordf_t m_gap_xy;
|
||||
|
||||
// If enabled, the support layers will be synchronized with object layers.
|
||||
// This does not prevent the support layers to be combined.
|
||||
bool m_synchronize_support_layers_with_object;
|
||||
// If disabled and m_synchronize_support_layers_with_object,
|
||||
// the support layers will be synchronized with the object layers exactly, no layer will be combined.
|
||||
bool m_combine_support_layers;
|
||||
};
|
||||
|
||||
} // namespace Slic3r
|
||||
|
@ -56,7 +56,7 @@ REGISTER_CLASS(PrintConfig, "Config::Print");
|
||||
REGISTER_CLASS(FullPrintConfig, "Config::Full");
|
||||
REGISTER_CLASS(Surface, "Surface");
|
||||
REGISTER_CLASS(SurfaceCollection, "Surface::Collection");
|
||||
REGISTER_CLASS(PrintSupportMaterial, "Print::SupportMaterial2");
|
||||
REGISTER_CLASS(PrintObjectSupportMaterial, "Print::SupportMaterial2");
|
||||
REGISTER_CLASS(TriangleMesh, "TriangleMesh");
|
||||
REGISTER_CLASS(GLVertexArray, "GUI::_3DScene::GLVertexArray");
|
||||
|
||||
|
@ -5,15 +5,9 @@
|
||||
#include "libslic3r/SupportMaterial.hpp"
|
||||
%}
|
||||
|
||||
%name{Slic3r::Print::SupportMaterial2} class PrintSupportMaterial {
|
||||
%name{_new} PrintSupportMaterial(
|
||||
PrintConfig *print_config,
|
||||
PrintObjectConfig *object_config,
|
||||
Flow *flow,
|
||||
Flow *first_layer_flow,
|
||||
Flow *interface_flow,
|
||||
bool soluble_interface);
|
||||
~PrintSupportMaterial();
|
||||
%name{Slic3r::Print::SupportMaterial2} class PrintObjectSupportMaterial {
|
||||
PrintObjectSupportMaterial(PrintObject *print_object);
|
||||
~PrintObjectSupportMaterial();
|
||||
|
||||
void generate(PrintObject *object)
|
||||
%code{% THIS->generate(*object); %};
|
||||
|
@ -221,9 +221,9 @@ PerimeterGenerator* O_OBJECT_SLIC3R
|
||||
Ref<PerimeterGenerator> O_OBJECT_SLIC3R_T
|
||||
Clone<PerimeterGenerator> O_OBJECT_SLIC3R_T
|
||||
|
||||
PrintSupportMaterial* O_OBJECT_SLIC3R
|
||||
Ref<PrintSupportMaterial> O_OBJECT_SLIC3R_T
|
||||
Clone<PrintSupportMaterial> O_OBJECT_SLIC3R_T
|
||||
PrintObjectSupportMaterial* O_OBJECT_SLIC3R
|
||||
Ref<PrintObjectSupportMaterial> O_OBJECT_SLIC3R_T
|
||||
Clone<PrintObjectSupportMaterial> O_OBJECT_SLIC3R_T
|
||||
|
||||
GLVertexArray* O_OBJECT_SLIC3R
|
||||
|
||||
|
@ -141,9 +141,9 @@
|
||||
%typemap{SupportLayer*};
|
||||
%typemap{Ref<SupportLayer>}{simple};
|
||||
|
||||
%typemap{PrintSupportMaterial*};
|
||||
%typemap{Ref<PrintSupportMaterial>}{simple};
|
||||
%typemap{Clone<PrintSupportMaterial>}{simple};
|
||||
%typemap{PrintObjectSupportMaterial*};
|
||||
%typemap{Ref<PrintObjectSupportMaterial>}{simple};
|
||||
%typemap{Clone<PrintObjectSupportMaterial>}{simple};
|
||||
|
||||
%typemap{PlaceholderParser*};
|
||||
%typemap{Ref<PlaceholderParser>}{simple};
|
||||
|
Loading…
Reference in New Issue
Block a user