Merge branch 'master' of https://github.com/prusa3d/PrusaSlicer into dev
This commit is contained in:
commit
8033bb654a
1 changed files with 89 additions and 67 deletions
|
@ -20,6 +20,8 @@ struct TravelPoint
|
|||
Point point;
|
||||
// Index of the polygon containing this point. A negative value indicates that the point is not on any border.
|
||||
int border_idx;
|
||||
// simplify_travel() doesn't remove this point.
|
||||
bool do_not_remove = false;
|
||||
};
|
||||
|
||||
struct Intersection
|
||||
|
@ -32,6 +34,8 @@ struct Intersection
|
|||
Point point;
|
||||
// Distance from the first point in the corresponding boundary
|
||||
float distance;
|
||||
// simplify_travel() doesn't remove this point.
|
||||
bool do_not_remove = false;
|
||||
};
|
||||
|
||||
struct ClosestLine
|
||||
|
@ -207,8 +211,8 @@ static std::vector<Intersection> extend_for_closest_lines(const std::vector<Inte
|
|||
const ClosestLine &cl_start = start_lines[cl_indices.first];
|
||||
const ClosestLine &cl_end = end_lines[cl_indices.second];
|
||||
std::vector<Intersection> new_intersections;
|
||||
new_intersections.push_back({cl_start.border_idx, cl_start.line_idx, cl_start.point, compute_distance(cl_start)});
|
||||
new_intersections.push_back({cl_end.border_idx, cl_end.line_idx, cl_end.point, compute_distance(cl_end)});
|
||||
new_intersections.push_back({cl_start.border_idx, cl_start.line_idx, cl_start.point, compute_distance(cl_start), true});
|
||||
new_intersections.push_back({cl_end.border_idx, cl_end.line_idx, cl_end.point, compute_distance(cl_end), true});
|
||||
return new_intersections;
|
||||
}
|
||||
}
|
||||
|
@ -259,7 +263,7 @@ static std::vector<Intersection> extend_for_closest_lines(const std::vector<Inte
|
|||
if (cl_start_idx != std::numeric_limits<size_t>::max()) {
|
||||
// If there is any ClosestLine around the start point closer to the Intersection, then replace this Intersection with ClosestLine.
|
||||
const ClosestLine &cl_start = start_lines[cl_start_idx];
|
||||
new_intersections.front() = {cl_start.border_idx, cl_start.line_idx, cl_start.point, compute_distance(cl_start)};
|
||||
new_intersections.front() = {cl_start.border_idx, cl_start.line_idx, cl_start.point, compute_distance(cl_start), true};
|
||||
} else {
|
||||
// Check if there is any ClosestLine with the same boundary_idx as any Intersection. If this ClosestLine exists, then add it to the
|
||||
// vector of intersections. This allows in some cases when it is more than one around ClosestLine start point chose that one which
|
||||
|
@ -267,7 +271,7 @@ static std::vector<Intersection> extend_for_closest_lines(const std::vector<Inte
|
|||
// use the first one, which is the closest one to the start point.
|
||||
size_t start_closest_lines_idx = find_closest_line_with_same_boundary_idx(start_lines, new_intersections, true);
|
||||
const ClosestLine &cl_start = (start_closest_lines_idx != std::numeric_limits<size_t>::max()) ? start_lines[start_closest_lines_idx] : start_lines.front();
|
||||
new_intersections.insert(new_intersections.begin(),{cl_start.border_idx, cl_start.line_idx, cl_start.point, compute_distance(cl_start)});
|
||||
new_intersections.insert(new_intersections.begin(),{cl_start.border_idx, cl_start.line_idx, cl_start.point, compute_distance(cl_start), true});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -276,7 +280,7 @@ static std::vector<Intersection> extend_for_closest_lines(const std::vector<Inte
|
|||
if (cl_end_idx != std::numeric_limits<size_t>::max()) {
|
||||
// If there is any ClosestLine around the end point closer to the Intersection, then replace this Intersection with ClosestLine.
|
||||
const ClosestLine &cl_end = end_lines[cl_end_idx];
|
||||
new_intersections.back() = {cl_end.border_idx, cl_end.line_idx, cl_end.point, compute_distance(cl_end)};
|
||||
new_intersections.back() = {cl_end.border_idx, cl_end.line_idx, cl_end.point, compute_distance(cl_end), true};
|
||||
} else {
|
||||
// Check if there is any ClosestLine with the same boundary_idx as any Intersection. If this ClosestLine exists, then add it to the
|
||||
// vector of intersections. This allows in some cases when it is more than one around ClosestLine end point chose that one which
|
||||
|
@ -284,7 +288,7 @@ static std::vector<Intersection> extend_for_closest_lines(const std::vector<Inte
|
|||
// use the first one, which is the closest one to the end point.
|
||||
size_t end_closest_lines_idx = find_closest_line_with_same_boundary_idx(end_lines, new_intersections, false);
|
||||
const ClosestLine &cl_end = (end_closest_lines_idx != std::numeric_limits<size_t>::max()) ? end_lines[end_closest_lines_idx] : end_lines.front();
|
||||
new_intersections.push_back({cl_end.border_idx, cl_end.line_idx, cl_end.point, compute_distance(cl_end)});
|
||||
new_intersections.push_back({cl_end.border_idx, cl_end.line_idx, cl_end.point, compute_distance(cl_end), true});
|
||||
}
|
||||
}
|
||||
return new_intersections;
|
||||
|
@ -359,16 +363,17 @@ static void export_travel_to_svg(const Polygons &boundary,
|
|||
const std::vector<Intersection> &intersections,
|
||||
const std::string &path)
|
||||
{
|
||||
BoundingBox bbox = get_extents(boundary);
|
||||
coordf_t stroke_width = scale_(0.05);
|
||||
BoundingBox bbox = get_extents(boundary);
|
||||
::Slic3r::SVG svg(path, bbox);
|
||||
svg.draw_outline(boundary, "green");
|
||||
svg.draw(original_travel, "blue");
|
||||
svg.draw(result_travel, "red");
|
||||
svg.draw(original_travel.a, "black");
|
||||
svg.draw(original_travel.b, "grey");
|
||||
svg.draw_outline(boundary, "green", stroke_width);
|
||||
svg.draw(original_travel, "blue", stroke_width);
|
||||
svg.draw(result_travel, "red", stroke_width);
|
||||
svg.draw(original_travel.a, "black", stroke_width);
|
||||
svg.draw(original_travel.b, "grey", stroke_width);
|
||||
|
||||
for (const Intersection &intersection : intersections)
|
||||
svg.draw(intersection.point, "lightseagreen");
|
||||
svg.draw(intersection.point, "lightseagreen", stroke_width);
|
||||
}
|
||||
|
||||
static void export_travel_to_svg(const Polygons &boundary,
|
||||
|
@ -433,21 +438,22 @@ static std::vector<TravelPoint> simplify_travel(const AvoidCrossingPerimeters::B
|
|||
|
||||
visitor.pt_current = ¤t_point;
|
||||
|
||||
for (size_t point_idx_2 = point_idx + 1; point_idx_2 < travel.size(); ++point_idx_2) {
|
||||
if (travel[point_idx_2].point == current_point) {
|
||||
next = travel[point_idx_2];
|
||||
point_idx = point_idx_2;
|
||||
continue;
|
||||
}
|
||||
if (!next.do_not_remove)
|
||||
for (size_t point_idx_2 = point_idx + 1; point_idx_2 < travel.size() && !travel[point_idx_2].do_not_remove; ++point_idx_2) {
|
||||
if (travel[point_idx_2].point == current_point) {
|
||||
next = travel[point_idx_2];
|
||||
point_idx = point_idx_2;
|
||||
continue;
|
||||
}
|
||||
|
||||
visitor.pt_next = &travel[point_idx_2].point;
|
||||
boundary.grid.visit_cells_intersecting_line(*visitor.pt_current, *visitor.pt_next, visitor);
|
||||
// Check if deleting point causes crossing a boundary
|
||||
if (!visitor.intersect) {
|
||||
next = travel[point_idx_2];
|
||||
point_idx = point_idx_2;
|
||||
visitor.pt_next = &travel[point_idx_2].point;
|
||||
boundary.grid.visit_cells_intersecting_line(*visitor.pt_current, *visitor.pt_next, visitor);
|
||||
// Check if deleting point causes crossing a boundary
|
||||
if (!visitor.intersect) {
|
||||
next = travel[point_idx_2];
|
||||
point_idx = point_idx_2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
simplified_path.emplace_back(next);
|
||||
}
|
||||
|
@ -566,7 +572,7 @@ static size_t avoid_perimeters_inner(const AvoidCrossingPerimeters::Boundary &bo
|
|||
// Offset of the polygon's point using get_middle_point_offset is used to simplify the calculation of intersection between the
|
||||
// boundary and the travel. The appended point is translated in the direction of inward normal. This translation ensures that the
|
||||
// appended point will be inside the polygon and not on the polygon border.
|
||||
result.push_back({get_middle_point_offset(boundaries[intersection_first.border_idx], left_idx, right_idx, intersection_first.point, coord_t(SCALED_EPSILON)), int(intersection_first.border_idx)});
|
||||
result.push_back({get_middle_point_offset(boundaries[intersection_first.border_idx], left_idx, right_idx, intersection_first.point, coord_t(SCALED_EPSILON)), int(intersection_first.border_idx), intersection_first.do_not_remove});
|
||||
|
||||
// Check if intersection line also exit the boundary polygon
|
||||
if (it_second_r != it_last_item) {
|
||||
|
@ -590,7 +596,7 @@ static size_t avoid_perimeters_inner(const AvoidCrossingPerimeters::Boundary &bo
|
|||
// Append the farthest intersection into the path
|
||||
left_idx = intersection_second.line_idx;
|
||||
right_idx = (intersection_second.line_idx >= (boundaries[intersection_second.border_idx].points.size() - 1)) ? 0 : (intersection_second.line_idx + 1);
|
||||
result.push_back({get_middle_point_offset(boundaries[intersection_second.border_idx], left_idx, right_idx, intersection_second.point, coord_t(SCALED_EPSILON)), int(intersection_second.border_idx)});
|
||||
result.push_back({get_middle_point_offset(boundaries[intersection_second.border_idx], left_idx, right_idx, intersection_second.point, coord_t(SCALED_EPSILON)), int(intersection_second.border_idx), intersection_second.do_not_remove});
|
||||
// Skip intersections in between
|
||||
it_first = it_second;
|
||||
}
|
||||
|
@ -945,55 +951,71 @@ static std::vector<float> contour_distance(const EdgeGrid::Grid &grid,
|
|||
// ExPolygons are handled one by one so returned ExPolygons could intersect.
|
||||
static ExPolygons inner_offset(const ExPolygons &ex_polygons, double offset)
|
||||
{
|
||||
double min_contour_width = 2. * offset + SCALED_EPSILON;
|
||||
double search_radius = 2. * (offset + min_contour_width);
|
||||
ExPolygons ex_poly_result = ex_polygons;
|
||||
const std::vector<double> min_contour_width_values = {offset / 2., offset, 2. * offset + SCALED_EPSILON};
|
||||
ExPolygons ex_poly_result = ex_polygons;
|
||||
resample_expolygons(ex_poly_result, offset / 2, scaled<double>(0.5));
|
||||
|
||||
for (ExPolygon &ex_poly : ex_poly_result) {
|
||||
BoundingBox bbox(get_extents(ex_poly));
|
||||
bbox.offset(SCALED_EPSILON);
|
||||
EdgeGrid::Grid grid;
|
||||
grid.set_bbox(bbox);
|
||||
grid.create(ex_poly, coord_t(0.7 * search_radius));
|
||||
|
||||
std::vector<std::vector<float>> ex_poly_distances;
|
||||
precompute_expolygon_distances(ex_poly, ex_poly_distances);
|
||||
// Filter out expolygons smaller than 0.1mm^2
|
||||
if (Vec2d bbox_size = bbox.size().cast<double>(); bbox_size.x() * bbox_size.y() < Slic3r::sqr(scale_(0.1f)))
|
||||
continue;
|
||||
|
||||
std::vector<std::vector<float>> offsets;
|
||||
offsets.reserve(ex_poly.holes.size() + 1);
|
||||
for (size_t idx_contour = 0; idx_contour <= ex_poly.holes.size(); ++idx_contour) {
|
||||
const Polygon &poly = (idx_contour == 0) ? ex_poly.contour : ex_poly.holes[idx_contour - 1];
|
||||
assert(poly.is_counter_clockwise() == (idx_contour == 0));
|
||||
std::vector<float> distances = contour_distance(grid, ex_poly_distances[idx_contour], idx_contour, poly, offset, search_radius);
|
||||
for (float &distance : distances) {
|
||||
if (distance < min_contour_width)
|
||||
distance = 0.f;
|
||||
else if (distance > min_contour_width + 2. * offset)
|
||||
distance = - float(offset);
|
||||
else
|
||||
distance = - (distance - float(min_contour_width)) / 2.f;
|
||||
}
|
||||
offsets.emplace_back(distances);
|
||||
}
|
||||
for (const double &min_contour_width : min_contour_width_values) {
|
||||
const size_t min_contour_width_idx = &min_contour_width - &min_contour_width_values.front();
|
||||
const double search_radius = 2. * (offset + min_contour_width);
|
||||
|
||||
ExPolygons offset_ex_poly = variable_offset_inner_ex(ex_poly, offsets);
|
||||
// If variable_offset_inner_ex produces empty result, then original ex_polygon is used
|
||||
if (offset_ex_poly.size() == 1) {
|
||||
ex_poly = std::move(offset_ex_poly.front());
|
||||
} else if (offset_ex_poly.size() > 1) {
|
||||
// fix_after_inner_offset called inside variable_offset_inner_ex sometimes produces
|
||||
// tiny artefacts polygons, so these artefacts are removed.
|
||||
double max_area = offset_ex_poly.front().area();
|
||||
size_t max_area_idx = 0;
|
||||
for (size_t poly_idx = 1; poly_idx < offset_ex_poly.size(); ++poly_idx) {
|
||||
double area = offset_ex_poly[poly_idx].area();
|
||||
if (max_area < area) {
|
||||
max_area = area;
|
||||
max_area_idx = poly_idx;
|
||||
EdgeGrid::Grid grid;
|
||||
grid.set_bbox(bbox);
|
||||
grid.create(ex_poly, coord_t(0.7 * search_radius));
|
||||
|
||||
std::vector<std::vector<float>> ex_poly_distances;
|
||||
precompute_expolygon_distances(ex_poly, ex_poly_distances);
|
||||
|
||||
std::vector<std::vector<float>> offsets;
|
||||
offsets.reserve(ex_poly.holes.size() + 1);
|
||||
for (size_t idx_contour = 0; idx_contour <= ex_poly.holes.size(); ++idx_contour) {
|
||||
const Polygon &poly = (idx_contour == 0) ? ex_poly.contour : ex_poly.holes[idx_contour - 1];
|
||||
assert(poly.is_counter_clockwise() == (idx_contour == 0));
|
||||
std::vector<float> distances = contour_distance(grid, ex_poly_distances[idx_contour], idx_contour, poly, offset, search_radius);
|
||||
for (float &distance : distances) {
|
||||
if (distance < min_contour_width)
|
||||
distance = 0.f;
|
||||
else if (distance > min_contour_width + 2. * offset)
|
||||
distance = -float(offset);
|
||||
else
|
||||
distance = -(distance - float(min_contour_width)) / 2.f;
|
||||
}
|
||||
offsets.emplace_back(distances);
|
||||
}
|
||||
|
||||
ExPolygons offset_ex_poly = variable_offset_inner_ex(ex_poly, offsets);
|
||||
// If variable_offset_inner_ex produces empty result, then original ex_polygon is used
|
||||
if (offset_ex_poly.size() == 1 && offset_ex_poly.front().holes.size() == ex_poly.holes.size()) {
|
||||
ex_poly = std::move(offset_ex_poly.front());
|
||||
break;
|
||||
} else if ((min_contour_width_idx + 1) < min_contour_width_values.size()) {
|
||||
continue; // Try the next round with bigger min_contour_width.
|
||||
} else if (offset_ex_poly.size() == 1) {
|
||||
ex_poly = std::move(offset_ex_poly.front());
|
||||
break;
|
||||
} else if (offset_ex_poly.size() > 1) {
|
||||
// fix_after_inner_offset called inside variable_offset_inner_ex sometimes produces
|
||||
// tiny artefacts polygons, so these artefacts are removed.
|
||||
double max_area = offset_ex_poly.front().area();
|
||||
size_t max_area_idx = 0;
|
||||
for (size_t poly_idx = 1; poly_idx < offset_ex_poly.size(); ++poly_idx) {
|
||||
double area = offset_ex_poly[poly_idx].area();
|
||||
if (max_area < area) {
|
||||
max_area = area;
|
||||
max_area_idx = poly_idx;
|
||||
}
|
||||
}
|
||||
ex_poly = std::move(offset_ex_poly[max_area_idx]);
|
||||
break;
|
||||
}
|
||||
ex_poly = std::move(offset_ex_poly[max_area_idx]);
|
||||
}
|
||||
}
|
||||
return ex_poly_result;
|
||||
|
|
Loading…
Add table
Reference in a new issue