mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-08-16 08:25:55 +08:00
Rectilinear improvements:
* for bridges, don't connect if too long (2*spacing). Prevent printing a bridge over another one, following the perimeter. * try to start the connect the lines from both direction, and choose the one with less continuous lines. * Fix some cases where rectilinear put itself in a bad state. supermerill/superslicer#1889
This commit is contained in:
parent
56af116257
commit
d1fa026479
@ -959,10 +959,14 @@ static void slice_region_by_vertical_lines(const FillRectilinear* filler, std::v
|
||||
for (size_t i_seg = 0; i_seg < segs.size(); ++i_seg) {
|
||||
SegmentedIntersectionLine& sil = segs[i_seg];
|
||||
if ((sil.intersections.size() & 1) == 1 && sil.intersections.size() > 1) {
|
||||
BOOST_LOG_TRIVIAL(error) << "FillRectilinear::fill_surface() failed to fill a region: impair number of intersections at layer " << filler->layer_id << " @z="<< filler->z;
|
||||
if (sil.intersections.back().iContour == 0 && sil.intersections[sil.intersections.size() - 2].iContour == 0)
|
||||
BOOST_LOG_TRIVIAL(error) << "FillRectilinear::fill_surface() fail: impair number of intersections at layer " << filler->layer_id << " @z="<< filler->z;
|
||||
if (sil.intersections.back().iContour == sil.intersections[sil.intersections.size() - 2].iContour)
|
||||
sil.intersections.pop_back();
|
||||
}
|
||||
if (sil.intersections.size() == 1) {
|
||||
BOOST_LOG_TRIVIAL(error) << "FillRectilinear::fill_surface() fail: only one intersection at layer " << filler->layer_id << " @z=" << filler->z;
|
||||
sil.intersections.clear();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SLIC3R_DEBUG
|
||||
@ -1172,6 +1176,8 @@ static void connect_segment_intersections_by_contours(
|
||||
same_next = true;
|
||||
}
|
||||
}
|
||||
// note: here, an intersection can have its prev to vertical on the same line, but the other intersection can have its intersection on horizontal
|
||||
// it can be problematic...
|
||||
assert(iprev >= 0);
|
||||
assert(inext >= 0);
|
||||
|
||||
@ -1248,6 +1254,27 @@ static void connect_segment_intersections_by_contours(
|
||||
}
|
||||
}
|
||||
|
||||
// Removed un-mirrored vertical connection.
|
||||
for (size_t i_intersection = 0; i_intersection < il.intersections.size(); ++i_intersection) {
|
||||
SegmentIntersection& it = il.intersections[i_intersection];
|
||||
if (it.has_left_vertical()) {
|
||||
SegmentIntersection& it2 = il.intersections[it.left_vertical()];
|
||||
if (it2.left_vertical() != i_intersection) {
|
||||
// as it can happen that a vertical connection isn't symetric, if it happens, break the erroneous link
|
||||
it.prev_on_contour = -1;
|
||||
it.prev_on_contour_type = SegmentIntersection::LinkType::Phony;
|
||||
}
|
||||
}
|
||||
if (it.has_right_vertical()) {
|
||||
SegmentIntersection& it2 = il.intersections[it.right_vertical()];
|
||||
if (it2.right_vertical() != i_intersection) {
|
||||
// as it can happen that a vertical connection isn't symetric, if it happens, break the erroneous link
|
||||
it.next_on_contour = -1;
|
||||
it.next_on_contour_type = SegmentIntersection::LinkType::Phony;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make the LinkQuality::Invalid symmetric on vertical connections.
|
||||
for (size_t i_intersection = 0; i_intersection < il.intersections.size(); ++i_intersection) {
|
||||
SegmentIntersection& it = il.intersections[i_intersection];
|
||||
@ -1419,7 +1446,7 @@ static SegmentIntersection& end_of_vertical_run(SegmentedIntersectionLine& il, S
|
||||
}
|
||||
|
||||
static void traverse_graph_generate_polylines(
|
||||
const ExPolygonWithOffset& poly_with_offset, const FillParams& params, std::vector<SegmentedIntersectionLine>& segs, Polylines& polylines_out)
|
||||
const ExPolygonWithOffset& poly_with_offset, const FillParams& params, std::vector<SegmentedIntersectionLine>& segs, Polylines& polylines_out, coord_t spacing, bool inverted_dir = false)
|
||||
{
|
||||
// For each outer only chords, measure their maximum distance to the bow of the outer contour.
|
||||
// Mark an outer only chord as consumed, if the distance is low.
|
||||
@ -1453,6 +1480,7 @@ static void traverse_graph_generate_polylines(
|
||||
pointLast = polylines_out.back().points.back();
|
||||
for (;;) {
|
||||
if (i_intersection == -1) {
|
||||
if (!polylines_out.empty()) {
|
||||
// The path has been interrupted. Find a next starting point, closest to the previous extruder position.
|
||||
coordf_t dist2min = std::numeric_limits<coordf_t>().max();
|
||||
for (size_t i_vline2 = 0; i_vline2 < segs.size(); ++i_vline2) {
|
||||
@ -1496,8 +1524,64 @@ static void traverse_graph_generate_polylines(
|
||||
// Emit the first point of a path.
|
||||
pointLast = Point(segs[i_vline].pos, segs[i_vline].intersections[i_intersection].pos());
|
||||
polyline_current->points.push_back(pointLast);
|
||||
|
||||
} else {
|
||||
//find the starting intersection
|
||||
i_vline = 0;
|
||||
i_intersection = 0;
|
||||
bool found = false;
|
||||
while (!found) {
|
||||
//go to next column if we don't found a suitable one in the current column
|
||||
while (i_intersection >= segs[i_vline].intersections.size()) {
|
||||
i_vline++;
|
||||
i_intersection = 0;
|
||||
if (i_vline >= segs.size()) {
|
||||
// nothing to merge
|
||||
return;
|
||||
}
|
||||
}
|
||||
assert(segs[i_vline].intersections[i_intersection].is_low() || i_intersection > 0);
|
||||
//does the current on is suitable?
|
||||
bool consumed = segs[i_vline].intersections[i_intersection].is_low() ?
|
||||
segs[i_vline].intersections[i_intersection].consumed_vertical_up :
|
||||
segs[i_vline].intersections[i_intersection - 1].consumed_vertical_up;
|
||||
//move
|
||||
if (consumed)
|
||||
i_intersection++;
|
||||
else
|
||||
found = true;
|
||||
}
|
||||
//if inverted dir, stay on the current column but try to start at the opposide side
|
||||
if (inverted_dir) {
|
||||
int i_intersection_inv = segs[i_vline].intersections.size() - 1;
|
||||
found = false;
|
||||
while (!found) {
|
||||
assert(segs[i_vline].intersections[i_intersection_inv].is_low() || i_intersection_inv > 0);
|
||||
bool consumed_inv = segs[i_vline].intersections[i_intersection_inv].is_low() ?
|
||||
segs[i_vline].intersections[i_intersection_inv].consumed_vertical_up :
|
||||
segs[i_vline].intersections[i_intersection_inv - 1].consumed_vertical_up;
|
||||
if (consumed_inv)
|
||||
i_intersection_inv--;
|
||||
else
|
||||
found = true;
|
||||
if (i_intersection_inv <= i_intersection) {
|
||||
//can't use another start point, return so we can use the other path.
|
||||
return;
|
||||
}
|
||||
}
|
||||
i_intersection = i_intersection_inv;
|
||||
}
|
||||
// Start a new path with no previous position
|
||||
polylines_out.push_back(Polyline());
|
||||
polyline_current = &polylines_out.back();
|
||||
// Emit the first point of a path.
|
||||
pointLast = Point(segs[i_vline].pos, segs[i_vline].intersections[i_intersection].pos());
|
||||
polyline_current->points.push_back(pointLast);
|
||||
}
|
||||
}
|
||||
|
||||
assert(i_vline >= 0);
|
||||
assert(i_intersection >= 0);
|
||||
// From the initial point (i_vline, i_intersection), follow a path.
|
||||
SegmentedIntersectionLine& vline = segs[i_vline];
|
||||
SegmentIntersection* it = &vline.intersections[i_intersection];
|
||||
@ -1555,6 +1639,14 @@ static void traverse_graph_generate_polylines(
|
||||
int i_next = it->right_horizontal();
|
||||
bool intersection_prev_valid = intersection_on_prev_vertical_line_valid(segs, i_vline, i_intersection);
|
||||
bool intersection_next_valid = intersection_on_next_vertical_line_valid(segs, i_vline, i_intersection);
|
||||
// special path for bridges: do not make long connection, as it's over-extruded.
|
||||
if (params.flow.bridge) {
|
||||
coordf_t max_length = coordf_t(spacing) * 2.1;
|
||||
intersection_prev_valid = (intersection_prev_valid
|
||||
&& measure_perimeter_horizontal_segment_length(poly_with_offset, segs, i_vline - 1, i_prev, i_intersection) < max_length);
|
||||
intersection_next_valid = (intersection_next_valid
|
||||
&& measure_perimeter_horizontal_segment_length(poly_with_offset, segs, i_vline, i_intersection, i_next) < max_length);
|
||||
}
|
||||
bool intersection_horizontal_valid = intersection_prev_valid || intersection_next_valid;
|
||||
// Mark both the left and right connecting segment as consumed, because one cannot go to this intersection point as it has been consumed.
|
||||
if (i_prev != -1)
|
||||
@ -2920,8 +3012,21 @@ bool FillRectilinear::fill_surface_by_lines(const Surface *surface, const FillPa
|
||||
std::vector<MonotonicRegionLink> path = chain_monotonic_regions(regions, poly_with_offset, segs, rng);
|
||||
polylines_from_paths(path, poly_with_offset, segs, polylines_out);
|
||||
}
|
||||
} else
|
||||
traverse_graph_generate_polylines(poly_with_offset, params, segs, polylines_out);
|
||||
} else {
|
||||
std::vector<SegmentedIntersectionLine> segs_save = segs;
|
||||
if (polylines_out.size() > 0) {
|
||||
traverse_graph_generate_polylines(poly_with_offset, params, segs, polylines_out, line_spacing);
|
||||
} else {
|
||||
traverse_graph_generate_polylines(poly_with_offset, params, segs, polylines_out, line_spacing);
|
||||
if (polylines_out.size() > 1) {
|
||||
//try with inverted dir if the connection is better
|
||||
Polylines next_try;
|
||||
traverse_graph_generate_polylines(poly_with_offset, params, segs_save, next_try, line_spacing, true);
|
||||
if (next_try.size() > 0 && next_try.size() < polylines_out.size())
|
||||
polylines_out = next_try;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef SLIC3R_DEBUG
|
||||
@ -3013,6 +3118,9 @@ bool FillRectilinear::fill_surface_by_multilines(const Surface* surface, FillPar
|
||||
auto it_high = it;
|
||||
assert(it_high->type == SegmentIntersection::OUTER_HIGH);
|
||||
if (it_high->type == SegmentIntersection::OUTER_HIGH) {
|
||||
if (angle == 0.)
|
||||
fill_lines.emplace_back(Point(vline.pos, it_low->pos()), Point(vline.pos, it_high->pos()));
|
||||
else
|
||||
fill_lines.emplace_back(Point(vline.pos, it_low->pos()).rotated(cos_a, sin_a), Point(vline.pos, it_high->pos()).rotated(cos_a, sin_a));
|
||||
++it;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user