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 "../FillRectilinear.hpp"
#include "../../ClipperUtils.hpp" #include "../../ClipperUtils.hpp"
#include <tbb/parallel_for.h>
namespace Slic3r::FillLightning namespace Slic3r::FillLightning
{ {
@ -22,23 +24,25 @@ DistanceField::DistanceField(const coord_t& radius, const Polygons& current_outl
const size_t unsupported_points_prev_size = m_unsupported_points.size(); const size_t unsupported_points_prev_size = m_unsupported_points.size();
m_unsupported_points.resize(unsupported_points_prev_size + sampled_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 {
const Point &sp = sampled_points[sp_idx]; for (size_t sp_idx = range.begin(); sp_idx < range.end(); ++sp_idx) {
// Find a squared distance to the source expolygon boundary. const Point &sp = sampled_points[sp_idx];
double d2 = std::numeric_limits<double>::max(); // Find a squared distance to the source expolygon boundary.
for (size_t icontour = 0; icontour <= expoly.holes.size(); ++icontour) { double d2 = std::numeric_limits<double>::max();
const Polygon &contour = icontour == 0 ? expoly.contour : expoly.holes[icontour - 1]; for (size_t icontour = 0; icontour <= expoly.holes.size(); ++icontour) {
if (contour.size() > 2) { const Polygon &contour = icontour == 0 ? expoly.contour : expoly.holes[icontour - 1];
Point prev = contour.points.back(); if (contour.size() > 2) {
for (const Point &p2 : contour.points) { Point prev = contour.points.back();
d2 = std::min(d2, Line::distance_to_squared(sp, prev, p2)); for (const Point &p2 : contour.points) {
prev = p2; d2 = std::min(d2, Line::distance_to_squared(sp, prev, p2));
prev = p2;
}
} }
} }
self.m_unsupported_points[unsupported_points_prev_size + sp_idx] = {sp, coord_t(std::sqrt(d2))};
assert(self.m_unsupported_points_bbox.contains(sp));
} }
m_unsupported_points[unsupported_points_prev_size + sp_idx] = {sp, coord_t(std::sqrt(d2))}; }); // end of parallel_for
assert(m_unsupported_points_bbox.contains(p));
}
} }
std::stable_sort(m_unsupported_points.begin(), m_unsupported_points.end(), [&radius](const UnsupportedCell &a, const UnsupportedCell &b) { 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; constexpr coord_t prime_for_hash = 191;

View File

@ -10,6 +10,10 @@
#include "../../Geometry.hpp" #include "../../Geometry.hpp"
#include "Utils.hpp" #include "Utils.hpp"
#include <tbb/parallel_for.h>
#include <tbb/blocked_range2d.h>
#include <mutex>
namespace Slic3r::FillLightning { namespace Slic3r::FillLightning {
coord_t Layer::getWeightedDistance(const Point& boundary_loc, const Point& unsupported_location) coord_t Layer::getWeightedDistance(const Point& boundary_loc, const Point& unsupported_location)
@ -150,21 +154,44 @@ GroundingLocation Layer::getBestGroundingLocation
region.min = to_grid_point(region.min, current_outlines_bbox); region.min = to_grid_point(region.min, current_outlines_bbox);
region.max = to_grid_point(region.max, 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) Point current_dist_grid_addr{std::numeric_limits<coord_t>::lowest(), std::numeric_limits<coord_t>::lowest()};
for (coord_t grid_addr_x = region.min.x(); grid_addr_x < region.max.x(); ++grid_addr_x) { std::mutex current_dist_mutex;
const auto it_range = tree_node_locator.equal_range({grid_addr_x, grid_addr_y}); 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 (auto it = it_range.first; it != it_range.second; ++it) { for (coord_t grid_addr_y = range.rows().begin(); grid_addr_y < range.rows().end(); ++grid_addr_y)
const NodeSPtr candidate_sub_tree = it->second.lock(); for (coord_t grid_addr_x = range.cols().begin(); grid_addr_x < range.cols().end(); ++grid_addr_x) {
if ((candidate_sub_tree && candidate_sub_tree != exclude_tree) && const Point local_grid_addr{grid_addr_x, grid_addr_y};
!(exclude_tree && exclude_tree->hasOffspring(candidate_sub_tree)) && NodeSPtr local_sub_tree{nullptr};
!polygonCollidesWithLineSegment(unsupported_location, candidate_sub_tree->getLocation(), outline_locator)) { coord_t local_current_dist = current_dist_copy;
if (const coord_t candidate_dist = candidate_sub_tree->getWeightedDistance(unsupported_location, supporting_radius); candidate_dist < current_dist) { const auto it_range = tree_node_locator.equal_range(local_grid_addr);
current_dist = candidate_dist; for (auto it = it_range.first; it != it_range.second; ++it) {
sub_tree = candidate_sub_tree; 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 < 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 ? return ! sub_tree ?