Refactoring of the adaptive infill using hooks
This commit is contained in:
parent
cd2881e14e
commit
de242f48cb
1 changed files with 80 additions and 55 deletions
|
@ -565,33 +565,43 @@ static Matrix2d rotation_matrix_from_vector(const Point &vector)
|
|||
|
||||
struct Intersection
|
||||
{
|
||||
// Index of the closest line to intersect_line
|
||||
size_t closest_line_idx;
|
||||
// Copy of closest line to intersect_point, used for storing original line in an unchanged state
|
||||
Line closest_line;
|
||||
Point closest_point;
|
||||
// Point for which is computed closest line (closest_line)
|
||||
Point intersect_point;
|
||||
// Index of the polyline from which is computed closest_line
|
||||
size_t intersect_pl_idx;
|
||||
// Pointer to the polyline from which is computed closest_line
|
||||
Polyline *intersect_pl;
|
||||
// The line for which is computed closest line from intersect_point to closest_line
|
||||
Line intersect_line;
|
||||
// Indicate if intersect_point is the first or the last point of intersect_line
|
||||
bool forward;
|
||||
// Indication if this intersection has been proceed
|
||||
bool used = false;
|
||||
|
||||
Intersection(const size_t closest_line_idx,
|
||||
const Line &closest_line,
|
||||
const Point &closest_point,
|
||||
const Point &intersect_point,
|
||||
size_t intersect_pl_idx,
|
||||
Polyline *intersect_pl,
|
||||
const Line &intersect_line,
|
||||
bool forward)
|
||||
: closest_line_idx(closest_line_idx)
|
||||
, closest_line(closest_line)
|
||||
, closest_point(closest_point)
|
||||
, intersect_point(intersect_point)
|
||||
, intersect_pl_idx(intersect_pl_idx)
|
||||
, intersect_pl(intersect_pl)
|
||||
, intersect_line(intersect_line)
|
||||
, forward(forward){};
|
||||
, forward(forward)
|
||||
{}
|
||||
};
|
||||
|
||||
static inline Intersection *get_nearest_intersection(std::vector<std::pair<Intersection, double>> &intersect_line, const size_t first_idx)
|
||||
{
|
||||
assert(intersect_line.size() >= 2);
|
||||
if (first_idx == 0)
|
||||
return &intersect_line[first_idx + 1].first;
|
||||
else if (first_idx == (intersect_line.size() - 1))
|
||||
|
@ -600,8 +610,9 @@ static inline Intersection *get_nearest_intersection(std::vector<std::pair<Inter
|
|||
return &intersect_line[first_idx - 1].first;
|
||||
else
|
||||
return &intersect_line[first_idx + 1].first;
|
||||
};
|
||||
}
|
||||
|
||||
// Create a line based on line_to_offset translated it in the direction of the intersection line (intersection.intersect_line)
|
||||
static Line create_offset_line(const Line &line_to_offset, const Intersection &intersection, const double scaled_spacing)
|
||||
{
|
||||
Matrix2d rotation = rotation_matrix_from_vector(line_to_offset.vector());
|
||||
|
@ -612,12 +623,9 @@ static Line create_offset_line(const Line &line_to_offset, const Intersection &i
|
|||
if ((rotation * furthest_point).y() >= (rotation * offset_line_point).y()) offset_vector *= -1;
|
||||
|
||||
Line offset_line = line_to_offset;
|
||||
Point line_extension = (1000000. * line_to_offset.vector().cast<double>().normalized()).cast<coord_t>();
|
||||
|
||||
offset_line.translate(offset_vector.x(), offset_vector.y());
|
||||
offset_line.a -= line_extension;
|
||||
offset_line.b += line_extension;
|
||||
|
||||
// Extend the line by small value to guarantee a collision with adjacent lines
|
||||
offset_line.offset(1000000);
|
||||
return offset_line;
|
||||
};
|
||||
|
||||
|
@ -630,6 +638,7 @@ using rtree_point_t = bgm::point<int64_t, 2, boost::geometry::cs::cartesian>;
|
|||
using rtree_segment_t = bgm::segment<rtree_point_t>;
|
||||
using rtree_t = bgi::rtree<std::pair<rtree_segment_t, size_t>, bgi::rstar<16, 4>>;
|
||||
|
||||
// Create a hook based on hook_line and append it to the begin or end of the polyline in the intersection
|
||||
static void add_hook(const Intersection &intersection, const Line &hook_line, const double scaled_spacing, const int hook_length, const rtree_t &rtree)
|
||||
{
|
||||
Vec2d hook_vector_norm = hook_line.vector().cast<double>().normalized();
|
||||
|
@ -642,13 +651,18 @@ static void add_hook(const Intersection &intersection, const Line &hook_line, co
|
|||
|
||||
Line hook_forward(intersection_point, intersection_point + hook_vector);
|
||||
Line hook_backward(intersection_point, intersection_point - hook_vector);
|
||||
Line hook_forward_o = hook_forward, hook_backward_o = hook_backward;
|
||||
hook_forward_o.offset(-SCALED_EPSILON);
|
||||
hook_backward_o.offset(-SCALED_EPSILON);
|
||||
|
||||
auto filter_itself = [&intersection](const auto &item) {
|
||||
const rtree_segment_t &seg = item.first;
|
||||
const Point &i_point = intersection.intersect_point;
|
||||
return !((i_point.x() == bg::get<0, 0>(seg) && i_point.y() == bg::get<0, 1>(seg)) ||
|
||||
(i_point.x() == bg::get<1, 0>(seg) && i_point.y() == bg::get<1, 1>(seg)));
|
||||
};
|
||||
|
||||
std::vector<std::pair<rtree_segment_t, size_t>> hook_intersections;
|
||||
rtree.query(bgi::intersects(rtree_segment_t(rtree_point_t(hook_forward_o.a.x(), hook_forward_o.a.y()),
|
||||
rtree_point_t(hook_forward_o.b.x(), hook_forward_o.b.y()))),
|
||||
rtree.query(bgi::intersects(
|
||||
rtree_segment_t(rtree_point_t(hook_forward.a.x(), hook_forward.a.y()), rtree_point_t(hook_forward.b.x(), hook_forward.b.y()))) &&
|
||||
bgi::satisfies(filter_itself),
|
||||
std::back_inserter(hook_intersections));
|
||||
|
||||
auto max_hook_length = [&hook_intersections, &hook_length](const Line &hook) {
|
||||
|
@ -669,8 +683,9 @@ static void add_hook(const Intersection &intersection, const Line &hook_line, co
|
|||
// There is not enough space for the hook, try another direction
|
||||
coord_t hook_forward_max_length = max_hook_length(hook_forward);
|
||||
hook_intersections.clear();
|
||||
rtree.query(bgi::intersects(rtree_segment_t(rtree_point_t(hook_backward_o.a.x(), hook_backward_o.a.y()),
|
||||
rtree_point_t(hook_backward_o.b.x(), hook_backward_o.b.y()))),
|
||||
rtree.query(bgi::intersects(rtree_segment_t(rtree_point_t(hook_backward.a.x(), hook_backward.a.y()),
|
||||
rtree_point_t(hook_backward.b.x(), hook_backward.b.y()))) &&
|
||||
bgi::satisfies(filter_itself),
|
||||
std::back_inserter(hook_intersections));
|
||||
|
||||
if (hook_intersections.empty()) {
|
||||
|
@ -709,7 +724,8 @@ static void connect_lines_using_hooks(Polylines &&lines, Polylines &polylines_ou
|
|||
|
||||
std::vector<Intersection> intersections;
|
||||
coord_t scaled_spacing = scale_(spacing);
|
||||
for (Polyline &line : lines) {
|
||||
for (size_t line_idx = 0; line_idx < lines.size(); ++line_idx) {
|
||||
Polyline &line = lines[line_idx];
|
||||
// Lines shorter than spacing are skipped because it is needed to shrink a line by the value of spacing.
|
||||
// A shorter line than spacing could produce a degenerate polyline.
|
||||
if (line.length() <= scaled_spacing) continue;
|
||||
|
@ -718,16 +734,18 @@ static void connect_lines_using_hooks(Polylines &&lines, Polylines &polylines_ou
|
|||
Point back_point = line.points.back();
|
||||
std::vector<std::pair<rtree_segment_t, size_t>> closest;
|
||||
|
||||
closest.reserve(2);
|
||||
rtree.query(bgi::nearest(rtree_point_t(front_point.x(), front_point.y()), 2), std::back_inserter(closest));
|
||||
auto filter_itself = [line_idx](const auto &item) { return item.second != line_idx; };
|
||||
|
||||
// Find the nearest line from the start point of the line.
|
||||
rtree.query(bgi::nearest(rtree_point_t(front_point.x(), front_point.y()), 1) && bgi::satisfies(filter_itself), std::back_inserter(closest));
|
||||
if (((Line) lines[closest[0].second]).distance_to(front_point) <= 1000)
|
||||
intersections.emplace_back(closest[0].second, (Line) lines[closest[0].second], front_point, &line - lines.data(), &line, (Line) line, true);
|
||||
intersections.emplace_back(closest[0].second, (Line) lines[closest[0].second], front_point, line_idx, &line, (Line) line, true);
|
||||
|
||||
closest.clear();
|
||||
closest.reserve(2);
|
||||
rtree.query(bgi::nearest(rtree_point_t(back_point.x(), back_point.y()), 2), std::back_inserter(closest));
|
||||
// Find the nearest line from the end point of the line
|
||||
rtree.query(bgi::nearest(rtree_point_t(back_point.x(), back_point.y()), 1) && bgi::satisfies(filter_itself), std::back_inserter(closest));
|
||||
if (((Line) lines[closest[0].second]).distance_to(back_point) <= 1000)
|
||||
intersections.emplace_back(closest[0].second, (Line) lines[closest[0].second], back_point, &line - lines.data(), &line, (Line) line, false);
|
||||
intersections.emplace_back(closest[0].second, (Line) lines[closest[0].second], back_point, line_idx, &line, (Line) line, false);
|
||||
}
|
||||
|
||||
std::sort(intersections.begin(), intersections.end(),
|
||||
|
@ -736,7 +754,7 @@ static void connect_lines_using_hooks(Polylines &&lines, Polylines &polylines_ou
|
|||
std::vector<size_t> merged_with(lines.size());
|
||||
std::iota(merged_with.begin(), merged_with.end(), 0);
|
||||
|
||||
// Appends the boundary polygon with all holes to rtee for detection if hooks not crossing the boundary
|
||||
// Appends the boundary polygon with all holes to rtree for detection if hooks not crossing the boundary
|
||||
for (const Line &line : boundary.contour.lines())
|
||||
rtree.insert(std::make_pair(rtree_segment_t(rtree_point_t(line.a.x(), line.a.y()), rtree_point_t(line.b.x(), line.b.y())), poly_idx++));
|
||||
for (const Polygon &polygon : boundary.holes)
|
||||
|
@ -760,19 +778,20 @@ static void connect_lines_using_hooks(Polylines &&lines, Polylines &polylines_ou
|
|||
for (size_t min_idx = 0; min_idx < intersections.size(); ++min_idx) {
|
||||
std::vector<std::pair<Intersection, double>> intersect_line;
|
||||
Matrix2d rotation = rotation_matrix_from_vector(intersections[min_idx].closest_line.vector());
|
||||
intersect_line.emplace_back(intersections[min_idx], (rotation * intersections[min_idx].closest_point.cast<double>()).x());
|
||||
|
||||
intersect_line.emplace_back(intersections[min_idx], (rotation * intersections[min_idx].intersect_point.cast<double>()).x());
|
||||
// All the nearest points on the same line are projected on this line. Because of it, it can easily find the nearest point
|
||||
for (size_t max_idx = min_idx + 1; max_idx < intersections.size(); ++max_idx) {
|
||||
if (intersections[min_idx].closest_line_idx == intersections[max_idx].closest_line_idx) {
|
||||
intersect_line.emplace_back(intersections[max_idx], (rotation * intersections[max_idx].closest_point.cast<double>()).x());
|
||||
if (intersections[min_idx].closest_line_idx != intersections[max_idx].closest_line_idx) break;
|
||||
|
||||
intersect_line.emplace_back(intersections[max_idx], (rotation * intersections[max_idx].intersect_point.cast<double>()).x());
|
||||
min_idx = max_idx;
|
||||
}
|
||||
}
|
||||
|
||||
assert(!intersect_line.empty());
|
||||
if (intersect_line.size() <= 1) {
|
||||
// On the adjacent line is only one intersection
|
||||
Intersection &first_i = intersect_line.front().first;
|
||||
if (first_i.used || first_i.intersect_pl->points.size() == 0) continue;
|
||||
if (first_i.used || first_i.intersect_pl->points.empty()) continue;
|
||||
|
||||
add_hook(first_i, first_i.closest_line, scale_(spacing), hook_length, rtree);
|
||||
first_i.used = true;
|
||||
|
@ -785,59 +804,65 @@ static void connect_lines_using_hooks(Polylines &&lines, Polylines &polylines_ou
|
|||
Intersection &first_i = intersect_line[first_idx].first;
|
||||
Intersection &nearest_i = *get_nearest_intersection(intersect_line, first_idx);
|
||||
|
||||
if (first_i.used || first_i.intersect_pl->points.size() == 0) continue;
|
||||
// The intersection has been processer or polyline has been merge to another polyline
|
||||
if (first_i.used || first_i.intersect_pl->points.empty()) continue;
|
||||
|
||||
// A line between two intersections points
|
||||
Line intersection_line(first_i.closest_point, nearest_i.closest_point);
|
||||
Line intersection_line(first_i.intersect_point, nearest_i.intersect_point);
|
||||
Line offset_line = create_offset_line(intersection_line, first_i, scale_(spacing));
|
||||
double intersection_line_length = intersection_line.length();
|
||||
|
||||
{
|
||||
// Update the polyline index to index which is merged
|
||||
nearest_i.intersect_pl_idx = get_merged_index(nearest_i.intersect_pl_idx);
|
||||
nearest_i.intersect_pl = &lines[nearest_i.intersect_pl_idx];
|
||||
|
||||
if (!nearest_i.used && nearest_i.intersect_pl->points.size() != 0)
|
||||
nearest_i.forward = (nearest_i.intersect_pl->points.front() == nearest_i.closest_point);
|
||||
}
|
||||
// The nearest intersection has been processer or polyline has been merge to another polyline
|
||||
if (!nearest_i.used && !nearest_i.intersect_pl->points.empty())
|
||||
nearest_i.forward = (nearest_i.intersect_pl->points.front() == nearest_i.intersect_point);
|
||||
|
||||
// Check if both intersections lie on the offset_line and simultaneously get their points of intersecting.
|
||||
// These points are used as start and end of the hook
|
||||
Point first_i_point, nearest_i_point;
|
||||
if (first_i.intersect_line.intersection(offset_line, &first_i_point) &&
|
||||
nearest_i.intersect_line.intersection(offset_line, &nearest_i_point)) {
|
||||
if (!nearest_i.used && nearest_i.intersect_pl->points.size() != 0 && intersection_line_length <= 2 * hook_length) {
|
||||
// Both intersections are so close that their polylines can be connected
|
||||
if (!nearest_i.used && !nearest_i.intersect_pl->points.empty() && intersection_line_length <= 2 * hook_length) {
|
||||
if (first_i.intersect_pl_idx == nearest_i.intersect_pl_idx) {
|
||||
// Both intersections are on the same polyline
|
||||
if (!first_i.forward) { std::swap(first_i_point, nearest_i_point); }
|
||||
|
||||
first_i.intersect_pl->points.front() = first_i_point;
|
||||
first_i.intersect_pl->points.back() = nearest_i_point;
|
||||
first_i.intersect_pl->points.emplace(first_i.intersect_pl->points.begin(), nearest_i_point);
|
||||
} else {
|
||||
// Both intersections are on different polylines
|
||||
Points merge_polyline_points;
|
||||
size_t first_polyline_lenght = first_i.intersect_pl->points.size();
|
||||
size_t short_polyline_lenght = nearest_i.intersect_pl->points.size();
|
||||
merge_polyline_points.reserve(first_polyline_lenght + short_polyline_lenght);
|
||||
size_t first_polyline_size = first_i.intersect_pl->points.size();
|
||||
size_t nearest_polyline_size = nearest_i.intersect_pl->points.size();
|
||||
merge_polyline_points.reserve(first_polyline_size + nearest_polyline_size);
|
||||
|
||||
if (first_i.forward) {
|
||||
if (nearest_i.forward)
|
||||
for (auto it = nearest_i.intersect_pl->points.rbegin(); it != nearest_i.intersect_pl->points.rend(); ++it)
|
||||
merge_polyline_points.emplace_back(*it);
|
||||
else
|
||||
for (auto it = nearest_i.intersect_pl->points.begin(); it != nearest_i.intersect_pl->points.end(); ++it)
|
||||
merge_polyline_points.emplace_back(*it);
|
||||
for (const Point &point : nearest_i.intersect_pl->points)
|
||||
merge_polyline_points.emplace_back(point);
|
||||
|
||||
append(merge_polyline_points, std::move(first_i.intersect_pl->points));
|
||||
merge_polyline_points[short_polyline_lenght - 1] = nearest_i_point;
|
||||
merge_polyline_points[short_polyline_lenght] = first_i_point;
|
||||
merge_polyline_points[nearest_polyline_size - 1] = nearest_i_point;
|
||||
merge_polyline_points[nearest_polyline_size] = first_i_point;
|
||||
} else {
|
||||
append(merge_polyline_points, std::move(first_i.intersect_pl->points));
|
||||
if (nearest_i.forward)
|
||||
for (auto it = nearest_i.intersect_pl->points.begin(); it != nearest_i.intersect_pl->points.end(); ++it)
|
||||
merge_polyline_points.emplace_back(*it);
|
||||
for (const Point &point : nearest_i.intersect_pl->points)
|
||||
merge_polyline_points.emplace_back(point);
|
||||
else
|
||||
for (auto it = nearest_i.intersect_pl->points.rbegin(); it != nearest_i.intersect_pl->points.rend(); ++it)
|
||||
merge_polyline_points.emplace_back(*it);
|
||||
|
||||
merge_polyline_points[first_polyline_lenght - 1] = first_i_point;
|
||||
merge_polyline_points[first_polyline_lenght] = nearest_i_point;
|
||||
merge_polyline_points[first_polyline_size - 1] = first_i_point;
|
||||
merge_polyline_points[first_polyline_size] = nearest_i_point;
|
||||
}
|
||||
|
||||
merged_with[nearest_i.intersect_pl_idx] = merged_with[first_i.intersect_pl_idx];
|
||||
|
|
Loading…
Reference in a new issue