mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-06-04 11:14:17 +08:00
Fixed numerical issue with the new algorithm to connect infill lines
with perimeters: 1) Increased accuracy of the contour length parametrization from float to double, as double should capture the difference of 32bit coord_t with full accuracy (or at least very close). 2) The algorithm to insert the T-joint points into the infill perimeter contour was improved to avoid inserting duplicate points.
This commit is contained in:
parent
3c9f3d2b66
commit
93a5906a18
@ -96,10 +96,10 @@ coord_t Fill::_adjust_solid_spacing(const coord_t width, const coord_t distance)
|
|||||||
assert(width >= 0);
|
assert(width >= 0);
|
||||||
assert(distance > 0);
|
assert(distance > 0);
|
||||||
// floor(width / distance)
|
// floor(width / distance)
|
||||||
coord_t number_of_intervals = (width - EPSILON) / distance;
|
const auto number_of_intervals = coord_t((width - EPSILON) / distance);
|
||||||
coord_t distance_new = (number_of_intervals == 0) ?
|
coord_t distance_new = (number_of_intervals == 0) ?
|
||||||
distance :
|
distance :
|
||||||
((width - EPSILON) / number_of_intervals);
|
coord_t((width - EPSILON) / number_of_intervals);
|
||||||
const coordf_t factor = coordf_t(distance_new) / coordf_t(distance);
|
const coordf_t factor = coordf_t(distance_new) / coordf_t(distance);
|
||||||
assert(factor > 1. - 1e-5);
|
assert(factor > 1. - 1e-5);
|
||||||
// How much could the extrusion width be increased? By 20%.
|
// How much could the extrusion width be increased? By 20%.
|
||||||
@ -143,7 +143,7 @@ std::pair<float, Point> Fill::_infill_direction(const Surface *surface) const
|
|||||||
#ifdef SLIC3R_DEBUG
|
#ifdef SLIC3R_DEBUG
|
||||||
printf("Filling bridge with angle %f\n", surface->bridge_angle);
|
printf("Filling bridge with angle %f\n", surface->bridge_angle);
|
||||||
#endif /* SLIC3R_DEBUG */
|
#endif /* SLIC3R_DEBUG */
|
||||||
out_angle = surface->bridge_angle;
|
out_angle = float(surface->bridge_angle);
|
||||||
} else if (this->layer_id != size_t(-1)) {
|
} else if (this->layer_id != size_t(-1)) {
|
||||||
// alternate fill direction
|
// alternate fill direction
|
||||||
out_angle += this->_layer_angle(this->layer_id / surface->thickness_layers);
|
out_angle += this->_layer_angle(this->layer_id / surface->thickness_layers);
|
||||||
@ -161,15 +161,15 @@ struct ContourIntersectionPoint {
|
|||||||
size_t contour_idx;
|
size_t contour_idx;
|
||||||
size_t point_idx;
|
size_t point_idx;
|
||||||
// Eucleidean parameter of point_idx along its contour.
|
// Eucleidean parameter of point_idx along its contour.
|
||||||
float param;
|
double param;
|
||||||
// Other intersection points along the same contour. If there is only a single T-joint on a contour
|
// Other intersection points along the same contour. If there is only a single T-joint on a contour
|
||||||
// with an intersection line, then the prev_on_contour and next_on_contour remain nulls.
|
// with an intersection line, then the prev_on_contour and next_on_contour remain nulls.
|
||||||
ContourIntersectionPoint* prev_on_contour { nullptr };
|
ContourIntersectionPoint* prev_on_contour { nullptr };
|
||||||
ContourIntersectionPoint* next_on_contour { nullptr };
|
ContourIntersectionPoint* next_on_contour { nullptr };
|
||||||
// Length of the contour not yet allocated to some extrusion path going back (clockwise), or masked out by some overlapping infill line.
|
// Length of the contour not yet allocated to some extrusion path going back (clockwise), or masked out by some overlapping infill line.
|
||||||
float contour_not_taken_length_prev { std::numeric_limits<float>::max() };
|
double contour_not_taken_length_prev { std::numeric_limits<double>::max() };
|
||||||
// Length of the contour not yet allocated to some extrusion path going forward (counter-clockwise), or masked out by some overlapping infill line.
|
// Length of the contour not yet allocated to some extrusion path going forward (counter-clockwise), or masked out by some overlapping infill line.
|
||||||
float contour_not_taken_length_next { std::numeric_limits<float>::max() };
|
double contour_not_taken_length_next { std::numeric_limits<double>::max() };
|
||||||
// End point is consumed if an infill line connected to this T-joint was already connected left or right along the contour,
|
// End point is consumed if an infill line connected to this T-joint was already connected left or right along the contour,
|
||||||
// or if the infill line was processed, but it was not possible to connect it left or right along the contour.
|
// or if the infill line was processed, but it was not possible to connect it left or right along the contour.
|
||||||
bool consumed { false };
|
bool consumed { false };
|
||||||
@ -180,13 +180,13 @@ struct ContourIntersectionPoint {
|
|||||||
void consume_prev() { this->contour_not_taken_length_prev = 0.; this->prev_trimmed = true; this->consumed = true; }
|
void consume_prev() { this->contour_not_taken_length_prev = 0.; this->prev_trimmed = true; this->consumed = true; }
|
||||||
void consume_next() { this->contour_not_taken_length_next = 0.; this->next_trimmed = true; this->consumed = true; }
|
void consume_next() { this->contour_not_taken_length_next = 0.; this->next_trimmed = true; this->consumed = true; }
|
||||||
|
|
||||||
void trim_prev(const float new_len) {
|
void trim_prev(const double new_len) {
|
||||||
if (new_len < this->contour_not_taken_length_prev) {
|
if (new_len < this->contour_not_taken_length_prev) {
|
||||||
this->contour_not_taken_length_prev = new_len;
|
this->contour_not_taken_length_prev = new_len;
|
||||||
this->prev_trimmed = true;
|
this->prev_trimmed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void trim_next(const float new_len) {
|
void trim_next(const double new_len) {
|
||||||
if (new_len < this->contour_not_taken_length_next) {
|
if (new_len < this->contour_not_taken_length_next) {
|
||||||
this->contour_not_taken_length_next = new_len;
|
this->contour_not_taken_length_next = new_len;
|
||||||
this->next_trimmed = true;
|
this->next_trimmed = true;
|
||||||
@ -207,24 +207,24 @@ struct ContourIntersectionPoint {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Distance from param1 to param2 when going counter-clockwise.
|
// Distance from param1 to param2 when going counter-clockwise.
|
||||||
static inline float closed_contour_distance_ccw(float param1, float param2, float contour_length)
|
static inline double closed_contour_distance_ccw(double param1, double param2, double contour_length)
|
||||||
{
|
{
|
||||||
assert(param1 >= 0.f && param1 <= contour_length);
|
assert(param1 >= 0. && param1 <= contour_length);
|
||||||
assert(param2 >= 0.f && param2 <= contour_length);
|
assert(param2 >= 0. && param2 <= contour_length);
|
||||||
float d = param2 - param1;
|
double d = param2 - param1;
|
||||||
if (d < 0.f)
|
if (d < 0.)
|
||||||
d += contour_length;
|
d += contour_length;
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Distance from param1 to param2 when going clockwise.
|
// Distance from param1 to param2 when going clockwise.
|
||||||
static inline float closed_contour_distance_cw(float param1, float param2, float contour_length)
|
static inline double closed_contour_distance_cw(double param1, double param2, double contour_length)
|
||||||
{
|
{
|
||||||
return closed_contour_distance_ccw(param2, param1, contour_length);
|
return closed_contour_distance_ccw(param2, param1, contour_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Length along the contour from cp1 to cp2 going counter-clockwise.
|
// Length along the contour from cp1 to cp2 going counter-clockwise.
|
||||||
float path_length_along_contour_ccw(const ContourIntersectionPoint *cp1, const ContourIntersectionPoint *cp2, float contour_length)
|
double path_length_along_contour_ccw(const ContourIntersectionPoint *cp1, const ContourIntersectionPoint *cp2, double contour_length)
|
||||||
{
|
{
|
||||||
assert(cp1 != nullptr);
|
assert(cp1 != nullptr);
|
||||||
assert(cp2 != nullptr);
|
assert(cp2 != nullptr);
|
||||||
@ -234,13 +234,13 @@ float path_length_along_contour_ccw(const ContourIntersectionPoint *cp1, const C
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Lengths along the contour from cp1 to cp2 going CCW and going CW.
|
// Lengths along the contour from cp1 to cp2 going CCW and going CW.
|
||||||
std::pair<float, float> path_lengths_along_contour(const ContourIntersectionPoint *cp1, const ContourIntersectionPoint *cp2, float contour_length)
|
std::pair<double, double> path_lengths_along_contour(const ContourIntersectionPoint *cp1, const ContourIntersectionPoint *cp2, double contour_length)
|
||||||
{
|
{
|
||||||
// Zero'th param is the length of the contour.
|
// Zero'th param is the length of the contour.
|
||||||
float param_lo = cp1->param;
|
double param_lo = cp1->param;
|
||||||
float param_hi = cp2->param;
|
double param_hi = cp2->param;
|
||||||
assert(param_lo >= 0.f && param_lo <= contour_length);
|
assert(param_lo >= 0. && param_lo <= contour_length);
|
||||||
assert(param_hi >= 0.f && param_hi <= contour_length);
|
assert(param_hi >= 0. && param_hi <= contour_length);
|
||||||
bool reversed = false;
|
bool reversed = false;
|
||||||
if (param_lo > param_hi) {
|
if (param_lo > param_hi) {
|
||||||
std::swap(param_lo, param_hi);
|
std::swap(param_lo, param_hi);
|
||||||
@ -267,25 +267,25 @@ static inline void take_cw_full(Polyline &pl, const Points& contour, size_t idx_
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add contour points from interval (idx_start, idx_end> to polyline, limited by the Eucleidean length taken.
|
// Add contour points from interval (idx_start, idx_end> to polyline, limited by the Eucleidean length taken.
|
||||||
static inline float take_cw_limited(Polyline &pl, const Points &contour, const std::vector<float> ¶ms, size_t idx_start, size_t idx_end, float length_to_take)
|
static inline double take_cw_limited(Polyline &pl, const Points &contour, const std::vector<double> ¶ms, size_t idx_start, size_t idx_end, double length_to_take)
|
||||||
{
|
{
|
||||||
// If appending to an infill line, then the start point of a perimeter line shall match the end point of an infill line.
|
// If appending to an infill line, then the start point of a perimeter line shall match the end point of an infill line.
|
||||||
assert(pl.empty() || pl.points.back() == contour[idx_start]);
|
assert(pl.empty() || pl.points.back() == contour[idx_start]);
|
||||||
assert(contour.size() + 1 == params.size());
|
assert(contour.size() + 1 == params.size());
|
||||||
assert(length_to_take > SCALED_EPSILON);
|
assert(length_to_take > SCALED_EPSILON);
|
||||||
// Length of the contour.
|
// Length of the contour.
|
||||||
float length = params.back();
|
double length = params.back();
|
||||||
// Parameter (length from contour.front()) for the first point.
|
// Parameter (length from contour.front()) for the first point.
|
||||||
float p0 = params[idx_start];
|
double p0 = params[idx_start];
|
||||||
// Current (2nd) point of the contour.
|
// Current (2nd) point of the contour.
|
||||||
size_t i = (idx_start == 0) ? contour.size() - 1 : idx_start - 1;
|
size_t i = (idx_start == 0) ? contour.size() - 1 : idx_start - 1;
|
||||||
// Previous point of the contour.
|
// Previous point of the contour.
|
||||||
size_t iprev = idx_start;
|
size_t iprev = idx_start;
|
||||||
// Length of the contour curve taken for iprev.
|
// Length of the contour curve taken for iprev.
|
||||||
float lprev = 0.f;
|
double lprev = 0.;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
float l = closed_contour_distance_cw(p0, params[i], length);
|
double l = closed_contour_distance_cw(p0, params[i], length);
|
||||||
if (l >= length_to_take) {
|
if (l >= length_to_take) {
|
||||||
// Trim the last segment.
|
// Trim the last segment.
|
||||||
double t = double(length_to_take - lprev) / (l - lprev);
|
double t = double(length_to_take - lprev) / (l - lprev);
|
||||||
@ -323,16 +323,16 @@ static inline void take_ccw_full(Polyline &pl, const Points &contour, size_t idx
|
|||||||
|
|
||||||
// Add contour points from interval (idx_start, idx_end> to polyline, limited by the Eucleidean length taken.
|
// Add contour points from interval (idx_start, idx_end> to polyline, limited by the Eucleidean length taken.
|
||||||
// Returns length of the contour taken.
|
// Returns length of the contour taken.
|
||||||
static inline float take_ccw_limited(Polyline &pl, const Points &contour, const std::vector<float> ¶ms, size_t idx_start, size_t idx_end, float length_to_take)
|
static inline double take_ccw_limited(Polyline &pl, const Points &contour, const std::vector<double> ¶ms, size_t idx_start, size_t idx_end, double length_to_take)
|
||||||
{
|
{
|
||||||
// If appending to an infill line, then the start point of a perimeter line shall match the end point of an infill line.
|
// If appending to an infill line, then the start point of a perimeter line shall match the end point of an infill line.
|
||||||
assert(pl.empty() || pl.points.back() == contour[idx_start]);
|
assert(pl.empty() || pl.points.back() == contour[idx_start]);
|
||||||
assert(contour.size() + 1 == params.size());
|
assert(contour.size() + 1 == params.size());
|
||||||
assert(length_to_take > SCALED_EPSILON);
|
assert(length_to_take > SCALED_EPSILON);
|
||||||
// Length of the contour.
|
// Length of the contour.
|
||||||
float length = params.back();
|
double length = params.back();
|
||||||
// Parameter (length from contour.front()) for the first point.
|
// Parameter (length from contour.front()) for the first point.
|
||||||
float p0 = params[idx_start];
|
double p0 = params[idx_start];
|
||||||
// Current (2nd) point of the contour.
|
// Current (2nd) point of the contour.
|
||||||
size_t i = idx_start;
|
size_t i = idx_start;
|
||||||
if (++ i == contour.size())
|
if (++ i == contour.size())
|
||||||
@ -340,9 +340,9 @@ static inline float take_ccw_limited(Polyline &pl, const Points &contour, const
|
|||||||
// Previous point of the contour.
|
// Previous point of the contour.
|
||||||
size_t iprev = idx_start;
|
size_t iprev = idx_start;
|
||||||
// Length of the contour curve taken at iprev.
|
// Length of the contour curve taken at iprev.
|
||||||
float lprev = 0.f;
|
double lprev = 0;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
float l = closed_contour_distance_ccw(p0, params[i], length);
|
double l = closed_contour_distance_ccw(p0, params[i], length);
|
||||||
if (l >= length_to_take) {
|
if (l >= length_to_take) {
|
||||||
// Trim the last segment.
|
// Trim the last segment.
|
||||||
double t = double(length_to_take - lprev) / (l - lprev);
|
double t = double(length_to_take - lprev) / (l - lprev);
|
||||||
@ -411,8 +411,8 @@ static void take(Polyline &pl1, const Polyline &pl2, const Points &contour, Cont
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void take_limited(
|
static void take_limited(
|
||||||
Polyline &pl1, const Points &contour, const std::vector<float> ¶ms,
|
Polyline &pl1, const Points &contour, const std::vector<double> ¶ms,
|
||||||
ContourIntersectionPoint *cp_start, ContourIntersectionPoint *cp_end, bool clockwise, float take_max_length, float line_half_width)
|
ContourIntersectionPoint *cp_start, ContourIntersectionPoint *cp_end, bool clockwise, double take_max_length, double line_half_width)
|
||||||
{
|
{
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
// This is a valid case, where a single infill line connect to two different contours (outer contour + hole or two holes).
|
// This is a valid case, where a single infill line connect to two different contours (outer contour + hole or two holes).
|
||||||
@ -445,11 +445,11 @@ static void take_limited(
|
|||||||
pl1.points.reserve(pl1.points.size() + pl_tmp.size() + size_t(new_points));
|
pl1.points.reserve(pl1.points.size() + pl_tmp.size() + size_t(new_points));
|
||||||
}
|
}
|
||||||
|
|
||||||
float length = params.back();
|
double length = params.back();
|
||||||
float length_to_go = take_max_length;
|
double length_to_go = take_max_length;
|
||||||
cp_start->consumed = true;
|
cp_start->consumed = true;
|
||||||
if (cp_start == cp_end) {
|
if (cp_start == cp_end) {
|
||||||
length_to_go = std::max(0.f, std::min(length_to_go, length - line_half_width));
|
length_to_go = std::max(0., std::min(length_to_go, length - line_half_width));
|
||||||
length_to_go = std::min(length_to_go, clockwise ? cp_start->contour_not_taken_length_prev : cp_start->contour_not_taken_length_next);
|
length_to_go = std::min(length_to_go, clockwise ? cp_start->contour_not_taken_length_prev : cp_start->contour_not_taken_length_next);
|
||||||
cp_start->consume_prev();
|
cp_start->consume_prev();
|
||||||
cp_start->consume_next();
|
cp_start->consume_next();
|
||||||
@ -462,11 +462,11 @@ static void take_limited(
|
|||||||
assert(cp_start != cp_end);
|
assert(cp_start != cp_end);
|
||||||
for (ContourIntersectionPoint *cp = cp_start; cp != cp_end; cp = cp->prev_on_contour) {
|
for (ContourIntersectionPoint *cp = cp_start; cp != cp_end; cp = cp->prev_on_contour) {
|
||||||
// Length of the segment from cp to cp->prev_on_contour.
|
// Length of the segment from cp to cp->prev_on_contour.
|
||||||
float l = closed_contour_distance_cw(cp->param, cp->prev_on_contour->param, length);
|
double l = closed_contour_distance_cw(cp->param, cp->prev_on_contour->param, length);
|
||||||
length_to_go = std::min(length_to_go, cp->contour_not_taken_length_prev);
|
length_to_go = std::min(length_to_go, cp->contour_not_taken_length_prev);
|
||||||
//if (cp->prev_on_contour->consumed)
|
//if (cp->prev_on_contour->consumed)
|
||||||
// Don't overlap with an already extruded infill line.
|
// Don't overlap with an already extruded infill line.
|
||||||
length_to_go = std::max(0.f, std::min(length_to_go, l - line_half_width));
|
length_to_go = std::max(0., std::min(length_to_go, l - line_half_width));
|
||||||
cp->consume_prev();
|
cp->consume_prev();
|
||||||
if (l >= length_to_go) {
|
if (l >= length_to_go) {
|
||||||
if (length_to_go > SCALED_EPSILON) {
|
if (length_to_go > SCALED_EPSILON) {
|
||||||
@ -475,7 +475,7 @@ static void take_limited(
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
cp->prev_on_contour->trim_next(0.f);
|
cp->prev_on_contour->trim_next(0.);
|
||||||
take_cw_full(pl1, contour, cp->point_idx, cp->prev_on_contour->point_idx);
|
take_cw_full(pl1, contour, cp->point_idx, cp->prev_on_contour->point_idx);
|
||||||
length_to_go -= l;
|
length_to_go -= l;
|
||||||
}
|
}
|
||||||
@ -483,11 +483,11 @@ static void take_limited(
|
|||||||
} else {
|
} else {
|
||||||
assert(cp_start != cp_end);
|
assert(cp_start != cp_end);
|
||||||
for (ContourIntersectionPoint *cp = cp_start; cp != cp_end; cp = cp->next_on_contour) {
|
for (ContourIntersectionPoint *cp = cp_start; cp != cp_end; cp = cp->next_on_contour) {
|
||||||
float l = closed_contour_distance_ccw(cp->param, cp->next_on_contour->param, length);
|
double l = closed_contour_distance_ccw(cp->param, cp->next_on_contour->param, length);
|
||||||
length_to_go = std::min(length_to_go, cp->contour_not_taken_length_next);
|
length_to_go = std::min(length_to_go, cp->contour_not_taken_length_next);
|
||||||
//if (cp->next_on_contour->consumed)
|
//if (cp->next_on_contour->consumed)
|
||||||
// Don't overlap with an already extruded infill line.
|
// Don't overlap with an already extruded infill line.
|
||||||
length_to_go = std::max(0.f, std::min(length_to_go, l - line_half_width));
|
length_to_go = std::max(0., std::min(length_to_go, l - line_half_width));
|
||||||
cp->consume_next();
|
cp->consume_next();
|
||||||
if (l >= length_to_go) {
|
if (l >= length_to_go) {
|
||||||
if (length_to_go > SCALED_EPSILON) {
|
if (length_to_go > SCALED_EPSILON) {
|
||||||
@ -496,7 +496,7 @@ static void take_limited(
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
cp->next_on_contour->trim_prev(0.f);
|
cp->next_on_contour->trim_prev(0.);
|
||||||
take_ccw_full(pl1, contour, cp->point_idx, cp->next_on_contour->point_idx);
|
take_ccw_full(pl1, contour, cp->point_idx, cp->next_on_contour->point_idx);
|
||||||
length_to_go -= l;
|
length_to_go -= l;
|
||||||
}
|
}
|
||||||
@ -678,19 +678,19 @@ static inline bool line_rounded_thick_segment_collision(
|
|||||||
return intersects;
|
return intersects;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool inside_interval(float low, float high, float p)
|
static inline bool inside_interval(double low, double high, double p)
|
||||||
{
|
{
|
||||||
return p >= low && p <= high;
|
return p >= low && p <= high;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool interval_inside_interval(float outer_low, float outer_high, float inner_low, float inner_high, float epsilon)
|
static inline bool interval_inside_interval(double outer_low, double outer_high, double inner_low, double inner_high, double epsilon)
|
||||||
{
|
{
|
||||||
outer_low -= epsilon;
|
outer_low -= epsilon;
|
||||||
outer_high += epsilon;
|
outer_high += epsilon;
|
||||||
return inside_interval(outer_low, outer_high, inner_low) && inside_interval(outer_low, outer_high, inner_high);
|
return inside_interval(outer_low, outer_high, inner_low) && inside_interval(outer_low, outer_high, inner_high);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool cyclic_interval_inside_interval(float outer_low, float outer_high, float inner_low, float inner_high, float length)
|
static inline bool cyclic_interval_inside_interval(double outer_low, double outer_high, double inner_low, double inner_high, double length)
|
||||||
{
|
{
|
||||||
if (outer_low > outer_high)
|
if (outer_low > outer_high)
|
||||||
outer_high += length;
|
outer_high += length;
|
||||||
@ -700,7 +700,7 @@ static inline bool cyclic_interval_inside_interval(float outer_low, float outer_
|
|||||||
inner_low += length;
|
inner_low += length;
|
||||||
inner_high += length;
|
inner_high += length;
|
||||||
}
|
}
|
||||||
return interval_inside_interval(outer_low, outer_high, inner_low, inner_high, float(SCALED_EPSILON));
|
return interval_inside_interval(outer_low, outer_high, inner_low, inner_high, double(SCALED_EPSILON));
|
||||||
}
|
}
|
||||||
|
|
||||||
// #define INFILL_DEBUG_OUTPUT
|
// #define INFILL_DEBUG_OUTPUT
|
||||||
@ -710,7 +710,7 @@ static void export_infill_to_svg(
|
|||||||
// Boundary contour, along which the perimeter extrusions will be drawn.
|
// Boundary contour, along which the perimeter extrusions will be drawn.
|
||||||
const std::vector<Points> &boundary,
|
const std::vector<Points> &boundary,
|
||||||
// Parametrization of boundary with Euclidian length.
|
// Parametrization of boundary with Euclidian length.
|
||||||
const std::vector<std::vector<float>> &boundary_parameters,
|
const std::vector<std::vector<double>> &boundary_parameters,
|
||||||
// Intersections (T-joints) of the infill lines with the boundary.
|
// Intersections (T-joints) of the infill lines with the boundary.
|
||||||
std::vector<std::vector<ContourIntersectionPoint*>> &boundary_intersections,
|
std::vector<std::vector<ContourIntersectionPoint*>> &boundary_intersections,
|
||||||
// Infill lines, either completely inside the boundary, or touching the boundary.
|
// Infill lines, either completely inside the boundary, or touching the boundary.
|
||||||
@ -739,7 +739,7 @@ static void export_infill_to_svg(
|
|||||||
for (const std::vector<ContourIntersectionPoint*> &intersections : boundary_intersections) {
|
for (const std::vector<ContourIntersectionPoint*> &intersections : boundary_intersections) {
|
||||||
const size_t boundary_idx = &intersections - boundary_intersections.data();
|
const size_t boundary_idx = &intersections - boundary_intersections.data();
|
||||||
const Points &contour = boundary[boundary_idx];
|
const Points &contour = boundary[boundary_idx];
|
||||||
const std::vector<float> &contour_param = boundary_parameters[boundary_idx];
|
const std::vector<double> &contour_param = boundary_parameters[boundary_idx];
|
||||||
for (const ContourIntersectionPoint *ip : intersections) {
|
for (const ContourIntersectionPoint *ip : intersections) {
|
||||||
assert(ip->next_trimmed == ip->next_on_contour->prev_trimmed);
|
assert(ip->next_trimmed == ip->next_on_contour->prev_trimmed);
|
||||||
assert(ip->prev_trimmed == ip->prev_on_contour->next_trimmed);
|
assert(ip->prev_trimmed == ip->prev_on_contour->next_trimmed);
|
||||||
@ -834,7 +834,7 @@ void mark_boundary_segments_touching_infill(
|
|||||||
// Boundary contour, along which the perimeter extrusions will be drawn.
|
// Boundary contour, along which the perimeter extrusions will be drawn.
|
||||||
const std::vector<Points> &boundary,
|
const std::vector<Points> &boundary,
|
||||||
// Parametrization of boundary with Euclidian length.
|
// Parametrization of boundary with Euclidian length.
|
||||||
const std::vector<std::vector<float>> &boundary_parameters,
|
const std::vector<std::vector<double>> &boundary_parameters,
|
||||||
// Intersections (T-joints) of the infill lines with the boundary.
|
// Intersections (T-joints) of the infill lines with the boundary.
|
||||||
std::vector<std::vector<ContourIntersectionPoint*>> &boundary_intersections,
|
std::vector<std::vector<ContourIntersectionPoint*>> &boundary_intersections,
|
||||||
// Bounding box around the boundary.
|
// Bounding box around the boundary.
|
||||||
@ -865,12 +865,12 @@ void mark_boundary_segments_touching_infill(
|
|||||||
// Make sure that the the grid is big enough for queries against the thick segment.
|
// Make sure that the the grid is big enough for queries against the thick segment.
|
||||||
grid.set_bbox(boundary_bbox.inflated(distance_colliding * 1.43));
|
grid.set_bbox(boundary_bbox.inflated(distance_colliding * 1.43));
|
||||||
// Inflate the bounding box by a thick line width.
|
// Inflate the bounding box by a thick line width.
|
||||||
grid.create(boundary, std::max(clip_distance, distance_colliding) + scale_(10.));
|
grid.create(boundary, coord_t(std::max(clip_distance, distance_colliding) + scale_(10.)));
|
||||||
|
|
||||||
// Visitor for the EdgeGrid to trim boundary_intersections with existing infill lines.
|
// Visitor for the EdgeGrid to trim boundary_intersections with existing infill lines.
|
||||||
struct Visitor {
|
struct Visitor {
|
||||||
Visitor(const EdgeGrid::Grid &grid,
|
Visitor(const EdgeGrid::Grid &grid,
|
||||||
const std::vector<Points> &boundary, const std::vector<std::vector<float>> &boundary_parameters, std::vector<std::vector<ContourIntersectionPoint*>> &boundary_intersections,
|
const std::vector<Points> &boundary, const std::vector<std::vector<double>> &boundary_parameters, std::vector<std::vector<ContourIntersectionPoint*>> &boundary_intersections,
|
||||||
const double radius) :
|
const double radius) :
|
||||||
grid(grid), boundary(boundary), boundary_parameters(boundary_parameters), boundary_intersections(boundary_intersections), radius(radius), trim_l_threshold(0.5 * radius) {}
|
grid(grid), boundary(boundary), boundary_parameters(boundary_parameters), boundary_intersections(boundary_intersections), radius(radius), trim_l_threshold(0.5 * radius) {}
|
||||||
|
|
||||||
@ -907,10 +907,10 @@ void mark_boundary_segments_touching_infill(
|
|||||||
// The boundary segment intersects with the infill segment thickened by radius.
|
// The boundary segment intersects with the infill segment thickened by radius.
|
||||||
// Interval is specified in Euclidian length from seg_pt1 to seg_pt2.
|
// Interval is specified in Euclidian length from seg_pt1 to seg_pt2.
|
||||||
// 1) Find the Euclidian parameters of seg_pt1 and seg_pt2 on its boundary contour.
|
// 1) Find the Euclidian parameters of seg_pt1 and seg_pt2 on its boundary contour.
|
||||||
const std::vector<float> &contour_parameters = boundary_parameters[it_contour_and_segment->first];
|
const std::vector<double> &contour_parameters = boundary_parameters[it_contour_and_segment->first];
|
||||||
const float contour_length = contour_parameters.back();
|
const double contour_length = contour_parameters.back();
|
||||||
const float param_seg_pt1 = contour_parameters[it_contour_and_segment->second];
|
const double param_seg_pt1 = contour_parameters[it_contour_and_segment->second];
|
||||||
const float param_seg_pt2 = contour_parameters[it_contour_and_segment->second + 1];
|
const double param_seg_pt2 = contour_parameters[it_contour_and_segment->second + 1];
|
||||||
#ifdef INFILL_DEBUG_OUTPUT
|
#ifdef INFILL_DEBUG_OUTPUT
|
||||||
this->perimeter_overlaps.push_back({ Point((seg_pt1 + (seg_pt2 - seg_pt1).normalized() * interval.first).cast<coord_t>()),
|
this->perimeter_overlaps.push_back({ Point((seg_pt1 + (seg_pt2 - seg_pt1).normalized() * interval.first).cast<coord_t>()),
|
||||||
Point((seg_pt1 + (seg_pt2 - seg_pt1).normalized() * interval.second).cast<coord_t>()) });
|
Point((seg_pt1 + (seg_pt2 - seg_pt1).normalized() * interval.second).cast<coord_t>()) });
|
||||||
@ -918,8 +918,8 @@ void mark_boundary_segments_touching_infill(
|
|||||||
assert(interval.first >= 0.);
|
assert(interval.first >= 0.);
|
||||||
assert(interval.second >= 0.);
|
assert(interval.second >= 0.);
|
||||||
assert(interval.first <= interval.second);
|
assert(interval.first <= interval.second);
|
||||||
const auto param_overlap1 = std::min(param_seg_pt2, float(param_seg_pt1 + interval.first));
|
const auto param_overlap1 = std::min(param_seg_pt2, param_seg_pt1 + interval.first);
|
||||||
const auto param_overlap2 = std::min(param_seg_pt2, float(param_seg_pt1 + interval.second));
|
const auto param_overlap2 = std::min(param_seg_pt2, param_seg_pt1 + interval.second);
|
||||||
// 2) Find the ContourIntersectionPoints before param_overlap1 and after param_overlap2.
|
// 2) Find the ContourIntersectionPoints before param_overlap1 and after param_overlap2.
|
||||||
// Find the span of ContourIntersectionPoints, that is trimmed by the interval (param_overlap1, param_overlap2).
|
// Find the span of ContourIntersectionPoints, that is trimmed by the interval (param_overlap1, param_overlap2).
|
||||||
ContourIntersectionPoint *ip_low, *ip_high;
|
ContourIntersectionPoint *ip_low, *ip_high;
|
||||||
@ -946,7 +946,7 @@ void mark_boundary_segments_touching_infill(
|
|||||||
ip->consume_next();
|
ip->consume_next();
|
||||||
}
|
}
|
||||||
// Subtract the interval from the first and last segments.
|
// Subtract the interval from the first and last segments.
|
||||||
float trim_l = closed_contour_distance_ccw(ip_low->param, param_overlap1, contour_length);
|
double trim_l = closed_contour_distance_ccw(ip_low->param, param_overlap1, contour_length);
|
||||||
//if (trim_l > trim_l_threshold)
|
//if (trim_l > trim_l_threshold)
|
||||||
ip_low->trim_next(trim_l);
|
ip_low->trim_next(trim_l);
|
||||||
trim_l = closed_contour_distance_ccw(param_overlap2, ip_high->param, contour_length);
|
trim_l = closed_contour_distance_ccw(param_overlap2, ip_high->param, contour_length);
|
||||||
@ -978,12 +978,12 @@ void mark_boundary_segments_touching_infill(
|
|||||||
|
|
||||||
const EdgeGrid::Grid &grid;
|
const EdgeGrid::Grid &grid;
|
||||||
const std::vector<Points> &boundary;
|
const std::vector<Points> &boundary;
|
||||||
const std::vector<std::vector<float>> &boundary_parameters;
|
const std::vector<std::vector<double>> &boundary_parameters;
|
||||||
std::vector<std::vector<ContourIntersectionPoint*>> &boundary_intersections;
|
std::vector<std::vector<ContourIntersectionPoint*>> &boundary_intersections;
|
||||||
// Maximum distance between the boundary and the infill line allowed to consider the boundary not touching the infill line.
|
// Maximum distance between the boundary and the infill line allowed to consider the boundary not touching the infill line.
|
||||||
const double radius;
|
const double radius;
|
||||||
// Region around the contour / infill line intersection point, where the intersections are ignored.
|
// Region around the contour / infill line intersection point, where the intersections are ignored.
|
||||||
const float trim_l_threshold;
|
const double trim_l_threshold;
|
||||||
|
|
||||||
const Vec2d *infill_pt1;
|
const Vec2d *infill_pt1;
|
||||||
const Vec2d *infill_pt2;
|
const Vec2d *infill_pt2;
|
||||||
@ -1100,11 +1100,11 @@ void Fill::connect_infill(Polylines &&infill_ordered, const Polygons &boundary_s
|
|||||||
void Fill::connect_infill(Polylines &&infill_ordered, const std::vector<const Polygon*> &boundary_src, const BoundingBox &bbox, Polylines &polylines_out, const double spacing, const FillParams ¶ms)
|
void Fill::connect_infill(Polylines &&infill_ordered, const std::vector<const Polygon*> &boundary_src, const BoundingBox &bbox, Polylines &polylines_out, const double spacing, const FillParams ¶ms)
|
||||||
{
|
{
|
||||||
assert(! infill_ordered.empty());
|
assert(! infill_ordered.empty());
|
||||||
assert(params.anchor_length >= 0.f);
|
assert(params.anchor_length >= 0.);
|
||||||
assert(params.anchor_length_max >= 0.01f);
|
assert(params.anchor_length_max >= 0.01f);
|
||||||
assert(params.anchor_length_max >= params.anchor_length);
|
assert(params.anchor_length_max >= params.anchor_length);
|
||||||
const auto anchor_length = float(scale_(params.anchor_length));
|
const double anchor_length = scale_(params.anchor_length);
|
||||||
const auto anchor_length_max = float(scale_(params.anchor_length_max));
|
const double anchor_length_max = scale_(params.anchor_length_max);
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
append(polylines_out, infill_ordered);
|
append(polylines_out, infill_ordered);
|
||||||
@ -1113,9 +1113,9 @@ void Fill::connect_infill(Polylines &&infill_ordered, const std::vector<const Po
|
|||||||
|
|
||||||
// 1) Add the end points of infill_ordered to boundary_src.
|
// 1) Add the end points of infill_ordered to boundary_src.
|
||||||
std::vector<Points> boundary;
|
std::vector<Points> boundary;
|
||||||
std::vector<std::vector<float>> boundary_params;
|
std::vector<std::vector<double>> boundary_params;
|
||||||
boundary.assign(boundary_src.size(), Points());
|
boundary.assign(boundary_src.size(), Points());
|
||||||
boundary_params.assign(boundary_src.size(), std::vector<float>());
|
boundary_params.assign(boundary_src.size(), std::vector<double>());
|
||||||
// Mapping the infill_ordered end point to a (contour, point) of boundary.
|
// Mapping the infill_ordered end point to a (contour, point) of boundary.
|
||||||
static constexpr auto boundary_idx_unconnected = std::numeric_limits<size_t>::max();
|
static constexpr auto boundary_idx_unconnected = std::numeric_limits<size_t>::max();
|
||||||
std::vector<ContourIntersectionPoint> map_infill_end_point_to_boundary(infill_ordered.size() * 2, ContourIntersectionPoint{ boundary_idx_unconnected, boundary_idx_unconnected });
|
std::vector<ContourIntersectionPoint> map_infill_end_point_to_boundary(infill_ordered.size() * 2, ContourIntersectionPoint{ boundary_idx_unconnected, boundary_idx_unconnected });
|
||||||
@ -1125,11 +1125,11 @@ void Fill::connect_infill(Polylines &&infill_ordered, const std::vector<const Po
|
|||||||
{
|
{
|
||||||
EdgeGrid::Grid grid;
|
EdgeGrid::Grid grid;
|
||||||
grid.set_bbox(bbox.inflated(SCALED_EPSILON));
|
grid.set_bbox(bbox.inflated(SCALED_EPSILON));
|
||||||
grid.create(boundary_src, scale_(10.));
|
grid.create(boundary_src, coord_t(scale_(10.)));
|
||||||
intersection_points.reserve(infill_ordered.size() * 2);
|
intersection_points.reserve(infill_ordered.size() * 2);
|
||||||
for (const Polyline &pl : infill_ordered)
|
for (const Polyline &pl : infill_ordered)
|
||||||
for (const Point *pt : { &pl.points.front(), &pl.points.back() }) {
|
for (const Point *pt : { &pl.points.front(), &pl.points.back() }) {
|
||||||
EdgeGrid::Grid::ClosestPointResult cp = grid.closest_point(*pt, SCALED_EPSILON);
|
EdgeGrid::Grid::ClosestPointResult cp = grid.closest_point(*pt, coord_t(SCALED_EPSILON));
|
||||||
if (cp.valid()) {
|
if (cp.valid()) {
|
||||||
// The infill end point shall lie on the contour.
|
// The infill end point shall lie on the contour.
|
||||||
assert(cp.distance <= 3.);
|
assert(cp.distance <= 3.);
|
||||||
@ -1163,21 +1163,29 @@ void Fill::connect_infill(Polylines &&infill_ordered, const std::vector<const Po
|
|||||||
contour_intersection_points.reserve(n_intersection_points);
|
contour_intersection_points.reserve(n_intersection_points);
|
||||||
}
|
}
|
||||||
for (size_t idx_point = 0; idx_point < contour_src.points.size(); ++ idx_point) {
|
for (size_t idx_point = 0; idx_point < contour_src.points.size(); ++ idx_point) {
|
||||||
contour_dst.emplace_back(contour_src.points[idx_point]);
|
const Point &ipt = contour_src.points[idx_point];
|
||||||
|
if (contour_dst.empty() || contour_dst.back() != ipt)
|
||||||
|
contour_dst.emplace_back(ipt);
|
||||||
for (; it != it_end && it->first.contour_idx == idx_contour && it->first.start_point_idx == idx_point; ++ it) {
|
for (; it != it_end && it->first.contour_idx == idx_contour && it->first.start_point_idx == idx_point; ++ it) {
|
||||||
// Add these points to the destination contour.
|
// Add these points to the destination contour.
|
||||||
const Polyline &infill_line = infill_ordered[it->second / 2];
|
const Polyline &infill_line = infill_ordered[it->second / 2];
|
||||||
const Point &pt = (it->second & 1) ? infill_line.points.back() : infill_line.points.front();
|
const Point &pt = (it->second & 1) ? infill_line.points.back() : infill_line.points.front();
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
{
|
{
|
||||||
const Vec2d pt1 = contour_src[idx_point].cast<double>();
|
const Vec2d pt1 = ipt.cast<double>();
|
||||||
const Vec2d pt2 = (idx_point + 1 == contour_src.size() ? contour_src.points.front() : contour_src.points[idx_point + 1]).cast<double>();
|
const Vec2d pt2 = (idx_point + 1 == contour_src.size() ? contour_src.points.front() : contour_src.points[idx_point + 1]).cast<double>();
|
||||||
const Vec2d ptx = lerp(pt1, pt2, it->first.t);
|
const Vec2d ptx = lerp(pt1, pt2, it->first.t);
|
||||||
assert(std::abs(pt.x() - pt.x()) < SCALED_EPSILON);
|
assert(std::abs(pt.x() - pt.x()) < SCALED_EPSILON);
|
||||||
assert(std::abs(pt.y() - pt.y()) < SCALED_EPSILON);
|
assert(std::abs(pt.y() - pt.y()) < SCALED_EPSILON);
|
||||||
}
|
}
|
||||||
#endif // NDEBUG
|
#endif // NDEBUG
|
||||||
map_infill_end_point_to_boundary[it->second] = ContourIntersectionPoint{ idx_contour, contour_dst.size() };
|
size_t idx_tjoint_pt = 0;
|
||||||
|
if (idx_point + 1 < contour_src.size() || pt != contour_dst.front()) {
|
||||||
|
if (pt != contour_dst.back())
|
||||||
|
contour_dst.emplace_back(pt);
|
||||||
|
idx_tjoint_pt = contour_dst.size() - 1;
|
||||||
|
}
|
||||||
|
map_infill_end_point_to_boundary[it->second] = ContourIntersectionPoint{ idx_contour, idx_tjoint_pt };
|
||||||
ContourIntersectionPoint *pthis = &map_infill_end_point_to_boundary[it->second];
|
ContourIntersectionPoint *pthis = &map_infill_end_point_to_boundary[it->second];
|
||||||
if (pprev) {
|
if (pprev) {
|
||||||
pprev->next_on_contour = pthis;
|
pprev->next_on_contour = pthis;
|
||||||
@ -1186,8 +1194,6 @@ void Fill::connect_infill(Polylines &&infill_ordered, const std::vector<const Po
|
|||||||
pfirst = pthis;
|
pfirst = pthis;
|
||||||
contour_intersection_points.emplace_back(pthis);
|
contour_intersection_points.emplace_back(pthis);
|
||||||
pprev = pthis;
|
pprev = pthis;
|
||||||
//add new point here
|
|
||||||
contour_dst.emplace_back(pt);
|
|
||||||
}
|
}
|
||||||
if (pfirst) {
|
if (pfirst) {
|
||||||
pprev->next_on_contour = pfirst;
|
pprev->next_on_contour = pfirst;
|
||||||
@ -1195,16 +1201,19 @@ void Fill::connect_infill(Polylines &&infill_ordered, const std::vector<const Po
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Parametrize the new boundary with the intersection points inserted.
|
// Parametrize the new boundary with the intersection points inserted.
|
||||||
std::vector<float> &contour_params = boundary_params[idx_contour];
|
std::vector<double> &contour_params = boundary_params[idx_contour];
|
||||||
contour_params.assign(contour_dst.size() + 1, 0.f);
|
contour_params.assign(contour_dst.size() + 1, 0.);
|
||||||
for (size_t i = 1; i < contour_dst.size(); ++ i)
|
for (size_t i = 1; i < contour_dst.size(); ++i) {
|
||||||
contour_params[i] = contour_params[i - 1] + (contour_dst[i].cast<float>() - contour_dst[i - 1].cast<float>()).norm();
|
contour_params[i] = contour_params[i - 1] + (contour_dst[i].cast<double>() - contour_dst[i - 1].cast<double>()).norm();
|
||||||
contour_params.back() = contour_params[contour_params.size() - 2] + (contour_dst.back().cast<float>() - contour_dst.front().cast<float>()).norm();
|
assert(contour_params[i] > contour_params[i - 1]);
|
||||||
|
}
|
||||||
|
contour_params.back() = contour_params[contour_params.size() - 2] + (contour_dst.back().cast<double>() - contour_dst.front().cast<double>()).norm();
|
||||||
|
assert(contour_params.back() > contour_params[contour_params.size() - 2]);
|
||||||
// Map parameters from contour_params to boundary_intersection_points.
|
// Map parameters from contour_params to boundary_intersection_points.
|
||||||
for (ContourIntersectionPoint *ip : contour_intersection_points)
|
for (ContourIntersectionPoint *ip : contour_intersection_points)
|
||||||
ip->param = contour_params[ip->point_idx];
|
ip->param = contour_params[ip->point_idx];
|
||||||
// and measure distance to the previous and next intersection point.
|
// and measure distance to the previous and next intersection point.
|
||||||
const float contour_length = contour_params.back();
|
const double contour_length = contour_params.back();
|
||||||
for (ContourIntersectionPoint *ip : contour_intersection_points)
|
for (ContourIntersectionPoint *ip : contour_intersection_points)
|
||||||
if (ip->next_on_contour == ip) {
|
if (ip->next_on_contour == ip) {
|
||||||
assert(ip->prev_on_contour == ip);
|
assert(ip->prev_on_contour == ip);
|
||||||
@ -1238,9 +1247,9 @@ void Fill::connect_infill(Polylines &&infill_ordered, const std::vector<const Po
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Connection from end of one infill line to the start of another infill line.
|
// Connection from end of one infill line to the start of another infill line.
|
||||||
//const float length_max = scale_(spacing);
|
//const double length_max = scale_(spacing);
|
||||||
// const auto length_max = float(scale_((2. / params.density) * spacing));
|
// const auto length_max = double(scale_((2. / params.density) * spacing));
|
||||||
const auto length_max = float(scale_((1000. / params.density) * spacing));
|
const auto length_max = double(scale_((1000. / params.density) * spacing));
|
||||||
std::vector<size_t> merged_with(infill_ordered.size());
|
std::vector<size_t> merged_with(infill_ordered.size());
|
||||||
std::iota(merged_with.begin(), merged_with.end(), 0);
|
std::iota(merged_with.begin(), merged_with.end(), 0);
|
||||||
struct ConnectionCost {
|
struct ConnectionCost {
|
||||||
@ -1258,7 +1267,7 @@ void Fill::connect_infill(Polylines &&infill_ordered, const std::vector<const Po
|
|||||||
const ContourIntersectionPoint *cp2 = &map_infill_end_point_to_boundary[idx_chain * 2];
|
const ContourIntersectionPoint *cp2 = &map_infill_end_point_to_boundary[idx_chain * 2];
|
||||||
if (cp1->contour_idx != boundary_idx_unconnected && cp1->contour_idx == cp2->contour_idx) {
|
if (cp1->contour_idx != boundary_idx_unconnected && cp1->contour_idx == cp2->contour_idx) {
|
||||||
// End points on the same contour. Try to connect them.
|
// End points on the same contour. Try to connect them.
|
||||||
std::pair<float, float> len = path_lengths_along_contour(cp1, cp2, boundary_params[cp1->contour_idx].back());
|
std::pair<double, double> len = path_lengths_along_contour(cp1, cp2, boundary_params[cp1->contour_idx].back());
|
||||||
if (len.first < length_max)
|
if (len.first < length_max)
|
||||||
connections_sorted.emplace_back(idx_chain - 1, len.first, false);
|
connections_sorted.emplace_back(idx_chain - 1, len.first, false);
|
||||||
if (len.second < length_max)
|
if (len.second < length_max)
|
||||||
@ -1281,7 +1290,7 @@ void Fill::connect_infill(Polylines &&infill_ordered, const std::vector<const Po
|
|||||||
return std::numeric_limits<size_t>::max();
|
return std::numeric_limits<size_t>::max();
|
||||||
};
|
};
|
||||||
|
|
||||||
const float line_half_width = 0.5f * scale_(spacing);
|
const double line_half_width = 0.5 * scale_(spacing);
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
for (ConnectionCost &connection_cost : connections_sorted) {
|
for (ConnectionCost &connection_cost : connections_sorted) {
|
||||||
@ -1291,7 +1300,7 @@ void Fill::connect_infill(Polylines &&infill_ordered, const std::vector<const Po
|
|||||||
assert(cp1->contour_idx == cp2->contour_idx && cp1->contour_idx != boundary_idx_unconnected);
|
assert(cp1->contour_idx == cp2->contour_idx && cp1->contour_idx != boundary_idx_unconnected);
|
||||||
if (cp1->consumed || cp2->consumed)
|
if (cp1->consumed || cp2->consumed)
|
||||||
continue;
|
continue;
|
||||||
const float length = connection_cost.cost;
|
const double length = connection_cost.cost;
|
||||||
bool could_connect;
|
bool could_connect;
|
||||||
{
|
{
|
||||||
// cp1, cp2 sorted CCW.
|
// cp1, cp2 sorted CCW.
|
||||||
@ -1334,7 +1343,7 @@ void Fill::connect_infill(Polylines &&infill_ordered, const std::vector<const Po
|
|||||||
|
|
||||||
struct Arc {
|
struct Arc {
|
||||||
ContourIntersectionPoint *intersection;
|
ContourIntersectionPoint *intersection;
|
||||||
float arc_length;
|
double arc_length;
|
||||||
};
|
};
|
||||||
std::vector<Arc> arches;
|
std::vector<Arc> arches;
|
||||||
arches.reserve(map_infill_end_point_to_boundary.size());
|
arches.reserve(map_infill_end_point_to_boundary.size());
|
||||||
@ -1352,7 +1361,7 @@ void Fill::connect_infill(Polylines &&infill_ordered, const std::vector<const Po
|
|||||||
size_t polyline_idx1 = get_and_update_merged_with(((cp1 - map_infill_end_point_to_boundary.data()) / 2));
|
size_t polyline_idx1 = get_and_update_merged_with(((cp1 - map_infill_end_point_to_boundary.data()) / 2));
|
||||||
size_t polyline_idx2 = get_and_update_merged_with(((cp2 - map_infill_end_point_to_boundary.data()) / 2));
|
size_t polyline_idx2 = get_and_update_merged_with(((cp2 - map_infill_end_point_to_boundary.data()) / 2));
|
||||||
const Points &contour = boundary[cp1->contour_idx];
|
const Points &contour = boundary[cp1->contour_idx];
|
||||||
const std::vector<float> &contour_params = boundary_params[cp1->contour_idx];
|
const std::vector<double> &contour_params = boundary_params[cp1->contour_idx];
|
||||||
if (polyline_idx1 != polyline_idx2) {
|
if (polyline_idx1 != polyline_idx2) {
|
||||||
Polyline &polyline1 = infill_ordered[polyline_idx1];
|
Polyline &polyline1 = infill_ordered[polyline_idx1];
|
||||||
Polyline &polyline2 = infill_ordered[polyline_idx2];
|
Polyline &polyline2 = infill_ordered[polyline_idx2];
|
||||||
@ -1386,22 +1395,22 @@ void Fill::connect_infill(Polylines &&infill_ordered, const std::vector<const Po
|
|||||||
for (ContourIntersectionPoint &contour_point : map_infill_end_point_to_boundary)
|
for (ContourIntersectionPoint &contour_point : map_infill_end_point_to_boundary)
|
||||||
if (! contour_point.consumed && contour_point.contour_idx != boundary_idx_unconnected) {
|
if (! contour_point.consumed && contour_point.contour_idx != boundary_idx_unconnected) {
|
||||||
const Points &contour = boundary[contour_point.contour_idx];
|
const Points &contour = boundary[contour_point.contour_idx];
|
||||||
const std::vector<float> &contour_params = boundary_params[contour_point.contour_idx];
|
const std::vector<double> &contour_params = boundary_params[contour_point.contour_idx];
|
||||||
const size_t contour_pt_idx = contour_point.point_idx;
|
const size_t contour_pt_idx = contour_point.point_idx;
|
||||||
|
|
||||||
float lprev = contour_point.could_connect_prev() ?
|
double lprev = contour_point.could_connect_prev() ?
|
||||||
path_length_along_contour_ccw(contour_point.prev_on_contour, &contour_point, contour_params.back()) :
|
path_length_along_contour_ccw(contour_point.prev_on_contour, &contour_point, contour_params.back()) :
|
||||||
std::numeric_limits<float>::max();
|
std::numeric_limits<double>::max();
|
||||||
float lnext = contour_point.could_connect_next() ?
|
double lnext = contour_point.could_connect_next() ?
|
||||||
path_length_along_contour_ccw(&contour_point, contour_point.next_on_contour, contour_params.back()) :
|
path_length_along_contour_ccw(&contour_point, contour_point.next_on_contour, contour_params.back()) :
|
||||||
std::numeric_limits<float>::max();
|
std::numeric_limits<double>::max();
|
||||||
size_t polyline_idx = get_and_update_merged_with(((&contour_point - map_infill_end_point_to_boundary.data()) / 2));
|
size_t polyline_idx = get_and_update_merged_with(((&contour_point - map_infill_end_point_to_boundary.data()) / 2));
|
||||||
Polyline &polyline = infill_ordered[polyline_idx];
|
Polyline &polyline = infill_ordered[polyline_idx];
|
||||||
assert(! polyline.empty());
|
assert(! polyline.empty());
|
||||||
assert(contour[contour_point.point_idx] == polyline.points.front() || contour[contour_point.point_idx] == polyline.points.back());
|
assert(contour[contour_point.point_idx] == polyline.points.front() || contour[contour_point.point_idx] == polyline.points.back());
|
||||||
bool connected = false;
|
bool connected = false;
|
||||||
for (float l : { std::min(lprev, lnext), std::max(lprev, lnext) }) {
|
for (double l : { std::min(lprev, lnext), std::max(lprev, lnext) }) {
|
||||||
if (l == std::numeric_limits<float>::max() || l > anchor_length_max)
|
if (l == std::numeric_limits<double>::max() || l > anchor_length_max)
|
||||||
break;
|
break;
|
||||||
// Take the complete contour.
|
// Take the complete contour.
|
||||||
bool reversed = l == lprev;
|
bool reversed = l == lprev;
|
||||||
@ -1439,7 +1448,7 @@ void Fill::connect_infill(Polylines &&infill_ordered, const std::vector<const Po
|
|||||||
// 2) Hook length
|
// 2) Hook length
|
||||||
// ...
|
// ...
|
||||||
// Let's take the longer now, as this improves the chance of another hook to be placed on the other side of this contour point.
|
// Let's take the longer now, as this improves the chance of another hook to be placed on the other side of this contour point.
|
||||||
float l = std::max(contour_point.contour_not_taken_length_prev, contour_point.contour_not_taken_length_next);
|
double l = std::max(contour_point.contour_not_taken_length_prev, contour_point.contour_not_taken_length_next);
|
||||||
if (l > SCALED_EPSILON) {
|
if (l > SCALED_EPSILON) {
|
||||||
if (contour_point.contour_not_taken_length_prev > contour_point.contour_not_taken_length_next)
|
if (contour_point.contour_not_taken_length_prev > contour_point.contour_not_taken_length_next)
|
||||||
take_limited(polyline, contour, contour_params, &contour_point, contour_point.prev_on_contour, true, anchor_length, line_half_width);
|
take_limited(polyline, contour, contour_params, &contour_point, contour_point.prev_on_contour, true, anchor_length, line_half_width);
|
||||||
|
@ -37,7 +37,7 @@ protected:
|
|||||||
|
|
||||||
bool _can_connect(coord_t dist_X, coord_t dist_Y)
|
bool _can_connect(coord_t dist_X, coord_t dist_Y)
|
||||||
{
|
{
|
||||||
coord_t TOLERANCE = 10 * SCALED_EPSILON;
|
const auto TOLERANCE = coord_t(10 * SCALED_EPSILON);
|
||||||
return (dist_X >= (this->_line_spacing - this->_line_oscillation) - TOLERANCE)
|
return (dist_X >= (this->_line_spacing - this->_line_oscillation) - TOLERANCE)
|
||||||
&& (dist_X <= (this->_line_spacing + this->_line_oscillation) + TOLERANCE)
|
&& (dist_X <= (this->_line_spacing + this->_line_oscillation) + TOLERANCE)
|
||||||
&& (dist_Y <= this->_diagonal_distance);
|
&& (dist_Y <= this->_diagonal_distance);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user