Optimized for reduced memory allocation and clarity.

This commit is contained in:
Vojtech Bubnik 2020-10-20 10:55:10 +02:00
parent 3e50699576
commit 50b603df5d

View File

@ -556,10 +556,9 @@ static void export_infill_lines_to_svg(const ExPolygon &expoly, const Polylines
static Matrix2d rotation_matrix_from_vector(const Point &vector) static Matrix2d rotation_matrix_from_vector(const Point &vector)
{ {
Matrix2d rotation; Matrix2d rotation;
rotation.block<1, 2>(0, 0) = vector.cast<double>() / vector.cast<double>().norm(); rotation.block<1, 2>(0, 0) = vector.cast<double>().normalized();
rotation(1, 0) = -rotation(0, 1); rotation(1, 0) = -rotation(0, 1);
rotation(1, 1) = rotation(0, 0); rotation(1, 1) = rotation(0, 0);
return rotation; return rotation;
} }
@ -638,6 +637,13 @@ using rtree_point_t = bgm::point<float, 2, boost::geometry::cs::cartesian>;
using rtree_segment_t = bgm::segment<rtree_point_t>; 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>>; using rtree_t = bgi::rtree<std::pair<rtree_segment_t, size_t>, bgi::rstar<16, 4>>;
static inline rtree_segment_t mk_rtree_seg(const Point &a, const Point &b) {
return { rtree_point_t(float(a.x()), float(a.y())), rtree_point_t(float(b.x()), float(b.y())) };
}
static inline rtree_segment_t mk_rtree_seg(const Line &l) {
return mk_rtree_seg(l.a, l.b);
}
// Create a hook based on hook_line and append it to the begin or end of the polyline in the intersection // 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) static void add_hook(const Intersection &intersection, const Line &hook_line, const double scaled_spacing, const int hook_length, const rtree_t &rtree)
{ {
@ -660,9 +666,7 @@ static void add_hook(const Intersection &intersection, const Line &hook_line, co
}; };
std::vector<std::pair<rtree_segment_t, size_t>> hook_intersections; std::vector<std::pair<rtree_segment_t, size_t>> hook_intersections;
rtree.query(bgi::intersects(rtree_segment_t(rtree_point_t(float(hook_forward.a.x()), float(hook_forward.a.y())), rtree.query(bgi::intersects(mk_rtree_seg(hook_forward)) && bgi::satisfies(filter_itself),
rtree_point_t(float(hook_forward.b.x()), float(hook_forward.b.y())))) &&
bgi::satisfies(filter_itself),
std::back_inserter(hook_intersections)); std::back_inserter(hook_intersections));
auto max_hook_length = [&hook_intersections, &hook_length](const Line &hook) { auto max_hook_length = [&hook_intersections, &hook_length](const Line &hook) {
@ -683,9 +687,7 @@ static void add_hook(const Intersection &intersection, const Line &hook_line, co
// There is not enough space for the hook, try another direction // There is not enough space for the hook, try another direction
coord_t hook_forward_max_length = max_hook_length(hook_forward); coord_t hook_forward_max_length = max_hook_length(hook_forward);
hook_intersections.clear(); hook_intersections.clear();
rtree.query(bgi::intersects(rtree_segment_t(rtree_point_t(float(hook_backward.a.x()), float(hook_backward.a.y())), rtree.query(bgi::intersects(mk_rtree_seg(hook_backward)) && bgi::satisfies(filter_itself),
rtree_point_t(float(hook_backward.b.x()), float(hook_backward.b.y())))) &&
bgi::satisfies(filter_itself),
std::back_inserter(hook_intersections)); std::back_inserter(hook_intersections));
if (hook_intersections.empty()) { if (hook_intersections.empty()) {
@ -712,40 +714,42 @@ static void add_hook(const Intersection &intersection, const Line &hook_line, co
} }
} }
static void connect_lines_using_hooks(Polylines &&lines, Polylines &polylines_out, const ExPolygon &boundary, const double spacing, const int hook_length) static Polylines connect_lines_using_hooks(Polylines &&lines, const ExPolygon &boundary, const double spacing, const int hook_length)
{ {
rtree_t rtree; rtree_t rtree;
size_t poly_idx = 0; size_t poly_idx = 0;
for (const Polyline &poly : lines) { for (const Polyline &poly : lines) {
rtree.insert(std::make_pair(rtree_segment_t(rtree_point_t(float(poly.points.front().x()), float(poly.points.front().y())), rtree.insert(std::make_pair(mk_rtree_seg(poly.points.front(), poly.points.back()), poly_idx++));
rtree_point_t(float(poly.points.back().x()), float(poly.points.back().y()))),
poly_idx++));
} }
std::vector<Intersection> intersections; std::vector<Intersection> intersections;
coord_t scaled_spacing = coord_t(scale_(spacing)); {
for (size_t line_idx = 0; line_idx < lines.size(); ++line_idx) { const coord_t scaled_spacing = coord_t(scale_(spacing));
Polyline &line = lines[line_idx]; // Keeping the vector of closest points outside the loop, so the vector does not need to be reallocated.
// 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 + SCALED_EPSILON)) continue;
Point front_point = line.points.front();
Point back_point = line.points.back();
std::vector<std::pair<rtree_segment_t, size_t>> closest; std::vector<std::pair<rtree_segment_t, size_t>> closest;
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 + SCALED_EPSILON)) continue;
auto filter_itself = [line_idx](const auto &item) { return item.second != line_idx; }; Point front_point = line.points.front();
Point back_point = line.points.back();
// Find the nearest line from the start point of the line. auto filter_itself = [line_idx](const auto &item) { return item.second != line_idx; };
rtree.query(bgi::nearest(rtree_point_t(float(front_point.x()), float(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_idx, &line, (Line) line, true);
closest.clear(); // Find the nearest line from the start point of the line.
// Find the nearest line from the end point of the line closest.clear();
rtree.query(bgi::nearest(rtree_point_t(float(back_point.x()), float(back_point.y())), 1) && bgi::satisfies(filter_itself), std::back_inserter(closest)); rtree.query(bgi::nearest(rtree_point_t(float(front_point.x()), float(front_point.y())), 1) && bgi::satisfies(filter_itself), std::back_inserter(closest));
if (((Line) lines[closest[0].second]).distance_to(back_point) <= 1000) if (((Line) lines[closest[0].second]).distance_to(front_point) <= 1000)
intersections.emplace_back(closest[0].second, (Line) lines[closest[0].second], back_point, line_idx, &line, (Line) line, false); intersections.emplace_back(closest[0].second, (Line) lines[closest[0].second], front_point, line_idx, &line, (Line) line, true);
// Find the nearest line from the end point of the line
closest.clear();
rtree.query(bgi::nearest(rtree_point_t(float(back_point.x()), float(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_idx, &line, (Line) line, false);
}
} }
std::sort(intersections.begin(), intersections.end(), std::sort(intersections.begin(), intersections.end(),
@ -755,15 +759,20 @@ static void connect_lines_using_hooks(Polylines &&lines, Polylines &polylines_ou
std::iota(merged_with.begin(), merged_with.end(), 0); std::iota(merged_with.begin(), merged_with.end(), 0);
// Appends the boundary polygon with all holes to rtree 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( Point prev = boundary.contour.points.back();
std::make_pair(rtree_segment_t(rtree_point_t(float(line.a.x()), float(line.a.y())), rtree_point_t(float(line.b.x()), float(line.b.y()))), for (const Point &point : boundary.contour.points) {
poly_idx++)); rtree.insert(std::make_pair(mk_rtree_seg(prev, point), poly_idx++));
for (const Polygon &polygon : boundary.holes) prev = point;
for (const Line &line : polygon.lines()) }
rtree.insert(std::make_pair(rtree_segment_t(rtree_point_t(float(line.a.x()), float(line.a.y())), for (const Polygon &polygon : boundary.holes) {
rtree_point_t(float(line.b.x()), float(line.b.y()))), Point prev = polygon.points.back();
poly_idx++)); for (const Point &point : polygon.points) {
rtree.insert(std::make_pair(mk_rtree_seg(prev, point), poly_idx++));
prev = point;
}
}
}
auto update_merged_polyline = [&lines, &merged_with](Intersection &intersection) { auto update_merged_polyline = [&lines, &merged_with](Intersection &intersection) {
// Update the polyline index to index which is merged // Update the polyline index to index which is merged
@ -884,9 +893,11 @@ static void connect_lines_using_hooks(Polylines &&lines, Polylines &polylines_ou
} }
} }
Polylines polylines_out;
polylines_out.reserve(polylines_out.size() + std::count_if(lines.begin(), lines.end(), [](const Polyline &pl) { return !pl.empty(); })); polylines_out.reserve(polylines_out.size() + std::count_if(lines.begin(), lines.end(), [](const Polyline &pl) { return !pl.empty(); }));
for (Polyline &pl : lines) for (Polyline &pl : lines)
if (!pl.empty()) polylines_out.emplace_back(std::move(pl)); if (!pl.empty()) polylines_out.emplace_back(std::move(pl));
return polylines_out;
} }
coord_t get_hook_length(const double spacing) { return coord_t(scale_(spacing)) * 5; } coord_t get_hook_length(const double spacing) { return coord_t(scale_(spacing)) * 5; }
@ -937,8 +948,11 @@ void Filler::_fill_surface_single(
all_polylines = intersection_pl(std::move(all_polylines), to_polygons(expolygon)); all_polylines = intersection_pl(std::move(all_polylines), to_polygons(expolygon));
// After intersection_pl some polylines with only one line are split into more lines // After intersection_pl some polylines with only one line are split into more lines
for (Polyline &polyline : all_polylines) for (Polyline &polyline : all_polylines) {
if (polyline.points.size() > 2) polyline = Polyline(polyline.points.front(), polyline.points.back()); //FIXME assert that all the points are collinear and in between the start and end point.
if (polyline.points.size() > 2)
polyline.points.erase(polyline.points.begin() + 1, polyline.points.end() - 1);
}
#ifdef ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT #ifdef ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT
{ {
@ -948,8 +962,7 @@ void Filler::_fill_surface_single(
#endif /* ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT */ #endif /* ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT */
coord_t hook_length = get_hook_length(this->spacing); coord_t hook_length = get_hook_length(this->spacing);
Polylines all_polylines_with_hooks; Polylines all_polylines_with_hooks = connect_lines_using_hooks(std::move(all_polylines), expolygon, this->spacing, hook_length);
connect_lines_using_hooks(std::move(all_polylines), all_polylines_with_hooks, expolygon, this->spacing, hook_length);
#ifdef ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT #ifdef ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT
{ {