Parallelized DistanceField::DistanceField() and Layer::getBestGroundingLocation() in Lightning infill.
This commit is contained in:
parent
95041751a1
commit
4bde35cae3
@ -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,7 +24,8 @@ 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 {
|
||||||
|
for (size_t sp_idx = range.begin(); sp_idx < range.end(); ++sp_idx) {
|
||||||
const Point &sp = sampled_points[sp_idx];
|
const Point &sp = sampled_points[sp_idx];
|
||||||
// Find a squared distance to the source expolygon boundary.
|
// Find a squared distance to the source expolygon boundary.
|
||||||
double d2 = std::numeric_limits<double>::max();
|
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))};
|
self.m_unsupported_points[unsupported_points_prev_size + sp_idx] = {sp, coord_t(std::sqrt(d2))};
|
||||||
assert(m_unsupported_points_bbox.contains(p));
|
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) {
|
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;
|
||||||
|
@ -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,22 +154,45 @@ 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()), [¤t_dist, current_dist_copy = current_dist, ¤t_dist_mutex, &sub_tree, ¤t_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) {
|
for (auto it = it_range.first; it != it_range.second; ++it) {
|
||||||
const NodeSPtr candidate_sub_tree = it->second.lock();
|
const NodeSPtr candidate_sub_tree = it->second.lock();
|
||||||
if ((candidate_sub_tree && candidate_sub_tree != exclude_tree) &&
|
if ((candidate_sub_tree && candidate_sub_tree != exclude_tree) &&
|
||||||
!(exclude_tree && exclude_tree->hasOffspring(candidate_sub_tree)) &&
|
!(exclude_tree && exclude_tree->hasOffspring(candidate_sub_tree)) &&
|
||||||
!polygonCollidesWithLineSegment(unsupported_location, candidate_sub_tree->getLocation(), outline_locator)) {
|
!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) {
|
if (const coord_t candidate_dist = candidate_sub_tree->getWeightedDistance(unsupported_location, supporting_radius); candidate_dist < local_current_dist) {
|
||||||
current_dist = candidate_dist;
|
local_current_dist = candidate_dist;
|
||||||
sub_tree = candidate_sub_tree;
|
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 ?
|
||||||
GroundingLocation{ nullptr, node_location } :
|
GroundingLocation{ nullptr, node_location } :
|
||||||
|
Loading…
Reference in New Issue
Block a user