diff --git a/src/libslic3r/Fill/Lightning/DistanceField.cpp b/src/libslic3r/Fill/Lightning/DistanceField.cpp index 3602e60ab..ef407664c 100644 --- a/src/libslic3r/Fill/Lightning/DistanceField.cpp +++ b/src/libslic3r/Fill/Lightning/DistanceField.cpp @@ -5,6 +5,8 @@ #include "../FillRectilinear.hpp" #include "../../ClipperUtils.hpp" +#include + 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(); m_unsupported_points.resize(unsupported_points_prev_size + sampled_points.size()); - for (size_t sp_idx = 0; sp_idx < sampled_points.size(); ++sp_idx) { - const Point &sp = sampled_points[sp_idx]; - // Find a squared distance to the source expolygon boundary. - double d2 = std::numeric_limits::max(); - for (size_t icontour = 0; icontour <= expoly.holes.size(); ++icontour) { - const Polygon &contour = icontour == 0 ? expoly.contour : expoly.holes[icontour - 1]; - if (contour.size() > 2) { - Point prev = contour.points.back(); - for (const Point &p2 : contour.points) { - d2 = std::min(d2, Line::distance_to_squared(sp, prev, p2)); - prev = p2; + tbb::parallel_for(tbb::blocked_range(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 &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::max(); + for (size_t icontour = 0; icontour <= expoly.holes.size(); ++icontour) { + const Polygon &contour = icontour == 0 ? expoly.contour : expoly.holes[icontour - 1]; + if (contour.size() > 2) { + Point prev = contour.points.back(); + for (const Point &p2 : contour.points) { + 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))}; - assert(m_unsupported_points_bbox.contains(p)); - } + }); // 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; diff --git a/src/libslic3r/Fill/Lightning/Layer.cpp b/src/libslic3r/Fill/Lightning/Layer.cpp index 8539bb532..0bd2a65c4 100644 --- a/src/libslic3r/Fill/Lightning/Layer.cpp +++ b/src/libslic3r/Fill/Lightning/Layer.cpp @@ -10,6 +10,10 @@ #include "../../Geometry.hpp" #include "Utils.hpp" +#include +#include +#include + namespace Slic3r::FillLightning { 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.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}); - 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; + Point current_dist_grid_addr{std::numeric_limits::lowest(), std::numeric_limits::lowest()}; + std::mutex current_dist_mutex; + tbb::parallel_for(tbb::blocked_range2d(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 &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 < 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 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 ?