SPE-2405: Add Zig Zag infill that is rectilinear infill but with a consistent pattern between layers.

This Zig Zag infill is inspired by the Zig Zag infill in Cura.

Change-Id: I798affa99f4b5c3bd67f47643e67530fb7c3e0cb
(cherry picked from commit 2808d04d5deef6f99f9618648e46f11de03efc98)
This commit is contained in:
Lukáš Hejl 2024-07-16 15:26:29 +02:00 committed by SoftFever
parent 33dc7bc1f2
commit 1321cf040a
20 changed files with 291 additions and 67 deletions

View file

@ -64,6 +64,7 @@ Fill* Fill::new_from_type(const InfillPattern type)
// BBS: for bottom and top surface only
// Orca: Replace BBS implementation with Prusa implementation
case ipMonotonicLine: return new FillMonotonicLines();
case ipZigZag: return new FillZigZag();
default: throw Slic3r::InvalidArgument("unknown type");
}
}
@ -240,7 +241,7 @@ void Fill::_create_gap_fill(const Surface* surface, const FillParams& params, Ex
// Calculate a new spacing to fill width with possibly integer number of lines,
// the first and last line being centered at the interval ends.
// This function possibly increases the spacing, never decreases,
// This function possibly increases the spacing, never decreases,
// and for a narrow width the increase in spacing may become severe,
// therefore the adjustment is limited to 20% increase.
coord_t Fill::_adjust_solid_spacing(const coord_t width, const coord_t distance)
@ -249,8 +250,8 @@ coord_t Fill::_adjust_solid_spacing(const coord_t width, const coord_t distance)
assert(distance > 0);
// floor(width / distance)
const auto number_of_intervals = coord_t((width - EPSILON) / distance);
coord_t distance_new = (number_of_intervals == 0) ?
distance :
coord_t distance_new = (number_of_intervals == 0) ?
distance :
coord_t((width - EPSILON) / number_of_intervals);
const coordf_t factor = coordf_t(distance_new) / coordf_t(distance);
assert(factor > 1. - 1e-5);
@ -276,8 +277,8 @@ std::pair<float, Point> Fill::_infill_direction(const Surface *surface) const
// Bounding box is the bounding box of a perl object Slic3r::Print::Object (c++ object Slic3r::PrintObject)
// The bounding box is only undefined in unit tests.
Point out_shift = empty(this->bounding_box) ?
surface->expolygon.contour.bounding_box().center() :
Point out_shift = empty(this->bounding_box) ?
surface->expolygon.contour.bounding_box().center() :
this->bounding_box.center();
#if 0
@ -351,10 +352,10 @@ struct ContourIntersectionPoint {
bool could_take_next() const throw() { return ! this->consumed && this->contour_not_taken_length_next > SCALED_EPSILON; }
// Could extrude a complete segment from this to this->prev_on_contour.
bool could_connect_prev() const throw()
bool could_connect_prev() const throw()
{ return ! this->consumed && this->prev_on_contour != this && ! this->prev_on_contour->consumed && ! this->prev_trimmed && ! this->prev_on_contour->next_trimmed; }
// Could extrude a complete segment from this to this->next_on_contour.
bool could_connect_next() const throw()
bool could_connect_next() const throw()
{ return ! this->consumed && this->next_on_contour != this && ! this->next_on_contour->consumed && ! this->next_trimmed && ! this->next_on_contour->prev_trimmed; }
};
@ -563,7 +564,7 @@ static void take(Polyline &pl1, const Polyline &pl2, const Points &contour, Cont
}
static void take_limited(
Polyline &pl1, const Points &contour, const std::vector<double> &params,
Polyline &pl1, const Points &contour, const std::vector<double> &params,
ContourIntersectionPoint *cp_start, ContourIntersectionPoint *cp_end, bool clockwise, double take_max_length, double line_half_width)
{
#ifndef NDEBUG
@ -727,8 +728,8 @@ static inline SegmentPoint clip_end_segment_and_point(const Points &polyline, do
// Calculate intersection of a line with a thick segment.
// Returns Eucledian parameters of the line / thick segment overlap.
static inline bool line_rounded_thick_segment_collision(
const Vec2d &line_a, const Vec2d &line_b,
const Vec2d &segment_a, const Vec2d &segment_b, const double offset,
const Vec2d &line_a, const Vec2d &line_b,
const Vec2d &segment_a, const Vec2d &segment_b, const double offset,
std::pair<double, double> &out_interval)
{
const Vec2d line_v0 = line_b - line_a;
@ -791,8 +792,8 @@ static inline bool line_rounded_thick_segment_collision(
std::pair<double, double> interval;
if (Geometry::liang_barsky_line_clipping_interval(
Vec2d(line_p0.dot(dir_x), line_p0.dot(dir_y)),
Vec2d(line_v0.dot(dir_x), line_v0.dot(dir_y)),
BoundingBoxf(Vec2d(0., - offset), Vec2d(segment_l, offset)),
Vec2d(line_v0.dot(dir_x), line_v0.dot(dir_y)),
BoundingBoxf(Vec2d(0., - offset), Vec2d(segment_l, offset)),
interval))
extend_interval(interval.first, interval.second);
} else
@ -1152,7 +1153,7 @@ void mark_boundary_segments_touching_infill(
// Clip the infill polyline by the Eucledian distance along the polyline.
SegmentPoint start_point = clip_start_segment_and_point(polyline.points, clip_distance);
SegmentPoint end_point = clip_end_segment_and_point(polyline.points, clip_distance);
if (start_point.valid() && end_point.valid() &&
if (start_point.valid() && end_point.valid() &&
(start_point.idx_segment < end_point.idx_segment || (start_point.idx_segment == end_point.idx_segment && start_point.t < end_point.t))) {
// The clipped polyline is non-empty.
#ifdef INFILL_DEBUG_OUTPUT
@ -1292,21 +1293,21 @@ struct BoundaryInfillGraph
};
static Direction dir(const Point &p1, const Point &p2) {
return p1.x() == p2.x() ?
return p1.x() == p2.x() ?
(p1.y() < p2.y() ? Up : Down) :
(p1.x() < p2.x() ? Right : Left);
}
const Direction dir_prev(const ContourIntersectionPoint &cp) const {
assert(cp.prev_on_contour);
return cp.could_take_prev() ?
return cp.could_take_prev() ?
dir(this->point(cp), this->point(*cp.prev_on_contour)) :
Taken;
}
const Direction dir_next(const ContourIntersectionPoint &cp) const {
assert(cp.next_on_contour);
return cp.could_take_next() ?
return cp.could_take_next() ?
dir(this->point(cp), this->point(*cp.next_on_contour)) :
Taken;
}
@ -1364,7 +1365,7 @@ static inline void mark_boundary_segments_overlapping_infill(
assert(interval.first == 0.);
double len_out = closed_contour_distance_ccw(contour_params[cp.point_idx], contour_params[i], contour_params.back()) + interval.second;
if (len_out < cp.contour_not_taken_length_next) {
// Leaving the infill line region before exiting cp.contour_not_taken_length_next,
// Leaving the infill line region before exiting cp.contour_not_taken_length_next,
// thus at least some of the contour is outside and we will extrude this segment.
inside = false;
break;
@ -1396,7 +1397,7 @@ static inline void mark_boundary_segments_overlapping_infill(
assert(interval.first == 0.);
double len_out = closed_contour_distance_cw(contour_params[cp.point_idx], contour_params[i], contour_params.back()) + interval.second;
if (len_out < cp.contour_not_taken_length_prev) {
// Leaving the infill line region before exiting cp.contour_not_taken_length_next,
// Leaving the infill line region before exiting cp.contour_not_taken_length_next,
// thus at least some of the contour is outside and we will extrude this segment.
inside = false;
break;
@ -1493,7 +1494,7 @@ BoundaryInfillGraph create_boundary_infill_graph(const Polylines &infill_ordered
ContourIntersectionPoint *pthis = &out.map_infill_end_point_to_boundary[it->second];
if (pprev) {
pprev->next_on_contour = pthis;
pthis->prev_on_contour = pprev;
pthis->prev_on_contour = pprev;
} else
pfirst = pthis;
contour_intersection_points.emplace_back(pthis);
@ -1518,7 +1519,7 @@ BoundaryInfillGraph create_boundary_infill_graph(const Polylines &infill_ordered
ip->param = contour_params[ip->point_idx];
// and measure distance to the previous and next intersection point.
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) {
assert(ip->prev_on_contour == ip);
ip->contour_not_taken_length_prev = ip->contour_not_taken_length_next = contour_length;
@ -1924,14 +1925,14 @@ static inline void base_support_extend_infill_lines(Polylines &infill, BoundaryI
// The contour is supposed to enter the "forbidden" zone outside of the (left, right) band at tbegin and also at tend.
static inline void emit_loops_in_band(
// Vertical band, which will trim the contour between tbegin and tend.
coord_t left,
coord_t left,
coord_t right,
// Contour and its parametrization.
const Points &contour,
const std::vector<double> &contour_params,
// Span of the parameters of an arch to trim with the vertical band.
double tbegin,
double tend,
double tend,
// Minimum arch length to put into polylines_out. Shorter arches are not necessary to support a dense support infill.
double min_length,
Polylines &polylines_out)
@ -1987,13 +1988,13 @@ static inline void emit_loops_in_band(
};
enum InOutBand {
Entering,
Entering,
Leaving,
};
class State {
public:
State(coord_t left, coord_t right, double min_length, Polylines &polylines_out) :
State(coord_t left, coord_t right, double min_length, Polylines &polylines_out) :
m_left(left), m_right(right), m_min_length(min_length), m_polylines_out(polylines_out) {}
void add_inner_point(const Point* p)
@ -2294,7 +2295,7 @@ void Fill::connect_base_support(Polylines &&infill_ordered, const std::vector<co
#endif // INFILL_DEBUG_OUTPUT
base_support_extend_infill_lines(infill_ordered, graph, spacing, params);
#ifdef INFILL_DEBUG_OUTPUT
export_partial_infill_to_svg(debug_out_path("connect_base_support-extended-%03d.svg", iRun), graph, infill_ordered, polylines_out);
#endif // INFILL_DEBUG_OUTPUT
@ -2329,7 +2330,7 @@ void Fill::connect_base_support(Polylines &&infill_ordered, const std::vector<co
};
// Connect infill lines at cp and cpo_next_on_contour.
// If the complete arch cannot be taken, then
// If the complete arch cannot be taken, then
// if (take_first)
// take the infill line at cp and an arc from cp towards cp.next_on_contour.
// else
@ -2623,7 +2624,7 @@ void Fill::connect_base_support(Polylines &&infill_ordered, const std::vector<co
for (ContourIntersectionPoint &cp : graph.map_infill_end_point_to_boundary) {
const SupportArcCost &cost_prev = arches[(&cp - graph.map_infill_end_point_to_boundary.data()) * 2];
const SupportArcCost &cost_next = *(&cost_prev + 1);
if (cp.contour_not_taken_length_prev > SCALED_EPSILON &&
if (cp.contour_not_taken_length_prev > SCALED_EPSILON &&
(cost_prev.self_loop ?
cost_prev.cost > cap_cost :
cost_prev.cost > cost_veryhigh)) {
@ -2640,7 +2641,7 @@ void Fill::connect_base_support(Polylines &&infill_ordered, const std::vector<co
polylines_out.emplace_back(std::move(pl));
}
}
if (cp.contour_not_taken_length_next > SCALED_EPSILON &&
if (cp.contour_not_taken_length_next > SCALED_EPSILON &&
(cost_next.self_loop ?
cost_next.cost > cap_cost :
cost_next.cost > cost_veryhigh)) {