mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-08-13 20:35:53 +08:00
change elepehant foot direction (again)
use reference in medial axis add comments in medial axis
This commit is contained in:
parent
6df17e1dd1
commit
26d17e03ee
@ -219,17 +219,11 @@ ExPolygon::remove_point_too_near(const coord_t tolerance) {
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ExPolygon::medial_axis(const ExPolygon &bounds, double max_width, double min_width, ThickPolylines* polylines, double height) const {
|
||||
Slic3r::MedialAxis ma(*this, bounds, (coord_t)max_width, (coord_t)min_width, height);
|
||||
ma.build(polylines);
|
||||
}
|
||||
|
||||
void
|
||||
ExPolygon::medial_axis(double max_width, double min_width, Polylines* polylines) const
|
||||
{
|
||||
ThickPolylines tp;
|
||||
this->medial_axis(*this, max_width, min_width, &tp, max_width/2.0);
|
||||
MedialAxis{ *this, coord_t(max_width), coord_t(min_width), coord_t(max_width / 2.0) }.build(tp);
|
||||
polylines->insert(polylines->end(), tp.begin(), tp.end());
|
||||
}
|
||||
|
||||
|
@ -57,7 +57,6 @@ public:
|
||||
ExPolygons simplify(double tolerance) const;
|
||||
void simplify(double tolerance, ExPolygons* expolygons) const;
|
||||
void remove_point_too_near(const coord_t tolerance);
|
||||
void medial_axis(const ExPolygon &bounds, double max_width, double min_width, ThickPolylines* polylines, double height) const;
|
||||
void medial_axis(double max_width, double min_width, Polylines* polylines) const;
|
||||
// void get_trapezoids(Polygons* polygons) const;
|
||||
// void get_trapezoids(Polygons* polygons, double angle) const;
|
||||
|
@ -138,7 +138,7 @@ void FillConcentricWGapFill::fill_surface_extrusion(const Surface *surface, cons
|
||||
//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, params.flow->height);
|
||||
MedialAxis{ ex, coord_t(max), coord_t(min), coord_t(params.flow->height) }.build(polylines);
|
||||
}
|
||||
}
|
||||
if (!polylines.empty() && good_role != erBridgeInfill) {
|
||||
|
@ -1774,7 +1774,8 @@ FillRectilinear2WGapFill::fill_surface_extrusion(const Surface *surface, const F
|
||||
ExtrusionRole good_role = getRoleFromSurfaceType(params, surface);
|
||||
|
||||
// remove areas for gapfill
|
||||
ExPolygons rectilinear_areas = offset2_ex(ExPolygons{ surface->expolygon }, -params.flow->scaled_spacing() * 0.8f, params.flow->scaled_spacing() * 0.8f);
|
||||
float factor = 1; // 0.8f;
|
||||
ExPolygons rectilinear_areas = offset2_ex(ExPolygons{ surface->expolygon }, -params.flow->scaled_spacing() * factor, params.flow->scaled_spacing() * factor);
|
||||
ExPolygons gapfill_areas = diff_ex(ExPolygons{ surface->expolygon }, rectilinear_areas);
|
||||
double rec_area = 0;
|
||||
for (ExPolygon &p : rectilinear_areas)rec_area += p.area();
|
||||
@ -1854,7 +1855,7 @@ FillRectilinear2WGapFill::fill_surface_extrusion(const Surface *surface, const F
|
||||
//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, params.flow->scaled_width()*2, params.flow->scaled_width()/5, &polylines_gapfill, params.flow->height);
|
||||
MedialAxis{ ex, params.flow->scaled_width() * 2, params.flow->scaled_width() / 5, coord_t(params.flow->height) }.build(polylines_gapfill);
|
||||
}
|
||||
}
|
||||
if (!polylines_gapfill.empty() && good_role != erBridgeInfill) {
|
||||
|
@ -1,3 +1,4 @@
|
||||
#include "MedialAxis.hpp"
|
||||
#include "BoundingBox.hpp"
|
||||
#include "ExPolygon.hpp"
|
||||
#include "Geometry.hpp"
|
||||
@ -13,14 +14,12 @@
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
int MedialAxis::id = 0;
|
||||
|
||||
void
|
||||
MedialAxis::build(Polylines* polylines)
|
||||
MedialAxis::build(Polylines &polylines)
|
||||
{
|
||||
ThickPolylines tp;
|
||||
this->build(&tp);
|
||||
polylines->insert(polylines->end(), tp.begin(), tp.end());
|
||||
this->build(tp);
|
||||
polylines.insert(polylines.end(), tp.begin(), tp.end());
|
||||
}
|
||||
|
||||
void
|
||||
@ -353,7 +352,9 @@ add_point_same_percent(ThickPolyline* pattern, ThickPolyline* to_modify)
|
||||
coordf_t new_width = to_modify->width[idx_other - 1] * (1 - percent_dist);
|
||||
new_width += to_modify->width[idx_other] * (percent_dist);
|
||||
to_modify->width.insert(to_modify->width.begin() + idx_other, new_width);
|
||||
to_modify->points.insert(to_modify->points.begin() + idx_other, to_modify->points[idx_other - 1].interpolate(percent_dist, to_modify->points[idx_other]));
|
||||
to_modify->points.insert(
|
||||
to_modify->points.begin() + idx_other,
|
||||
to_modify->points[idx_other - 1].interpolate(percent_dist, to_modify->points[idx_other]));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -455,7 +456,7 @@ MedialAxis::fusion_curve(ThickPolylines &pp)
|
||||
|
||||
size_t closest_point_idx = this->expolygon.contour.closest_point_index(polyline.points.back());
|
||||
|
||||
//check the 0-wodth point is on the contour.
|
||||
//check the 0-width point is on the contour.
|
||||
if (closest_point_idx == (size_t)-1) continue;
|
||||
|
||||
size_t prev_idx = closest_point_idx == 0 ? this->expolygon.contour.points.size() - 1 : closest_point_idx - 1;
|
||||
@ -616,7 +617,7 @@ MedialAxis::fusion_corners(ThickPolylines &pp)
|
||||
|
||||
void
|
||||
MedialAxis::extends_line_both_side(ThickPolylines& pp) {
|
||||
const ExPolygons anchors = offset2_ex(diff_ex(this->bounds, this->expolygon), double(-SCALED_RESOLUTION), double(SCALED_RESOLUTION));
|
||||
const ExPolygons anchors = offset2_ex(diff_ex(*this->bounds, this->expolygon), double(-SCALED_RESOLUTION), double(SCALED_RESOLUTION));
|
||||
for (size_t i = 0; i < pp.size(); ++i) {
|
||||
ThickPolyline& polyline = pp[i];
|
||||
this->extends_line(polyline, anchors, this->min_width);
|
||||
@ -632,7 +633,7 @@ MedialAxis::extends_line(ThickPolyline& polyline, const ExPolygons& anchors, con
|
||||
// We assign new endpoints to temporary variables because in case of a single-line
|
||||
// polyline, after we extend the start point it will be caught by the intersection()
|
||||
// call, so we keep the inner point until we perform the second intersection() as well
|
||||
if (polyline.endpoints.second && !bounds.has_boundary_point(polyline.points.back())) {
|
||||
if (polyline.endpoints.second && !bounds->has_boundary_point(polyline.points.back())) {
|
||||
size_t first_idx = polyline.points.size() - 2;
|
||||
Line line(*(polyline.points.begin() + first_idx), polyline.points.back());
|
||||
while (line.length() < SCALED_RESOLUTION && first_idx>0) {
|
||||
@ -674,10 +675,10 @@ MedialAxis::extends_line(ThickPolyline& polyline, const ExPolygons& anchors, con
|
||||
polyline.width.push_back(polyline.width.back());
|
||||
}
|
||||
Point new_bound;
|
||||
bool finded = bounds.contour.first_intersection(line, &new_bound);
|
||||
bool finded = bounds->contour.first_intersection(line, &new_bound);
|
||||
//verify also for holes.
|
||||
Point new_bound_temp;
|
||||
for (Polygon hole : bounds.holes) {
|
||||
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;
|
||||
@ -687,9 +688,8 @@ MedialAxis::extends_line(ThickPolyline& polyline, const ExPolygons& anchors, con
|
||||
}
|
||||
// safety check if no intersection
|
||||
if (!finded) {
|
||||
if (line.b.coincides_with_epsilon(polyline.points.back())) {
|
||||
if (line.b.coincides_with_epsilon(polyline.points.back()))
|
||||
return;
|
||||
}
|
||||
//check if we don't over-shoot inside us
|
||||
bool is_in_anchor = false;
|
||||
for (const ExPolygon& a : anchors) {
|
||||
@ -724,7 +724,7 @@ MedialAxis::extends_line(ThickPolyline& polyline, const ExPolygons& anchors, con
|
||||
p_obj.y() /= 2;
|
||||
Line l2 = Line(new_back, p_obj);
|
||||
l2.extend_end(max_width);
|
||||
(void)bounds.contour.first_intersection(l2, &new_bound);
|
||||
(void)bounds->contour.first_intersection(l2, &new_bound);
|
||||
}
|
||||
if (new_bound.coincides_with_epsilon(new_back)) {
|
||||
return;
|
||||
@ -983,6 +983,8 @@ MedialAxis::main_fusion(ThickPolylines& pp)
|
||||
coord_t max_width_from_main = std::sqrt(main_branch_width*main_branch_width + main_branch_dist*main_branch_dist);
|
||||
if (find_main_branch && polyline.width[idx_point] > max_width_from_main)
|
||||
polyline.width[idx_point] = max_width_from_main;
|
||||
if (find_main_branch && polyline.width[idx_point] > pp[biggest_main_branch_id].width.front() * 1.1)
|
||||
polyline.width[idx_point] = pp[biggest_main_branch_id].width.front() * 1.1;
|
||||
//std::cout << "main fusion, max dist : " << max_width_from_main << "\n";
|
||||
|
||||
++idx_point;
|
||||
@ -1025,7 +1027,7 @@ MedialAxis::main_fusion(ThickPolylines& pp)
|
||||
}
|
||||
//remove points that are outside of the geometry
|
||||
for (size_t idx_point = 0; idx_point < polyline.points.size(); ++idx_point) {
|
||||
if (!bounds.contains_b(polyline.points[idx_point])) {
|
||||
if (!bounds->contains_b(polyline.points[idx_point])) {
|
||||
polyline.points.erase(polyline.points.begin() + idx_point);
|
||||
polyline.width.erase(polyline.width.begin() + idx_point);
|
||||
--idx_point;
|
||||
@ -1173,7 +1175,7 @@ MedialAxis::concatenate_polylines_with_crossing(ThickPolylines& pp)
|
||||
best_dot = other_dot;
|
||||
}
|
||||
}
|
||||
if (best_candidate != nullptr && best_candidate->size() > 1) {
|
||||
if (best_candidate != nullptr && best_candidate->points.size() > 1) {
|
||||
if (polyline.last_point().coincides_with(best_candidate->last_point())) {
|
||||
best_candidate->reverse();
|
||||
} else if (polyline.first_point().coincides_with(best_candidate->last_point())) {
|
||||
@ -1302,12 +1304,12 @@ MedialAxis::ensure_not_overextrude(ThickPolylines& pp)
|
||||
|
||||
// compute bounds volume
|
||||
double boundsVolume = 0;
|
||||
boundsVolume += height*bounds.area();
|
||||
boundsVolume += height*bounds->area();
|
||||
// add external "perimeter gap"
|
||||
double perimeterRoundGap = bounds.contour.length() * height * (1 - 0.25*PI) * 0.5;
|
||||
double perimeterRoundGap = bounds->contour.length() * height * (1 - 0.25*PI) * 0.5;
|
||||
// add holes "perimeter gaps"
|
||||
double holesGaps = 0;
|
||||
for (const Polygon &hole : bounds.holes) {
|
||||
for (const Polygon &hole : bounds->holes) {
|
||||
holesGaps += hole.length() * height * (1 - 0.25*PI) * 0.5;
|
||||
}
|
||||
boundsVolume += perimeterRoundGap + holesGaps;
|
||||
@ -1323,59 +1325,66 @@ MedialAxis::ensure_not_overextrude(ThickPolylines& pp)
|
||||
}
|
||||
}
|
||||
|
||||
ExPolygon
|
||||
void
|
||||
MedialAxis::simplify_polygon_frontier()
|
||||
{
|
||||
//simplify the boundary between us and the bounds.
|
||||
ExPolygon simplified_poly = this->surface;
|
||||
simplified_poly.contour.remove_colinear_points(SCALED_EPSILON);
|
||||
for (Polygon &hole : simplified_poly.holes)
|
||||
hole.remove_colinear_points(SCALED_EPSILON);
|
||||
//it will remove every point in the surface contour that aren't on the bounds contour
|
||||
if (&this->surface != &this->bounds) {
|
||||
this->expolygon = this->surface;
|
||||
this->expolygon.contour.remove_collinear_points(SCALED_EPSILON);
|
||||
for (Polygon &hole : this->expolygon.holes)
|
||||
hole.remove_collinear_points(SCALED_EPSILON);
|
||||
if (&this->surface != this->bounds) {
|
||||
bool need_intersect = false;
|
||||
for (size_t i = 0; i < simplified_poly.contour.points.size(); i++) {
|
||||
Point &p_check = simplified_poly.contour.points[i];
|
||||
for (size_t i = 0; i < this->expolygon.contour.points.size(); i++) {
|
||||
Point &p_check = this->expolygon.contour.points[i];
|
||||
//if (!find) {
|
||||
if (!bounds.has_boundary_point(p_check)) {
|
||||
if (!bounds->has_boundary_point(p_check)) {
|
||||
//check if we put it at a bound point instead of delete it
|
||||
size_t prev_i = i == 0 ? simplified_poly.contour.points.size() - 1 : (i - 1);
|
||||
size_t next_i = i == simplified_poly.contour.points.size() - 1 ? 0 : (i + 1);
|
||||
const Point* closest = bounds.contour.closest_point(p_check);
|
||||
size_t prev_i = i == 0 ? this->expolygon.contour.points.size() - 1 : (i - 1);
|
||||
size_t next_i = i == this->expolygon.contour.points.size() - 1 ? 0 : (i + 1);
|
||||
const Point* closest = bounds->contour.closest_point(p_check);
|
||||
if (closest != nullptr && closest->distance_to(p_check) + SCALED_EPSILON
|
||||
< std::min(p_check.distance_to(simplified_poly.contour.points[prev_i]), p_check.distance_to(simplified_poly.contour.points[next_i])) / 2) {
|
||||
< std::min(p_check.distance_to(this->expolygon.contour.points[prev_i]), p_check.distance_to(this->expolygon.contour.points[next_i])) / 2) {
|
||||
p_check.x() = closest->x();
|
||||
p_check.y() = closest->y();
|
||||
need_intersect = true;
|
||||
} else {
|
||||
simplified_poly.contour.points.erase(simplified_poly.contour.points.begin() + i);
|
||||
this->expolygon.contour.points.erase(this->expolygon.contour.points.begin() + i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (need_intersect) {
|
||||
ExPolygons simplified_polys = intersection_ex(simplified_poly, bounds);
|
||||
if (simplified_polys.size() == 1) {
|
||||
simplified_poly = simplified_polys[0];
|
||||
ExPolygons simplified_polygons = intersection_ex(this->expolygon, *bounds);
|
||||
if (simplified_polygons.size() == 1) {
|
||||
this->expolygon = simplified_polygons[0];
|
||||
} else {
|
||||
simplified_poly = this->surface;
|
||||
//can't simplify that much, reuse the given one
|
||||
this->expolygon = this->surface;
|
||||
this->expolygon.contour.remove_collinear_points(SCALED_EPSILON);
|
||||
for (Polygon &hole : this->expolygon.holes)
|
||||
hole.remove_collinear_points(SCALED_EPSILON);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!simplified_poly.contour.points.empty())
|
||||
simplified_poly.remove_point_too_near((coord_t)SCALED_RESOLUTION);
|
||||
return simplified_poly;
|
||||
if (!this->expolygon.contour.points.empty())
|
||||
this->expolygon.remove_point_too_near((coord_t)SCALED_RESOLUTION);
|
||||
}
|
||||
|
||||
/// Grow the extrusion to at least nozzle_diameter*1.05 (lowest safe extrusion width)
|
||||
/// Do not grow points inside the anchor.
|
||||
void
|
||||
MedialAxis::grow_to_nozzle_diameter(ThickPolylines& pp, const ExPolygons& anchors) {
|
||||
MedialAxis::grow_to_nozzle_diameter(ThickPolylines& pp, const ExPolygons& anchors)
|
||||
{
|
||||
//compute the min width
|
||||
coord_t min_width = this->nozzle_diameter;
|
||||
if (this->height > 0)min_width = Flow::new_from_spacing(float(unscale_(this->nozzle_diameter)), float(unscale_(this->nozzle_diameter)), float(unscale_(this->height)), false).scaled_width();
|
||||
//ensure the width is not lower than 0.4.
|
||||
if (this->height > 0) min_width = Flow::new_from_spacing(
|
||||
float(unscale_(this->nozzle_diameter)),
|
||||
float(unscale_(this->nozzle_diameter)),
|
||||
float(unscale_(this->height)), false).scaled_width();
|
||||
//ensure the width is not lower than min_width.
|
||||
for (ThickPolyline& polyline : pp) {
|
||||
for (int i = 0; i < polyline.points.size(); ++i) {
|
||||
bool is_anchored = false;
|
||||
@ -1392,10 +1401,11 @@ MedialAxis::grow_to_nozzle_diameter(ThickPolylines& pp, const ExPolygons& anchor
|
||||
}
|
||||
|
||||
void
|
||||
MedialAxis::taper_ends(ThickPolylines& pp) {
|
||||
MedialAxis::taper_ends(ThickPolylines& pp)
|
||||
{
|
||||
// minimum size of the taper: be sure to extrude at least the "round edges" of the extrusion (0-spacing extrusion).
|
||||
const coord_t min_size = std::max(this->nozzle_diameter * 0.1, this->height * (1. - 0.25 * PI));
|
||||
const coordf_t length = std::min(this->anchor_size, (this->nozzle_diameter - min_size) / 2);
|
||||
const coordf_t length = std::min(this->taper_size, (this->nozzle_diameter - min_size) / 2);
|
||||
if (length <= SCALED_RESOLUTION) return;
|
||||
//ensure the width is not lower than min_size.
|
||||
for (ThickPolyline& polyline : pp) {
|
||||
@ -1442,8 +1452,8 @@ MedialAxis::taper_ends(ThickPolylines& pp) {
|
||||
}
|
||||
|
||||
void
|
||||
MedialAxis::build(ThickPolylines* polylines_out) {
|
||||
this->id++;
|
||||
MedialAxis::build(ThickPolylines &polylines_out)
|
||||
{
|
||||
//std::cout << this->id << "\n";
|
||||
//{
|
||||
// std::stringstream stri;
|
||||
@ -1452,7 +1462,7 @@ MedialAxis::build(ThickPolylines* polylines_out) {
|
||||
// svg.draw(this->surface);
|
||||
// svg.Close();
|
||||
//}
|
||||
this->expolygon = simplify_polygon_frontier();
|
||||
simplify_polygon_frontier();
|
||||
//{
|
||||
// std::stringstream stri;
|
||||
// stri << "medial_axis_0.5_simplified_" << id << ".svg";
|
||||
@ -1612,7 +1622,9 @@ MedialAxis::build(ThickPolylines* polylines_out) {
|
||||
// svg.Close();
|
||||
//}
|
||||
if (nozzle_diameter != min_width) {
|
||||
grow_to_nozzle_diameter(pp, diff_ex(this->bounds, this->expolygon));
|
||||
grow_to_nozzle_diameter(pp, diff_ex(*this->bounds, this->expolygon));
|
||||
}
|
||||
if(this->taper_size != 0){
|
||||
taper_ends(pp);
|
||||
}
|
||||
//{
|
||||
@ -1633,12 +1645,13 @@ MedialAxis::build(ThickPolylines* polylines_out) {
|
||||
// std::cout << "\n";
|
||||
//}
|
||||
|
||||
polylines_out->insert(polylines_out->end(), pp.begin(), pp.end());
|
||||
polylines_out.insert(polylines_out.end(), pp.begin(), pp.end());
|
||||
|
||||
}
|
||||
|
||||
ExtrusionEntityCollection
|
||||
thin_variable_width(const ThickPolylines &polylines, ExtrusionRole role, Flow flow) {
|
||||
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
|
||||
@ -1750,7 +1763,6 @@ thin_variable_width(const ThickPolylines &polylines, ExtrusionRole role, Flow fl
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return coll;
|
||||
}
|
||||
|
||||
|
@ -15,28 +15,57 @@ using boost::polygon::voronoi_diagram;
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
/// This class is used to create single-line extrusion pattern with variable width to cover a ExPolygon.
|
||||
/// The ends can enter a boundary area if neded, and can have a taper at each end.
|
||||
/// The constructor initialize the mandatory variable.
|
||||
/// you must use the setter to add the opptional settings before calling build().
|
||||
class MedialAxis {
|
||||
public:
|
||||
Lines lines; //lines is here only to avoid passing it in argument of many methods. Initialized in polyline_from_voronoi.
|
||||
ExPolygon expolygon;
|
||||
const ExPolygon& bounds;
|
||||
const ExPolygon& surface;
|
||||
const coord_t max_width;
|
||||
const coord_t min_width;
|
||||
const coord_t height;
|
||||
coord_t nozzle_diameter;
|
||||
coord_t anchor_size;
|
||||
bool stop_at_min_width;
|
||||
MedialAxis(const ExPolygon &_expolygon, const ExPolygon &_bounds, const coord_t _max_width, const coord_t _min_width, const coord_t _height)
|
||||
: surface(_expolygon), bounds(_bounds), max_width(_max_width), min_width(_min_width), height(_height),
|
||||
nozzle_diameter(_min_width),
|
||||
anchor_size(0),
|
||||
stop_at_min_width(true){};
|
||||
void build(ThickPolylines* polylines_out);
|
||||
void build(Polylines* polylines);
|
||||
/// _expolygon: the polygon to fill
|
||||
/// _max_width : maximum width of the extrusion. _expolygon shouldn't have a spot where a circle diameter is higher than that (or almost).
|
||||
/// _min_width : minimum width of the extrusion, every spot where a circle diameter is lower than that will be ignored (unless it's the tip of the extrusion)
|
||||
/// _height: height of the extrusion, used to compute the difference between width and spacing.
|
||||
MedialAxis(const ExPolygon &_expolygon, const coord_t _max_width, const coord_t _min_width, const coord_t _height)
|
||||
: surface(_expolygon), max_width(_max_width), min_width(_min_width), height(_height),
|
||||
bounds(&_expolygon), nozzle_diameter(_min_width), taper_size(0), stop_at_min_width(true){};
|
||||
|
||||
/// create the polylines_out collection of variable-width polyline to extrude.
|
||||
void build(ThickPolylines &polylines_out);
|
||||
/// You shouldn't use this method as it doesn't give you the variable width. Can be useful for debugging.
|
||||
void build(Polylines &polylines);
|
||||
|
||||
/// optional parameter: anchor area in which the extrusion should extends into. Default : expolygon (no bound)
|
||||
MedialAxis& use_bounds(const ExPolygon & _bounds) { this->bounds = &_bounds; return *this; }
|
||||
/// optional parameter: the real minimum width : it will grow the width of every extrusion that has a width lower than that. Default : min_width (same min)
|
||||
MedialAxis& use_min_real_width(const coord_t nozzle_diameter) { this->nozzle_diameter = nozzle_diameter; return *this; }
|
||||
/// optional parameter: create a taper of this length at each end (inside a bound or not). Default : 0 (no taper)
|
||||
MedialAxis& use_tapers(const coord_t taper_size) { this->taper_size = taper_size; return *this; }
|
||||
/// optional parameter: if true, the entension inside the bounds can be cut if the width is too small. Default : true
|
||||
MedialAxis& set_stop_at_min_width(const bool stop_at_min_width) { this->stop_at_min_width = stop_at_min_width; return *this; }
|
||||
|
||||
private:
|
||||
static int id;
|
||||
/// Cache value: lines is here only to avoid passing it in argument of many methods. Initialized in polyline_from_voronoi.
|
||||
Lines lines;
|
||||
|
||||
/// input polygon to fill
|
||||
const ExPolygon& surface;
|
||||
/// the copied expolygon from surface, it's modified in build() to simplify it. It's then used to create the voronoi diagram.
|
||||
ExPolygon expolygon;
|
||||
const ExPolygon* bounds;
|
||||
/// maximum width of the extrusion. _expolygon shouldn't have a spot where a circle diameter is higher than that (or almost).
|
||||
const coord_t max_width;
|
||||
/// minimum width of the extrusion, every spot where a circle diameter is lower than that will be ignored (unless it's the tip of the extrusion)
|
||||
const coord_t min_width;
|
||||
/// height of the extrusion, used to compute the diufference between width and spacing.
|
||||
const coord_t height;
|
||||
/// Used to compute the real minimum width we can extrude. if != min_width, it activate grow_to_nozzle_diameter().
|
||||
coord_t nozzle_diameter;
|
||||
/// if != , it activates taper_ends(). Can use nozzle_diameter.
|
||||
coord_t taper_size;
|
||||
//if true, remove_too_* can shorten the bits created by extends_line.
|
||||
bool stop_at_min_width;
|
||||
|
||||
//voronoi stuff
|
||||
class VD : public voronoi_diagram<double> {
|
||||
public:
|
||||
typedef double coord_type;
|
||||
@ -53,23 +82,38 @@ namespace Slic3r {
|
||||
const Point& retrieve_endpoint(const VD::cell_type* cell) const;
|
||||
void polyline_from_voronoi(const Lines& voronoi_edges, ThickPolylines* polylines_out);
|
||||
|
||||
ExPolygon simplify_polygon_frontier();
|
||||
// functions called by build:
|
||||
|
||||
/// create a simplied version of surface, store it in expolygon
|
||||
void simplify_polygon_frontier();
|
||||
/// fusion little polylines created (by voronoi) on the external side of a curve inside the main polyline.
|
||||
void fusion_curve(ThickPolylines &pp);
|
||||
/// fusion polylines created by voronoi, where needed.
|
||||
void main_fusion(ThickPolylines& pp);
|
||||
/// like fusion_curve but for sharp angles like a square corner.
|
||||
void fusion_corners(ThickPolylines &pp);
|
||||
/// extends the polylines inside bounds, use extends_line on both end
|
||||
void extends_line_both_side(ThickPolylines& pp);
|
||||
/// extends the polylines inside bounds (anchors)
|
||||
void extends_line(ThickPolyline& polyline, const ExPolygons& anchors, const coord_t join_width);
|
||||
/// remove too thin bits at start & end of polylines
|
||||
void remove_too_thin_extrusion(ThickPolylines& pp);
|
||||
/// instead of keeping polyline split at each corssing, we try to create long strait polylines that can cross each other.
|
||||
void concatenate_polylines_with_crossing(ThickPolylines& pp);
|
||||
/// remove bits around points that are too thin (can be inside the polyline)
|
||||
void remove_too_thin_points(ThickPolylines& pp);
|
||||
/// delete polylines that are too short
|
||||
void remove_too_short_polylines(ThickPolylines& pp, const coord_t min_size);
|
||||
/// be sure we didn't try to push more plastic than the volume defined by surface * height can receive. If overextruded, reduce all widths by the correct %.
|
||||
void ensure_not_overextrude(ThickPolylines& pp);
|
||||
/// if nozzle_diameter > min_width, grow bits that are < width(nozzle_diameter) to width(nozzle_diameter) (don't activate that for gapfill)
|
||||
void grow_to_nozzle_diameter(ThickPolylines& pp, const ExPolygons& anchors);
|
||||
/// taper the ends of polylines (don't activate that for gapfill)
|
||||
void taper_ends(ThickPolylines& pp);
|
||||
};
|
||||
|
||||
/// create a ExtrusionEntityCollection from ThickPolylines, discretizing the variable width into little sections (of 4*SCALED_RESOLUTION length) where needed.
|
||||
ExtrusionEntityCollection thin_variable_width(const ThickPolylines &polylines, ExtrusionRole role, Flow flow);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -410,10 +410,12 @@ void PerimeterGenerator::process()
|
||||
if (thin[0].area() > min_width*(ext_perimeter_width + ext_perimeter_spacing2)) {
|
||||
bound.remove_point_too_near((coord_t)SCALED_RESOLUTION);
|
||||
// the maximum thickness of our thin wall area is equal to the minimum thickness of a single loop
|
||||
Slic3r::MedialAxis ma(thin[0], bound, ext_perimeter_width + ext_perimeter_spacing2, min_width, this->layer_height);
|
||||
ma.nozzle_diameter = (coord_t)scale_(this->ext_perimeter_flow.nozzle_diameter);
|
||||
ma.anchor_size = overlap;
|
||||
ma.build(&thin_walls);
|
||||
Slic3r::MedialAxis ma{ thin[0], ext_perimeter_width + ext_perimeter_spacing2,
|
||||
min_width, coord_t(this->layer_height) };
|
||||
ma.use_bounds(bound)
|
||||
.use_min_real_width((coord_t)scale_(this->ext_perimeter_flow.nozzle_diameter))
|
||||
.use_tapers(overlap)
|
||||
.build(thin_walls);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -601,7 +603,7 @@ void PerimeterGenerator::process()
|
||||
//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, this->layer_height);
|
||||
MedialAxis{ ex, coord_t(max), coord_t(min), coord_t(this->layer_height) }.build(polylines);
|
||||
}
|
||||
}
|
||||
if (!polylines.empty()) {
|
||||
|
@ -316,7 +316,7 @@ Point Polygon::point_projection(const Point &point) const
|
||||
return proj;
|
||||
}
|
||||
|
||||
size_t Polygon::remove_colinear_points(coord_t max_offset){
|
||||
size_t Polygon::remove_collinear_points(coord_t max_offset){
|
||||
size_t nb_del = 0;
|
||||
if (points.size() < 3) return 0;
|
||||
|
||||
|
@ -61,7 +61,7 @@ public:
|
||||
Point point_projection(const Point &point) const;
|
||||
/// remove points that are (almost) on an existing line from previous & next point.
|
||||
/// return number of point removed
|
||||
size_t remove_colinear_points(coord_t max_offset);
|
||||
size_t remove_collinear_points(coord_t max_offset);
|
||||
};
|
||||
|
||||
extern BoundingBox get_extents(const Polygon &poly);
|
||||
|
@ -1984,13 +1984,20 @@ end:
|
||||
if (layer->m_regions.size() == 1) {
|
||||
// Optimized version for a single region layer.
|
||||
if (layer_id == 0) {
|
||||
if (delta > elephant_foot_compensation) {
|
||||
delta -= elephant_foot_compensation;
|
||||
elephant_foot_compensation = 0.f;
|
||||
} else if (delta > 0)
|
||||
elephant_foot_compensation -= delta;
|
||||
if (elephant_foot_compensation > 0) {
|
||||
delta += elephant_foot_compensation;
|
||||
elephant_foot_compensation = 0;
|
||||
}else if (delta > 0) {
|
||||
if (-elephant_foot_compensation < delta) {
|
||||
delta += elephant_foot_compensation;
|
||||
elephant_foot_compensation = 0;
|
||||
} else {
|
||||
elephant_foot_compensation += delta;
|
||||
delta = 0;
|
||||
}
|
||||
if (delta != 0.f || elephant_foot_compensation > 0.f) {
|
||||
}
|
||||
}
|
||||
if (delta != 0.f || elephant_foot_compensation != 0.f) {
|
||||
// Single region, growing or shrinking.
|
||||
LayerRegion *layerm = layer->m_regions.front();
|
||||
// Apply the XY compensation.
|
||||
@ -1998,16 +2005,16 @@ end:
|
||||
to_expolygons(std::move(layerm->slices.surfaces)) :
|
||||
offset_ex(to_expolygons(std::move(layerm->slices.surfaces)), delta);
|
||||
// Apply the elephant foot compensation.
|
||||
if (elephant_foot_compensation > 0) {
|
||||
if (elephant_foot_compensation != 0) {
|
||||
float elephant_foot_spacing = float(layerm->flow(frExternalPerimeter).scaled_elephant_foot_spacing());
|
||||
float external_perimeter_nozzle = float(scale_(this->print()->config().nozzle_diameter.get_at(layerm->region()->config().perimeter_extruder.value - 1)));
|
||||
// Apply the elephant foot compensation by steps of 1/10 nozzle diameter.
|
||||
float steps = std::ceil(elephant_foot_compensation / (0.1f * external_perimeter_nozzle));
|
||||
size_t nsteps = size_t(steps);
|
||||
size_t nsteps = size_t(std::abs(steps));
|
||||
float step = elephant_foot_compensation / steps;
|
||||
for (size_t i = 0; i < nsteps; ++ i) {
|
||||
Polygons tmp = offset(expolygons, - step);
|
||||
append(tmp, diff(to_polygons(expolygons), offset(offset_ex(expolygons, -elephant_foot_spacing - step), elephant_foot_spacing + step)));
|
||||
append(tmp, diff(to_polygons(expolygons), offset(offset_ex(expolygons, -elephant_foot_spacing + step), elephant_foot_spacing - step)));
|
||||
expolygons = union_ex(tmp);
|
||||
}
|
||||
}
|
||||
@ -2042,7 +2049,7 @@ end:
|
||||
for (size_t region_id = 0; region_id < layer->m_regions.size(); ++ region_id)
|
||||
layer->m_regions[region_id]->trim_surfaces(trimming);
|
||||
}
|
||||
if (elephant_foot_compensation > 0.f) {
|
||||
if (elephant_foot_compensation != 0.f) {
|
||||
// Apply the elephant foot compensation.
|
||||
std::vector<float> elephant_foot_spacing;
|
||||
elephant_foot_spacing.reserve(layer->m_regions.size());
|
||||
@ -2055,12 +2062,12 @@ end:
|
||||
external_perimeter_nozzle /= (float)layer->m_regions.size();
|
||||
// Apply the elephant foot compensation by steps of 1/10 nozzle diameter.
|
||||
float steps = std::ceil(elephant_foot_compensation / (0.1f * external_perimeter_nozzle));
|
||||
size_t nsteps = size_t(steps);
|
||||
size_t nsteps = size_t(std::abs(steps));
|
||||
float step = elephant_foot_compensation / steps;
|
||||
for (size_t i = 0; i < nsteps; ++ i) {
|
||||
Polygons trimming_polygons = offset(layer->merged(float(EPSILON)), double(- step - EPSILON));
|
||||
for (size_t region_id = 0; region_id < layer->m_regions.size(); ++ region_id)
|
||||
layer->m_regions[region_id]->elephant_foot_compensation_step(elephant_foot_spacing[region_id] + step, trimming_polygons);
|
||||
layer->m_regions[region_id]->elephant_foot_compensation_step(elephant_foot_spacing[region_id] - step, trimming_polygons);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2096,7 +2103,7 @@ void PrintObject::_offset_holes(double hole_delta, LayerRegion *layerm) {
|
||||
ok &= (hole.points.back().ccw_angle(*(hole.points.end() - 2), hole.points.front()) <= PI + 0.1);
|
||||
|
||||
if (ok) {
|
||||
for (Polygon newHole : offset(hole, -hole_delta)) {
|
||||
for (Polygon newHole : offset(hole, hole_delta)) {
|
||||
//reverse because it's a hole, not an object
|
||||
newHole.make_clockwise();
|
||||
new_ex_poly.holes.push_back(newHole);
|
||||
|
@ -1663,7 +1663,7 @@ void TriangleMeshSlicer::make_expolygons(const Polygons &loops, ExPolygons* slic
|
||||
Polygons filered_polys = loops;
|
||||
if (this->model_precision > 0){
|
||||
for (Polygon &hole : filered_polys){
|
||||
hole.remove_colinear_points(scale_(this->model_precision));
|
||||
hole.remove_collinear_points(scale_(this->model_precision));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -59,3 +59,18 @@ SCENARIO("Model construction") {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
SCENARIO("xy compensations"){
|
||||
GIVEN(("A Square with a complex hole inside")){
|
||||
Polygon square/*new_scale*/{ std::vector<Point>{
|
||||
Point{ 100, 100 },
|
||||
Point{ 200, 100 },
|
||||
Point{ 200, 200 },
|
||||
Point{ 100, 200 }} };
|
||||
THEN("elephant and xy can compensate each other"){
|
||||
}
|
||||
THEN("hole and xy can compensate each othere"){
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user