mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-05-17 18:42:24 +00:00
Allow specifying rotation patterns for Sparse and Solid infill (#9924)
* 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) * Add Cross zag and locked-zag for shoes Ported from BambuStudio * wip * sparse infill roratation template * solid_infill_rotate_template * remove rotate_solid_infill_direction * hide sparse infill rotation template for non applicable infill pattern * hide solid_infill_rotate_template for non supported solid infill patterns * update icon * support empty string for ConfigOptionFloats deserialize * fix build errors --------- Co-authored-by: Lukáš Hejl <hejl.lukas@gmail.com>
This commit is contained in:
@@ -67,6 +67,9 @@ 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();
|
||||
case ipCrossZag: return new FillCrossZag();
|
||||
case ipLockedZag: return new FillLockedZag();
|
||||
default: throw Slic3r::InvalidArgument("unknown type");
|
||||
}
|
||||
}
|
||||
@@ -243,7 +246,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)
|
||||
@@ -252,8 +255,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);
|
||||
@@ -279,8 +282,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
|
||||
@@ -354,10 +357,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; }
|
||||
};
|
||||
|
||||
@@ -566,7 +569,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> ¶ms,
|
||||
Polyline &pl1, const Points &contour, const std::vector<double> ¶ms,
|
||||
ContourIntersectionPoint *cp_start, ContourIntersectionPoint *cp_end, bool clockwise, double take_max_length, double line_half_width)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
@@ -730,8 +733,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;
|
||||
@@ -794,8 +797,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
|
||||
@@ -1155,7 +1158,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
|
||||
@@ -1295,21 +1298,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;
|
||||
}
|
||||
@@ -1367,7 +1370,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;
|
||||
@@ -1399,7 +1402,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;
|
||||
@@ -1496,7 +1499,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);
|
||||
@@ -1521,7 +1524,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;
|
||||
@@ -1556,6 +1559,18 @@ BoundaryInfillGraph create_boundary_infill_graph(const Polylines &infill_ordered
|
||||
return out;
|
||||
}
|
||||
|
||||
// The extended bounding box of the whole object that covers any rotation of every layer.
|
||||
BoundingBox Fill::extended_object_bounding_box() const
|
||||
{
|
||||
BoundingBox out = bounding_box;
|
||||
out.merge(Point(out.min.y(), out.min.x()));
|
||||
out.merge(Point(out.max.y(), out.max.x()));
|
||||
|
||||
// The bounding box is scaled by sqrt(2.) to ensure that the bounding box
|
||||
// covers any possible rotations.
|
||||
return out.scaled(sqrt(2.));
|
||||
}
|
||||
|
||||
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());
|
||||
@@ -1927,14 +1942,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)
|
||||
@@ -1990,13 +2005,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)
|
||||
@@ -2297,7 +2312,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
|
||||
@@ -2332,7 +2347,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
|
||||
@@ -2626,7 +2641,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)) {
|
||||
@@ -2643,7 +2658,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)) {
|
||||
|
||||
Reference in New Issue
Block a user