Parallelized DistanceField::DistanceField() and Layer::getBestGroundingLocation() in Lightning infill.

This commit is contained in:
Lukáš Hejl 2022-05-19 12:47:25 +02:00
parent 95041751a1
commit 4bde35cae3
2 changed files with 57 additions and 26 deletions

View File

@ -5,6 +5,8 @@
#include "../FillRectilinear.hpp"
#include "../../ClipperUtils.hpp"
#include <tbb/parallel_for.h>
namespace Slic3r::FillLightning
{
@ -22,7 +24,8 @@ DistanceField::DistanceField(const coord_t& radius, const Polygons& current_outl
const size_t unsupported_points_prev_size = m_unsupported_points.size();
m_unsupported_points.resize(unsupported_points_prev_size + sampled_points.size());
for (size_t sp_idx = 0; sp_idx < sampled_points.size(); ++sp_idx) {
tbb::parallel_for(tbb::blocked_range<size_t>(0, sampled_points.size()), [&self = *this, &expoly = std::as_const(expoly), &sampled_points = std::as_const(sampled_points), &unsupported_points_prev_size = std::as_const(unsupported_points_prev_size)](const tbb::blocked_range<size_t> &range) -> void {
for (size_t sp_idx = range.begin(); sp_idx < range.end(); ++sp_idx) {
const Point &sp = sampled_points[sp_idx];
// Find a squared distance to the source expolygon boundary.
double d2 = std::numeric_limits<double>::max();
@ -36,9 +39,10 @@ DistanceField::DistanceField(const coord_t& radius, const Polygons& current_outl
}
}
}
m_unsupported_points[unsupported_points_prev_size + sp_idx] = {sp, coord_t(std::sqrt(d2))};
assert(m_unsupported_points_bbox.contains(p));
self.m_unsupported_points[unsupported_points_prev_size + sp_idx] = {sp, coord_t(std::sqrt(d2))};
assert(self.m_unsupported_points_bbox.contains(sp));
}
}); // end of parallel_for
}
std::stable_sort(m_unsupported_points.begin(), m_unsupported_points.end(), [&radius](const UnsupportedCell &a, const UnsupportedCell &b) {
constexpr coord_t prime_for_hash = 191;

View File

@ -10,6 +10,10 @@
#include "../../Geometry.hpp"
#include "Utils.hpp"
#include <tbb/parallel_for.h>
#include <tbb/blocked_range2d.h>
#include <mutex>
namespace Slic3r::FillLightning {
coord_t Layer::getWeightedDistance(const Point& boundary_loc, const Point& unsupported_location)
@ -150,22 +154,45 @@ GroundingLocation Layer::getBestGroundingLocation
region.min = to_grid_point(region.min, current_outlines_bbox);
region.max = to_grid_point(region.max, current_outlines_bbox);
for (coord_t grid_addr_y = region.min.y(); grid_addr_y < region.max.y(); ++grid_addr_y)
for (coord_t grid_addr_x = region.min.x(); grid_addr_x < region.max.x(); ++grid_addr_x) {
const auto it_range = tree_node_locator.equal_range({grid_addr_x, grid_addr_y});
Point current_dist_grid_addr{std::numeric_limits<coord_t>::lowest(), std::numeric_limits<coord_t>::lowest()};
std::mutex current_dist_mutex;
tbb::parallel_for(tbb::blocked_range2d<coord_t>(region.min.y(), region.max.y(), region.min.x(), region.max.x()), [&current_dist, current_dist_copy = current_dist, &current_dist_mutex, &sub_tree, &current_dist_grid_addr, &exclude_tree = std::as_const(exclude_tree), &outline_locator = std::as_const(outline_locator), &supporting_radius = std::as_const(supporting_radius), &tree_node_locator = std::as_const(tree_node_locator), &unsupported_location = std::as_const(unsupported_location)](const tbb::blocked_range2d<coord_t> &range) -> void {
for (coord_t grid_addr_y = range.rows().begin(); grid_addr_y < range.rows().end(); ++grid_addr_y)
for (coord_t grid_addr_x = range.cols().begin(); grid_addr_x < range.cols().end(); ++grid_addr_x) {
const Point local_grid_addr{grid_addr_x, grid_addr_y};
NodeSPtr local_sub_tree{nullptr};
coord_t local_current_dist = current_dist_copy;
const auto it_range = tree_node_locator.equal_range(local_grid_addr);
for (auto it = it_range.first; it != it_range.second; ++it) {
const NodeSPtr candidate_sub_tree = it->second.lock();
if ((candidate_sub_tree && candidate_sub_tree != exclude_tree) &&
!(exclude_tree && exclude_tree->hasOffspring(candidate_sub_tree)) &&
!polygonCollidesWithLineSegment(unsupported_location, candidate_sub_tree->getLocation(), outline_locator)) {
if (const coord_t candidate_dist = candidate_sub_tree->getWeightedDistance(unsupported_location, supporting_radius); candidate_dist < current_dist) {
current_dist = candidate_dist;
sub_tree = candidate_sub_tree;
if (const coord_t candidate_dist = candidate_sub_tree->getWeightedDistance(unsupported_location, supporting_radius); candidate_dist < local_current_dist) {
local_current_dist = candidate_dist;
local_sub_tree = candidate_sub_tree;
}
}
}
// To always get the same result in a parallel version as in a non-parallel version,
// we need to preserve that for the same current_dist, we select the same sub_tree
// as in the non-parallel version. For this purpose, inside the variable
// current_dist_grid_addr is stored from with 2D grid position assigned sub_tree comes.
// And when there are two sub_tree with the same current_dist, one which will be found
// the first in the non-parallel version is selected.
{
std::lock_guard<std::mutex> lock(current_dist_mutex);
if (local_current_dist < current_dist ||
(local_current_dist == current_dist && (grid_addr_y < current_dist_grid_addr.y() ||
(grid_addr_y == current_dist_grid_addr.y() && grid_addr_x < current_dist_grid_addr.x())))) {
current_dist = local_current_dist;
sub_tree = local_sub_tree;
current_dist_grid_addr = local_grid_addr;
}
}
}
}); // end of parallel_for
}
return ! sub_tree ?
GroundingLocation{ nullptr, node_location } :