mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-07-31 18:22:04 +08:00
Merge branch 'master_slic3rPE_PR'
This commit is contained in:
commit
ad3b2879e8
@ -303,6 +303,18 @@ inline void extrusion_entities_append_paths(ExtrusionEntitiesPtr &dst, Polylines
|
|||||||
polylines.clear();
|
polylines.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void extrusion_entities_append_loops(ExtrusionEntitiesPtr &dst, Polygons &loops, ExtrusionRole role, double mm3_per_mm, float width, float height) {
|
||||||
|
dst.reserve(dst.size() + loops.size());
|
||||||
|
for (Polygon &poly : loops) {
|
||||||
|
if (poly.is_valid()) {
|
||||||
|
ExtrusionPath path(role, mm3_per_mm, width, height);
|
||||||
|
path.polyline.points = poly.points;
|
||||||
|
path.polyline.points.push_back(path.polyline.points.front());
|
||||||
|
dst.emplace_back(new ExtrusionLoop(std::move(path)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inline void extrusion_entities_append_loops(ExtrusionEntitiesPtr &dst, Polygons &&loops, ExtrusionRole role, double mm3_per_mm, float width, float height)
|
inline void extrusion_entities_append_loops(ExtrusionEntitiesPtr &dst, Polygons &&loops, ExtrusionRole role, double mm3_per_mm, float width, float height)
|
||||||
{
|
{
|
||||||
dst.reserve(dst.size() + loops.size());
|
dst.reserve(dst.size() + loops.size());
|
||||||
|
@ -22,6 +22,7 @@ Fill* Fill::new_from_type(const InfillPattern type)
|
|||||||
{
|
{
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ipConcentric: return new FillConcentric();
|
case ipConcentric: return new FillConcentric();
|
||||||
|
case ipConcentricGapFill: return new FillConcentricWGapFill();
|
||||||
case ipHoneycomb: return new FillHoneycomb();
|
case ipHoneycomb: return new FillHoneycomb();
|
||||||
case ip3DHoneycomb: return new Fill3DHoneycomb();
|
case ip3DHoneycomb: return new Fill3DHoneycomb();
|
||||||
case ipGyroid: return new FillGyroid();
|
case ipGyroid: return new FillGyroid();
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
#include "../ClipperUtils.hpp"
|
#include "../ClipperUtils.hpp"
|
||||||
#include "../ExPolygon.hpp"
|
#include "../ExPolygon.hpp"
|
||||||
#include "../Surface.hpp"
|
#include "../Surface.hpp"
|
||||||
|
#include "../ExtrusionEntityCollection.hpp"
|
||||||
|
#include "../MedialAxis.hpp"
|
||||||
|
|
||||||
#include "FillConcentric.hpp"
|
#include "FillConcentric.hpp"
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
|
|
||||||
void FillConcentric::_fill_surface_single(
|
void FillConcentric::_fill_surface_single(
|
||||||
const FillParams ¶ms,
|
const FillParams ¶ms,
|
||||||
@ -61,4 +64,98 @@ void FillConcentric::_fill_surface_single(
|
|||||||
// We want the loops to be split inside the G-code generator to get optimum path planning.
|
// We want the loops to be split inside the G-code generator to get optimum path planning.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FillConcentricWGapFill::fill_surface_extrusion(const Surface *surface, const FillParams ¶ms,
|
||||||
|
const Flow &flow, const ExtrusionRole &role, ExtrusionEntitiesPtr &out) {
|
||||||
|
|
||||||
|
// Perform offset.
|
||||||
|
Slic3r::ExPolygons expp = offset_ex(surface->expolygon, float(scale_(0 - 0.5 * this->spacing)));
|
||||||
|
// Create the infills for each of the regions.
|
||||||
|
Polylines polylines_out;
|
||||||
|
for (size_t i = 0; i < expp.size(); ++i) {
|
||||||
|
//_fill_surface_single(
|
||||||
|
//params,
|
||||||
|
//surface->thickness_layers,
|
||||||
|
//_infill_direction(surface),
|
||||||
|
//expp[i],
|
||||||
|
//polylines_out);
|
||||||
|
ExPolygon expolygon = expp[i];
|
||||||
|
|
||||||
|
coordf_t init_spacing = this->spacing;
|
||||||
|
|
||||||
|
// no rotation is supported for this infill pattern
|
||||||
|
BoundingBox bounding_box = expolygon.contour.bounding_box();
|
||||||
|
|
||||||
|
coord_t min_spacing = scale_(this->spacing);
|
||||||
|
coord_t distance = coord_t(min_spacing / params.density);
|
||||||
|
|
||||||
|
if (params.density > 0.9999f && !params.dont_adjust) {
|
||||||
|
distance = this->_adjust_solid_spacing(bounding_box.size().x, distance);
|
||||||
|
this->spacing = unscale(distance);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExPolygons gaps;
|
||||||
|
Polygons loops = (Polygons)expolygon;
|
||||||
|
Polygons last = loops;
|
||||||
|
while (!last.empty()) {
|
||||||
|
Polygons next_onion = offset2(last, -(distance + min_spacing / 2), +min_spacing / 2);
|
||||||
|
loops.insert(loops.end(), next_onion.begin(), next_onion.end());
|
||||||
|
append(gaps, diff_ex(
|
||||||
|
offset(last, -0.5f * distance),
|
||||||
|
offset(next_onion, 0.5f * distance + 10))); // safety offset
|
||||||
|
last = next_onion;
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate paths from the outermost to the innermost, to avoid
|
||||||
|
// adhesion problems of the first central tiny loops
|
||||||
|
//note: useless if we don't apply no_sort flag
|
||||||
|
//loops = union_pt_chained(loops, false);
|
||||||
|
|
||||||
|
|
||||||
|
//get the role
|
||||||
|
ExtrusionRole good_role = role;
|
||||||
|
if (good_role == erNone || good_role == erCustom) {
|
||||||
|
good_role = (flow.bridge ? erBridgeInfill :
|
||||||
|
(surface->is_solid() ?
|
||||||
|
((surface->is_top()) ? erTopSolidInfill : erSolidInfill) :
|
||||||
|
erInternalInfill));
|
||||||
|
}
|
||||||
|
|
||||||
|
ExtrusionEntityCollection *coll_nosort = new ExtrusionEntityCollection();
|
||||||
|
coll_nosort->no_sort = true; //can be sorted inside the pass
|
||||||
|
extrusion_entities_append_loops(
|
||||||
|
coll_nosort->entities, loops,
|
||||||
|
good_role,
|
||||||
|
flow.mm3_per_mm() * params.flow_mult,
|
||||||
|
flow.width * params.flow_mult,
|
||||||
|
flow.height);
|
||||||
|
|
||||||
|
//add gapfills
|
||||||
|
if (!gaps.empty() && params.density >= 1) {
|
||||||
|
// collapse
|
||||||
|
double min = 0.2 * distance * (1 - INSET_OVERLAP_TOLERANCE);
|
||||||
|
double max = 2. * distance;
|
||||||
|
ExPolygons gaps_ex = diff_ex(
|
||||||
|
offset2_ex(gaps, -min / 2, +min / 2),
|
||||||
|
offset2_ex(gaps, -max / 2, +max / 2),
|
||||||
|
true);
|
||||||
|
ThickPolylines polylines;
|
||||||
|
for (const ExPolygon &ex : gaps_ex) {
|
||||||
|
//remove too small gaps that are too hard to fill.
|
||||||
|
//ie one that are smaller than an extrusion with width of min and a length of max.
|
||||||
|
if (ex.area() > min*max) {
|
||||||
|
ex.medial_axis(ex, max, min, &polylines, flow.height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!polylines.empty()) {
|
||||||
|
ExtrusionEntityCollection gap_fill = thin_variable_width(polylines, erGapFill, flow);
|
||||||
|
coll_nosort->append(gap_fill.entities);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!coll_nosort->entities.empty())
|
||||||
|
out.push_back(coll_nosort);
|
||||||
|
else delete coll_nosort;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
@ -12,16 +12,29 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual Fill* clone() const { return new FillConcentric(*this); };
|
virtual Fill* clone() const { return new FillConcentric(*this); };
|
||||||
virtual void _fill_surface_single(
|
virtual void _fill_surface_single(
|
||||||
const FillParams ¶ms,
|
const FillParams ¶ms,
|
||||||
unsigned int thickness_layers,
|
unsigned int thickness_layers,
|
||||||
const std::pair<float, Point> &direction,
|
const std::pair<float, Point> &direction,
|
||||||
ExPolygon &expolygon,
|
ExPolygon &expolygon,
|
||||||
Polylines &polylines_out);
|
Polylines &polylines_out);
|
||||||
|
|
||||||
virtual bool no_sort() const { return true; }
|
virtual bool no_sort() const { return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class FillConcentricWGapFill : public Fill {
|
||||||
|
public:
|
||||||
|
virtual ~FillConcentricWGapFill() {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual Fill* clone() const { return new FillConcentricWGapFill(*this); };
|
||||||
|
virtual void fill_surface_extrusion(const Surface *surface, const FillParams ¶ms,
|
||||||
|
const Flow &flow, const ExtrusionRole &role, ExtrusionEntitiesPtr &out);
|
||||||
|
|
||||||
|
virtual bool no_sort() const { return true; }
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
|
||||||
#endif // slic3r_FillConcentric_hpp_
|
#endif // slic3r_FillConcentric_hpp_
|
||||||
|
@ -269,8 +269,9 @@ namespace Slic3r {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!eecroot->entities.empty())
|
if (!eecroot->entities.empty())
|
||||||
out.push_back(eecroot);
|
out.push_back(eecroot);
|
||||||
|
else delete eecroot;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -301,13 +301,14 @@ remove_point_too_near(ThickPolyline* to_reduce)
|
|||||||
to_reduce->points.erase(to_reduce->points.begin() + id);
|
to_reduce->points.erase(to_reduce->points.begin() + id);
|
||||||
to_reduce->width.erase(to_reduce->width.begin() + id);
|
to_reduce->width.erase(to_reduce->width.begin() + id);
|
||||||
newdist = to_reduce->points[id].distance_to(to_reduce->points[id - 1]);
|
newdist = to_reduce->points[id].distance_to(to_reduce->points[id - 1]);
|
||||||
|
//if you removed a point, it check if the next one isn't too near from the previous one.
|
||||||
|
// if not, it bypass it.
|
||||||
|
if (newdist > smallest) {
|
||||||
|
++id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//go to next one
|
//go to next one
|
||||||
//if you removed a point, it check if the next one isn't too near from the previous one.
|
else ++id;
|
||||||
// if not, it byepass it.
|
|
||||||
if (newdist > smallest) {
|
|
||||||
++id;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -620,20 +621,33 @@ MedialAxis::extends_line(ThickPolyline& polyline, const ExPolygons& anchors, con
|
|||||||
line.a = *(polyline.points.begin() + first_idx);
|
line.a = *(polyline.points.begin() + first_idx);
|
||||||
}
|
}
|
||||||
// prevent the line from touching on the other side, otherwise intersection() might return that solution
|
// prevent the line from touching on the other side, otherwise intersection() might return that solution
|
||||||
if (polyline.points.size() == 2) line.a = line.midpoint();
|
if (polyline.points.size() == 2 && this->expolygon.contains(line.midpoint())) line.a = line.midpoint();
|
||||||
|
|
||||||
line.extend_end(max_width);
|
line.extend_end(max_width);
|
||||||
Point new_back;
|
Point new_back;
|
||||||
if (this->expolygon.contour.has_boundary_point(polyline.points.back())) {
|
if (this->expolygon.contour.has_boundary_point(polyline.points.back())) {
|
||||||
new_back = polyline.points.back();
|
new_back = polyline.points.back();
|
||||||
} else {
|
} else {
|
||||||
//TODO: verify also for holes.
|
bool finded = this->expolygon.contour.first_intersection(line, &new_back);
|
||||||
(void)this->expolygon.contour.first_intersection(line, &new_back);
|
//verify also for holes.
|
||||||
|
Point new_back_temp;
|
||||||
|
for (Polygon hole : this->expolygon.holes) {
|
||||||
|
if (hole.first_intersection(line, &new_back_temp)) {
|
||||||
|
if (!finded || line.a.distance_to(new_back_temp) < line.a.distance_to(new_back)) {
|
||||||
|
finded = true;
|
||||||
|
new_back = new_back_temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// safety check if no intersection
|
// safety check if no intersection
|
||||||
if (new_back.x == 0 && new_back.y == 0) {
|
if (!finded) {
|
||||||
if (!this->expolygon.contains(line.b)) {
|
if (!this->expolygon.contains(line.b)) {
|
||||||
//it's outside!!!
|
//it's outside!!!
|
||||||
std::cout << "Error, a line is formed that start in a polygon, end outside of it can don't cross it!\n";
|
if (!this->expolygon.contains(line.a)) {
|
||||||
|
std::cout << "Error, a line is formed that start outside a polygon, end outside of it and don't cross it!\n";
|
||||||
|
} else {
|
||||||
|
std::cout << "Error, a line is formed that start in a polygon, end outside of it and don't cross it!\n";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
new_back = line.b;
|
new_back = line.b;
|
||||||
}
|
}
|
||||||
@ -641,10 +655,19 @@ MedialAxis::extends_line(ThickPolyline& polyline, const ExPolygons& anchors, con
|
|||||||
polyline.width.push_back(polyline.width.back());
|
polyline.width.push_back(polyline.width.back());
|
||||||
}
|
}
|
||||||
Point new_bound;
|
Point new_bound;
|
||||||
//TODO: verify also for holes.
|
bool finded = bounds.contour.first_intersection(line, &new_bound);
|
||||||
(void)bounds.contour.first_intersection(line, &new_bound);
|
//verify also for holes.
|
||||||
|
Point new_bound_temp;
|
||||||
|
for (Polygon hole : bounds.holes) {
|
||||||
|
if (hole.first_intersection(line, &new_bound_temp)) {
|
||||||
|
if (!finded || line.a.distance_to(new_bound_temp) < line.a.distance_to(new_bound)) {
|
||||||
|
finded = true;
|
||||||
|
new_bound = new_bound_temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// safety check if no intersection
|
// safety check if no intersection
|
||||||
if (new_bound.x == 0 && new_bound.y == 0) {
|
if (!finded) {
|
||||||
if (line.b.coincides_with_epsilon(polyline.points.back())) {
|
if (line.b.coincides_with_epsilon(polyline.points.back())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1479,4 +1502,105 @@ MedialAxis::build(ThickPolylines* polylines_out)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ExtrusionEntityCollection thin_variable_width(const ThickPolylines &polylines, ExtrusionRole role, Flow flow) {
|
||||||
|
// this value determines granularity of adaptive width, as G-code does not allow
|
||||||
|
// variable extrusion within a single move; this value shall only affect the amount
|
||||||
|
// of segments, and any pruning shall be performed before we apply this tolerance
|
||||||
|
const double tolerance = scale_(0.05);
|
||||||
|
|
||||||
|
int id_line = 0;
|
||||||
|
ExtrusionEntityCollection coll;
|
||||||
|
for (const ThickPolyline &p : polylines) {
|
||||||
|
id_line++;
|
||||||
|
ExtrusionPaths paths;
|
||||||
|
ExtrusionPath path(role);
|
||||||
|
ThickLines lines = p.thicklines();
|
||||||
|
|
||||||
|
for (int i = 0; i < (int)lines.size(); ++i) {
|
||||||
|
const ThickLine& line = lines[i];
|
||||||
|
|
||||||
|
const coordf_t line_len = line.length();
|
||||||
|
if (line_len < SCALED_EPSILON) continue;
|
||||||
|
|
||||||
|
double thickness_delta = fabs(line.a_width - line.b_width);
|
||||||
|
if (thickness_delta > tolerance) {
|
||||||
|
const unsigned short segments = ceil(thickness_delta / tolerance);
|
||||||
|
const coordf_t seg_len = line_len / segments;
|
||||||
|
Points pp;
|
||||||
|
std::vector<coordf_t> width;
|
||||||
|
{
|
||||||
|
pp.push_back(line.a);
|
||||||
|
width.push_back(line.a_width);
|
||||||
|
for (size_t j = 1; j < segments; ++j) {
|
||||||
|
pp.push_back(line.point_at(j*seg_len));
|
||||||
|
|
||||||
|
coordf_t w = line.a_width + (j*seg_len) * (line.b_width - line.a_width) / line_len;
|
||||||
|
width.push_back(w);
|
||||||
|
width.push_back(w);
|
||||||
|
}
|
||||||
|
pp.push_back(line.b);
|
||||||
|
width.push_back(line.b_width);
|
||||||
|
|
||||||
|
assert(pp.size() == segments + 1);
|
||||||
|
assert(width.size() == segments * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete this line and insert new ones
|
||||||
|
lines.erase(lines.begin() + i);
|
||||||
|
for (size_t j = 0; j < segments; ++j) {
|
||||||
|
ThickLine new_line(pp[j], pp[j + 1]);
|
||||||
|
new_line.a_width = width[2 * j];
|
||||||
|
new_line.b_width = width[2 * j + 1];
|
||||||
|
lines.insert(lines.begin() + i + j, new_line);
|
||||||
|
}
|
||||||
|
|
||||||
|
--i;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const double w = fmax(line.a_width, line.b_width);
|
||||||
|
if (path.polyline.points.empty()) {
|
||||||
|
path.polyline.append(line.a);
|
||||||
|
path.polyline.append(line.b);
|
||||||
|
// Convert from spacing to extrusion width based on the extrusion model
|
||||||
|
// of a square extrusion ended with semi circles.
|
||||||
|
flow.width = unscale(w) + flow.height * (1. - 0.25 * PI);
|
||||||
|
#ifdef SLIC3R_DEBUG
|
||||||
|
printf(" filling %f gap\n", flow.width);
|
||||||
|
#endif
|
||||||
|
path.mm3_per_mm = flow.mm3_per_mm();
|
||||||
|
path.width = flow.width;
|
||||||
|
path.height = flow.height;
|
||||||
|
} else {
|
||||||
|
thickness_delta = fabs(scale_(flow.width) - w);
|
||||||
|
if (thickness_delta <= tolerance / 2) {
|
||||||
|
// the width difference between this line and the current flow width is
|
||||||
|
// within the accepted tolerance
|
||||||
|
path.polyline.append(line.b);
|
||||||
|
} else {
|
||||||
|
// we need to initialize a new line
|
||||||
|
paths.emplace_back(std::move(path));
|
||||||
|
path = ExtrusionPath(role);
|
||||||
|
--i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (path.polyline.is_valid())
|
||||||
|
paths.emplace_back(std::move(path));
|
||||||
|
// Append paths to collection.
|
||||||
|
if (!paths.empty()) {
|
||||||
|
if (paths.front().first_point().coincides_with(paths.back().last_point())) {
|
||||||
|
coll.append(ExtrusionLoop(paths));
|
||||||
|
} else {
|
||||||
|
//not a loop : avoid to "sort" it.
|
||||||
|
ExtrusionEntityCollection unsortable_coll(paths);
|
||||||
|
unsortable_coll.no_sort = true;
|
||||||
|
coll.append(unsortable_coll);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return coll;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
#include "ExPolygon.hpp"
|
#include "ExPolygon.hpp"
|
||||||
#include "Polyline.hpp"
|
#include "Polyline.hpp"
|
||||||
#include "Geometry.hpp"
|
#include "Geometry.hpp"
|
||||||
|
#include "ExtrusionEntityCollection.hpp"
|
||||||
|
#include "Flow.hpp"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "boost/polygon/voronoi.hpp"
|
#include "boost/polygon/voronoi.hpp"
|
||||||
@ -58,6 +60,9 @@ namespace Slic3r {
|
|||||||
void remove_too_short_polylines(ThickPolylines& pp, const coord_t min_size);
|
void remove_too_short_polylines(ThickPolylines& pp, const coord_t min_size);
|
||||||
void ensure_not_overextrude(ThickPolylines& pp);
|
void ensure_not_overextrude(ThickPolylines& pp);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ExtrusionEntityCollection thin_variable_width(const ThickPolylines &polylines, ExtrusionRole role, Flow flow);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -282,6 +282,7 @@ void PerimeterGenerator::process()
|
|||||||
no_thin_zone = diff_ex(last, offset_ex(half_thins, (float)(min_width / 2) - SCALED_EPSILON), true);
|
no_thin_zone = diff_ex(last, offset_ex(half_thins, (float)(min_width / 2) - SCALED_EPSILON), true);
|
||||||
}
|
}
|
||||||
// compute a bit of overlap to anchor thin walls inside the print.
|
// compute a bit of overlap to anchor thin walls inside the print.
|
||||||
|
ExPolygons thin_zones_extruded;
|
||||||
for (ExPolygon &half_thin : half_thins) {
|
for (ExPolygon &half_thin : half_thins) {
|
||||||
//growing back the polygon
|
//growing back the polygon
|
||||||
ExPolygons thin = offset_ex(half_thin, (float)(min_width / 2));
|
ExPolygons thin = offset_ex(half_thin, (float)(min_width / 2));
|
||||||
@ -298,11 +299,13 @@ void PerimeterGenerator::process()
|
|||||||
// the maximum thickness of our thin wall area is equal to the minimum thickness of a single loop
|
// the maximum thickness of our thin wall area is equal to the minimum thickness of a single loop
|
||||||
thin[0].medial_axis(bound, ext_perimeter_width + ext_perimeter_spacing2, min_width,
|
thin[0].medial_axis(bound, ext_perimeter_width + ext_perimeter_spacing2, min_width,
|
||||||
&thin_walls, this->layer_height);
|
&thin_walls, this->layer_height);
|
||||||
|
thin_zones_extruded.emplace_back(thin[0]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
next_onion = diff_ex(offset_ex(last, -(float)(ext_perimeter_width / 2)), thin_zones_extruded, true);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//FIXME Is this offset correct if the line width of the inner perimeters differs
|
//FIXME Is this offset correct if the line width of the inner perimeters differs
|
||||||
@ -445,7 +448,7 @@ void PerimeterGenerator::process()
|
|||||||
|
|
||||||
// append thin walls
|
// append thin walls
|
||||||
if (!thin_walls.empty()) {
|
if (!thin_walls.empty()) {
|
||||||
ExtrusionEntityCollection tw = this->_variable_width
|
ExtrusionEntityCollection tw = thin_variable_width
|
||||||
(thin_walls, erExternalPerimeter, this->ext_perimeter_flow);
|
(thin_walls, erExternalPerimeter, this->ext_perimeter_flow);
|
||||||
|
|
||||||
entities.append(tw.entities);
|
entities.append(tw.entities);
|
||||||
@ -485,7 +488,7 @@ void PerimeterGenerator::process()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!polylines.empty()) {
|
if (!polylines.empty()) {
|
||||||
ExtrusionEntityCollection gap_fill = this->_variable_width(polylines,
|
ExtrusionEntityCollection gap_fill = thin_variable_width(polylines,
|
||||||
erGapFill, this->solid_infill_flow);
|
erGapFill, this->solid_infill_flow);
|
||||||
this->gap_fill->append(gap_fill.entities);
|
this->gap_fill->append(gap_fill.entities);
|
||||||
/* Make sure we don't infill narrow parts that are already gap-filled
|
/* Make sure we don't infill narrow parts that are already gap-filled
|
||||||
@ -605,7 +608,7 @@ ExtrusionEntityCollection PerimeterGenerator::_traverse_loops(
|
|||||||
|
|
||||||
// append thin walls to the nearest-neighbor search (only for first iteration)
|
// append thin walls to the nearest-neighbor search (only for first iteration)
|
||||||
if (!thin_walls.empty()) {
|
if (!thin_walls.empty()) {
|
||||||
ExtrusionEntityCollection tw = this->_variable_width
|
ExtrusionEntityCollection tw = thin_variable_width
|
||||||
(thin_walls, erExternalPerimeter, this->ext_perimeter_flow);
|
(thin_walls, erExternalPerimeter, this->ext_perimeter_flow);
|
||||||
|
|
||||||
coll.append(tw.entities);
|
coll.append(tw.entities);
|
||||||
@ -1219,109 +1222,6 @@ PerimeterGenerator::_traverse_and_join_loops(const PerimeterGeneratorLoop &loop,
|
|||||||
return my_loop;
|
return my_loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ExtrusionEntityCollection PerimeterGenerator::_variable_width(const ThickPolylines &polylines, ExtrusionRole role, Flow flow) const
|
|
||||||
{
|
|
||||||
// this value determines granularity of adaptive width, as G-code does not allow
|
|
||||||
// variable extrusion within a single move; this value shall only affect the amount
|
|
||||||
// of segments, and any pruning shall be performed before we apply this tolerance
|
|
||||||
const double tolerance = scale_(0.05);
|
|
||||||
|
|
||||||
int id_line = 0;
|
|
||||||
ExtrusionEntityCollection coll;
|
|
||||||
for (const ThickPolyline &p : polylines) {
|
|
||||||
id_line++;
|
|
||||||
ExtrusionPaths paths;
|
|
||||||
ExtrusionPath path(role);
|
|
||||||
ThickLines lines = p.thicklines();
|
|
||||||
|
|
||||||
for (int i = 0; i < (int)lines.size(); ++i) {
|
|
||||||
const ThickLine& line = lines[i];
|
|
||||||
|
|
||||||
const coordf_t line_len = line.length();
|
|
||||||
if (line_len < SCALED_EPSILON) continue;
|
|
||||||
|
|
||||||
double thickness_delta = fabs(line.a_width - line.b_width);
|
|
||||||
if (thickness_delta > tolerance) {
|
|
||||||
const unsigned short segments = ceil(thickness_delta / tolerance);
|
|
||||||
const coordf_t seg_len = line_len / segments;
|
|
||||||
Points pp;
|
|
||||||
std::vector<coordf_t> width;
|
|
||||||
{
|
|
||||||
pp.push_back(line.a);
|
|
||||||
width.push_back(line.a_width);
|
|
||||||
for (size_t j = 1; j < segments; ++j) {
|
|
||||||
pp.push_back(line.point_at(j*seg_len));
|
|
||||||
|
|
||||||
coordf_t w = line.a_width + (j*seg_len) * (line.b_width-line.a_width) / line_len;
|
|
||||||
width.push_back(w);
|
|
||||||
width.push_back(w);
|
|
||||||
}
|
|
||||||
pp.push_back(line.b);
|
|
||||||
width.push_back(line.b_width);
|
|
||||||
|
|
||||||
assert(pp.size() == segments + 1);
|
|
||||||
assert(width.size() == segments*2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// delete this line and insert new ones
|
|
||||||
lines.erase(lines.begin() + i);
|
|
||||||
for (size_t j = 0; j < segments; ++j) {
|
|
||||||
ThickLine new_line(pp[j], pp[j+1]);
|
|
||||||
new_line.a_width = width[2*j];
|
|
||||||
new_line.b_width = width[2*j+1];
|
|
||||||
lines.insert(lines.begin() + i + j, new_line);
|
|
||||||
}
|
|
||||||
|
|
||||||
--i;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const double w = fmax(line.a_width, line.b_width);
|
|
||||||
if (path.polyline.points.empty()) {
|
|
||||||
path.polyline.append(line.a);
|
|
||||||
path.polyline.append(line.b);
|
|
||||||
// Convert from spacing to extrusion width based on the extrusion model
|
|
||||||
// of a square extrusion ended with semi circles.
|
|
||||||
flow.width = unscale(w) + flow.height * (1. - 0.25 * PI);
|
|
||||||
#ifdef SLIC3R_DEBUG
|
|
||||||
printf(" filling %f gap\n", flow.width);
|
|
||||||
#endif
|
|
||||||
path.mm3_per_mm = flow.mm3_per_mm();
|
|
||||||
path.width = flow.width;
|
|
||||||
path.height = flow.height;
|
|
||||||
} else {
|
|
||||||
thickness_delta = fabs(scale_(flow.width) - w);
|
|
||||||
if (thickness_delta <= tolerance/2) {
|
|
||||||
// the width difference between this line and the current flow width is
|
|
||||||
// within the accepted tolerance
|
|
||||||
path.polyline.append(line.b);
|
|
||||||
} else {
|
|
||||||
// we need to initialize a new line
|
|
||||||
paths.emplace_back(std::move(path));
|
|
||||||
path = ExtrusionPath(role);
|
|
||||||
--i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (path.polyline.is_valid())
|
|
||||||
paths.emplace_back(std::move(path));
|
|
||||||
// Append paths to collection.
|
|
||||||
if (!paths.empty()) {
|
|
||||||
if (paths.front().first_point().coincides_with(paths.back().last_point())) {
|
|
||||||
coll.append(ExtrusionLoop(paths));
|
|
||||||
} else {
|
|
||||||
//not a loop : avoid to "sort" it.
|
|
||||||
ExtrusionEntityCollection unsortable_coll(paths);
|
|
||||||
unsortable_coll.no_sort = true;
|
|
||||||
coll.append(unsortable_coll);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return coll;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PerimeterGeneratorLoop::is_internal_contour() const
|
bool PerimeterGeneratorLoop::is_internal_contour() const
|
||||||
{
|
{
|
||||||
// An internal contour is a contour containing no other contours
|
// An internal contour is a contour containing no other contours
|
||||||
|
@ -99,13 +99,10 @@ private:
|
|||||||
double _mm3_per_mm_overhang;
|
double _mm3_per_mm_overhang;
|
||||||
Polygons _lower_slices_p;
|
Polygons _lower_slices_p;
|
||||||
|
|
||||||
ExtrusionEntityCollection _traverse_loops(const PerimeterGeneratorLoops &loops,
|
ExtrusionEntityCollection _traverse_loops(const PerimeterGeneratorLoops &loops, ThickPolylines &thin_walls) const;
|
||||||
ThickPolylines &thin_walls) const;
|
|
||||||
ExtrusionLoop _traverse_and_join_loops(const PerimeterGeneratorLoop &loop, const PerimeterGeneratorLoops &childs, const Point entryPoint) const;
|
ExtrusionLoop _traverse_and_join_loops(const PerimeterGeneratorLoop &loop, const PerimeterGeneratorLoops &childs, const Point entryPoint) const;
|
||||||
ExtrusionLoop _extrude_and_cut_loop(const PerimeterGeneratorLoop &loop, const Point entryPoint, const Line &direction = Line(Point(0,0),Point(0,0))) const;
|
ExtrusionLoop _extrude_and_cut_loop(const PerimeterGeneratorLoop &loop, const Point entryPoint, const Line &direction = Line(Point(0,0),Point(0,0))) const;
|
||||||
PerimeterIntersectionPoint _get_nearest_point(const PerimeterGeneratorLoops &children, ExtrusionLoop &myPolylines, const coord_t dist_cut, const coord_t max_dist) const;
|
PerimeterIntersectionPoint _get_nearest_point(const PerimeterGeneratorLoops &children, ExtrusionLoop &myPolylines, const coord_t dist_cut, const coord_t max_dist) const;
|
||||||
ExtrusionEntityCollection _variable_width
|
|
||||||
(const ThickPolylines &polylines, ExtrusionRole role, Flow flow) const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -316,6 +316,7 @@ PrintConfigDef::PrintConfigDef()
|
|||||||
def->enum_keys_map = &ConfigOptionEnum<InfillPattern>::get_enum_values();
|
def->enum_keys_map = &ConfigOptionEnum<InfillPattern>::get_enum_values();
|
||||||
def->enum_values.push_back("rectilinear");
|
def->enum_values.push_back("rectilinear");
|
||||||
def->enum_values.push_back("concentric");
|
def->enum_values.push_back("concentric");
|
||||||
|
def->enum_values.push_back("concentricgapfill");
|
||||||
def->enum_values.push_back("hilbertcurve");
|
def->enum_values.push_back("hilbertcurve");
|
||||||
def->enum_values.push_back("archimedeanchords");
|
def->enum_values.push_back("archimedeanchords");
|
||||||
def->enum_values.push_back("octagramspiral");
|
def->enum_values.push_back("octagramspiral");
|
||||||
@ -324,10 +325,11 @@ PrintConfigDef::PrintConfigDef()
|
|||||||
def->enum_values.push_back("smoothhilbert");
|
def->enum_values.push_back("smoothhilbert");
|
||||||
def->enum_labels.push_back(L("Rectilinear"));
|
def->enum_labels.push_back(L("Rectilinear"));
|
||||||
def->enum_labels.push_back(L("Concentric"));
|
def->enum_labels.push_back(L("Concentric"));
|
||||||
|
def->enum_labels.push_back(L("Concentric (filled)"));
|
||||||
def->enum_labels.push_back(L("Hilbert Curve"));
|
def->enum_labels.push_back(L("Hilbert Curve"));
|
||||||
def->enum_labels.push_back(L("Archimedean Chords"));
|
def->enum_labels.push_back(L("Archimedean Chords"));
|
||||||
def->enum_labels.push_back(L("Octagram Spiral"));
|
def->enum_labels.push_back(L("Octagram Spiral"));
|
||||||
def->enum_labels.push_back("Ironing");
|
def->enum_labels.push_back(L("Ironing"));
|
||||||
// solid_fill_pattern is an obsolete equivalent to top_fill_pattern/bottom_fill_pattern.
|
// solid_fill_pattern is an obsolete equivalent to top_fill_pattern/bottom_fill_pattern.
|
||||||
def->aliases = { "solid_fill_pattern" };
|
def->aliases = { "solid_fill_pattern" };
|
||||||
def->default_value = new ConfigOptionEnum<InfillPattern>(ipRectilinear);
|
def->default_value = new ConfigOptionEnum<InfillPattern>(ipRectilinear);
|
||||||
@ -340,14 +342,16 @@ PrintConfigDef::PrintConfigDef()
|
|||||||
def->enum_keys_map = &ConfigOptionEnum<InfillPattern>::get_enum_values();
|
def->enum_keys_map = &ConfigOptionEnum<InfillPattern>::get_enum_values();
|
||||||
def->enum_values.push_back("rectilinear");
|
def->enum_values.push_back("rectilinear");
|
||||||
def->enum_values.push_back("concentric");
|
def->enum_values.push_back("concentric");
|
||||||
|
def->enum_values.push_back("concentricgapfill");
|
||||||
def->enum_values.push_back("hilbertcurve");
|
def->enum_values.push_back("hilbertcurve");
|
||||||
def->enum_values.push_back("archimedeanchords");
|
def->enum_values.push_back("archimedeanchords");
|
||||||
def->enum_values.push_back("octagramspiral");
|
def->enum_values.push_back("octagramspiral");
|
||||||
def->enum_labels.push_back("Rectilinear");
|
def->enum_labels.push_back(L("Rectilinear"));
|
||||||
def->enum_labels.push_back("Concentric");
|
def->enum_labels.push_back(L("Concentric"));
|
||||||
def->enum_labels.push_back("Hilbert Curve");
|
def->enum_labels.push_back(L("Concentric (filled)"));
|
||||||
def->enum_labels.push_back("Archimedean Chords");
|
def->enum_labels.push_back(L("Hilbert Curve"));
|
||||||
def->enum_labels.push_back("Octagram Spiral");
|
def->enum_labels.push_back(L("Archimedean Chords"));
|
||||||
|
def->enum_labels.push_back(L("Octagram Spiral"));
|
||||||
def->default_value = new ConfigOptionEnum<InfillPattern>(ipRectilinear);
|
def->default_value = new ConfigOptionEnum<InfillPattern>(ipRectilinear);
|
||||||
|
|
||||||
def = this->add("enforce_full_fill_volume", coBool);
|
def = this->add("enforce_full_fill_volume", coBool);
|
||||||
@ -819,6 +823,7 @@ PrintConfigDef::PrintConfigDef()
|
|||||||
def->enum_values.push_back("cubic");
|
def->enum_values.push_back("cubic");
|
||||||
def->enum_values.push_back("line");
|
def->enum_values.push_back("line");
|
||||||
def->enum_values.push_back("concentric");
|
def->enum_values.push_back("concentric");
|
||||||
|
def->enum_values.push_back("concentricgapfill");
|
||||||
def->enum_values.push_back("honeycomb");
|
def->enum_values.push_back("honeycomb");
|
||||||
def->enum_values.push_back("3dhoneycomb");
|
def->enum_values.push_back("3dhoneycomb");
|
||||||
def->enum_values.push_back("gyroid");
|
def->enum_values.push_back("gyroid");
|
||||||
@ -832,6 +837,7 @@ PrintConfigDef::PrintConfigDef()
|
|||||||
def->enum_labels.push_back(L("Cubic"));
|
def->enum_labels.push_back(L("Cubic"));
|
||||||
def->enum_labels.push_back(L("Line"));
|
def->enum_labels.push_back(L("Line"));
|
||||||
def->enum_labels.push_back(L("Concentric"));
|
def->enum_labels.push_back(L("Concentric"));
|
||||||
|
def->enum_labels.push_back(L("Concentric (filled)"));
|
||||||
def->enum_labels.push_back(L("Honeycomb"));
|
def->enum_labels.push_back(L("Honeycomb"));
|
||||||
def->enum_labels.push_back(L("3D Honeycomb"));
|
def->enum_labels.push_back(L("3D Honeycomb"));
|
||||||
def->enum_labels.push_back(L("Gyroid"));
|
def->enum_labels.push_back(L("Gyroid"));
|
||||||
|
@ -34,7 +34,7 @@ enum PrintHostType {
|
|||||||
enum InfillPattern {
|
enum InfillPattern {
|
||||||
ipRectilinear, ipGrid, ipTriangles, ipStars, ipCubic, ipLine, ipConcentric, ipHoneycomb, ip3DHoneycomb,
|
ipRectilinear, ipGrid, ipTriangles, ipStars, ipCubic, ipLine, ipConcentric, ipHoneycomb, ip3DHoneycomb,
|
||||||
ipGyroid, ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral, ipSmooth, ipSmoothHilbert, ipSmoothTriple,
|
ipGyroid, ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral, ipSmooth, ipSmoothHilbert, ipSmoothTriple,
|
||||||
ipRectiWithPerimeter,
|
ipRectiWithPerimeter, ipConcentricGapFill
|
||||||
};
|
};
|
||||||
|
|
||||||
enum SupportMaterialPattern {
|
enum SupportMaterialPattern {
|
||||||
@ -89,6 +89,7 @@ template<> inline t_config_enum_values& ConfigOptionEnum<InfillPattern>::get_enu
|
|||||||
keys_map["cubic"] = ipCubic;
|
keys_map["cubic"] = ipCubic;
|
||||||
keys_map["line"] = ipLine;
|
keys_map["line"] = ipLine;
|
||||||
keys_map["concentric"] = ipConcentric;
|
keys_map["concentric"] = ipConcentric;
|
||||||
|
keys_map["concentricgapfill"] = ipConcentricGapFill;
|
||||||
keys_map["honeycomb"] = ipHoneycomb;
|
keys_map["honeycomb"] = ipHoneycomb;
|
||||||
keys_map["3dhoneycomb"] = ip3DHoneycomb;
|
keys_map["3dhoneycomb"] = ip3DHoneycomb;
|
||||||
keys_map["gyroid"] = ipGyroid;
|
keys_map["gyroid"] = ipGyroid;
|
||||||
|
@ -3098,7 +3098,7 @@ void PrintObjectSupportMaterial::generate_toolpaths(
|
|||||||
size_t idx_layer_top_contact = size_t(-1);
|
size_t idx_layer_top_contact = size_t(-1);
|
||||||
size_t idx_layer_intermediate = size_t(-1);
|
size_t idx_layer_intermediate = size_t(-1);
|
||||||
size_t idx_layer_inteface = size_t(-1);
|
size_t idx_layer_inteface = size_t(-1);
|
||||||
std::unique_ptr<Fill> filler_interface = std::unique_ptr<Fill>(Fill::new_from_type(m_slicing_params.soluble_interface ? ipConcentric : ipRectilinear));
|
std::unique_ptr<Fill> filler_interface = std::unique_ptr<Fill>(Fill::new_from_type(m_slicing_params.soluble_interface ? ipConcentricGapFill : ipRectilinear));
|
||||||
std::unique_ptr<Fill> filler_support = std::unique_ptr<Fill>(Fill::new_from_type(infill_pattern));
|
std::unique_ptr<Fill> filler_support = std::unique_ptr<Fill>(Fill::new_from_type(infill_pattern));
|
||||||
std::unique_ptr<Fill> filler_solid = std::unique_ptr<Fill>(Fill::new_from_type(ipRectiWithPerimeter));
|
std::unique_ptr<Fill> filler_solid = std::unique_ptr<Fill>(Fill::new_from_type(ipRectiWithPerimeter));
|
||||||
filler_interface->set_bounding_box(bbox_object);
|
filler_interface->set_bounding_box(bbox_object);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user