mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-08-16 20:15:53 +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) {
|
for (size_t i_seg = 0; i_seg < segs.size(); ++i_seg) {
|
||||||
SegmentedIntersectionLine& sil = segs[i_seg];
|
SegmentedIntersectionLine& sil = segs[i_seg];
|
||||||
if ((sil.intersections.size() & 1) == 1 && sil.intersections.size() > 1) {
|
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;
|
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 == 0 && sil.intersections[sil.intersections.size() - 2].iContour == 0)
|
if (sil.intersections.back().iContour == sil.intersections[sil.intersections.size() - 2].iContour)
|
||||||
sil.intersections.pop_back();
|
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
|
#ifdef SLIC3R_DEBUG
|
||||||
@ -1172,6 +1176,8 @@ static void connect_segment_intersections_by_contours(
|
|||||||
same_next = true;
|
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(iprev >= 0);
|
||||||
assert(inext >= 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.
|
// Make the LinkQuality::Invalid symmetric on vertical connections.
|
||||||
for (size_t i_intersection = 0; i_intersection < il.intersections.size(); ++i_intersection) {
|
for (size_t i_intersection = 0; i_intersection < il.intersections.size(); ++i_intersection) {
|
||||||
SegmentIntersection& it = il.intersections[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(
|
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.
|
// 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.
|
// 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();
|
pointLast = polylines_out.back().points.back();
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (i_intersection == -1) {
|
if (i_intersection == -1) {
|
||||||
|
if (!polylines_out.empty()) {
|
||||||
// The path has been interrupted. Find a next starting point, closest to the previous extruder position.
|
// 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();
|
coordf_t dist2min = std::numeric_limits<coordf_t>().max();
|
||||||
for (size_t i_vline2 = 0; i_vline2 < segs.size(); ++i_vline2) {
|
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.
|
// Emit the first point of a path.
|
||||||
pointLast = Point(segs[i_vline].pos, segs[i_vline].intersections[i_intersection].pos());
|
pointLast = Point(segs[i_vline].pos, segs[i_vline].intersections[i_intersection].pos());
|
||||||
polyline_current->points.push_back(pointLast);
|
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.
|
// From the initial point (i_vline, i_intersection), follow a path.
|
||||||
SegmentedIntersectionLine& vline = segs[i_vline];
|
SegmentedIntersectionLine& vline = segs[i_vline];
|
||||||
SegmentIntersection* it = &vline.intersections[i_intersection];
|
SegmentIntersection* it = &vline.intersections[i_intersection];
|
||||||
@ -1555,6 +1639,14 @@ static void traverse_graph_generate_polylines(
|
|||||||
int i_next = it->right_horizontal();
|
int i_next = it->right_horizontal();
|
||||||
bool intersection_prev_valid = intersection_on_prev_vertical_line_valid(segs, i_vline, i_intersection);
|
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);
|
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;
|
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.
|
// 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)
|
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);
|
std::vector<MonotonicRegionLink> path = chain_monotonic_regions(regions, poly_with_offset, segs, rng);
|
||||||
polylines_from_paths(path, poly_with_offset, segs, polylines_out);
|
polylines_from_paths(path, poly_with_offset, segs, polylines_out);
|
||||||
}
|
}
|
||||||
} else
|
} else {
|
||||||
traverse_graph_generate_polylines(poly_with_offset, params, segs, polylines_out);
|
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
|
#ifdef SLIC3R_DEBUG
|
||||||
@ -3013,6 +3118,9 @@ bool FillRectilinear::fill_surface_by_multilines(const Surface* surface, FillPar
|
|||||||
auto it_high = it;
|
auto it_high = it;
|
||||||
assert(it_high->type == SegmentIntersection::OUTER_HIGH);
|
assert(it_high->type == SegmentIntersection::OUTER_HIGH);
|
||||||
if (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));
|
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;
|
++it;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user