WIP Tree Supports: Ported parallelization from cura homebrew parallel_for

to thread building blocks tbb::parallel_for.
This commit is contained in:
Vojtech Bubnik 2022-07-19 17:14:07 +02:00
parent f6ae93366a
commit 6e1e4fcca2
3 changed files with 1066 additions and 1044 deletions

View File

@ -9,6 +9,9 @@
#include "TreeModelVolumes.hpp" #include "TreeModelVolumes.hpp"
#include "TreeSupport.hpp" #include "TreeSupport.hpp"
#include <tbb/parallel_for.h>
#include <tbb/task_group.h>
namespace Slic3r namespace Slic3r
{ {
@ -71,20 +74,22 @@ TreeModelVolumes::TreeModelVolumes(const SliceDataStorage& storage, const coord_
{ {
SliceMeshStorage mesh = storage.meshes[mesh_idx]; SliceMeshStorage mesh = storage.meshes[mesh_idx];
cura::parallel_for<LayerIndex>(0, LayerIndex(layer_outlines_[mesh_to_layeroutline_idx[mesh_idx]].second.size()), 1, tbb::parallel_for(tbb::blocked_range<size_t>(0, layer_outlines_[mesh_to_layeroutline_idx[mesh_idx]].second.size()),
[&](const LayerIndex layer_idx) [&](const tbb::blocked_range<size_t> &range) {
{ for (const size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) {
if (mesh.layer_nr_max_filled_layer < layer_idx) if (mesh.layer_nr_max_filled_layer < layer_idx)
{ {
return; // cant break as parallel_for wont allow it, this is equivalent to a continue return; // cant break as parallel_for wont allow it, this is equivalent to a continue
} }
Polygons outline = extractOutlineFromMesh(mesh, layer_idx); Polygons outline = extractOutlineFromMesh(mesh, layer_idx);
layer_outlines_[mesh_to_layeroutline_idx[mesh_idx]].second[layer_idx].add(outline); layer_outlines_[mesh_to_layeroutline_idx[mesh_idx]].second[layer_idx].add(outline);
}
}); });
} }
cura::parallel_for<LayerIndex>(0, LayerIndex(anti_overhang_.size()), 1,
[&](const LayerIndex layer_idx) tbb::parallel_for(tbb::blocked_range<size_t>(0, anti_overhang_.size()),
{ [&](const tbb::blocked_range<size_t> &range) {
for (const size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) {
if (layer_idx < coord_t(additional_excluded_areas.size())) if (layer_idx < coord_t(additional_excluded_areas.size()))
{ {
anti_overhang_[layer_idx].add(additional_excluded_areas[layer_idx]); anti_overhang_[layer_idx].add(additional_excluded_areas[layer_idx]);
@ -100,11 +105,16 @@ TreeModelVolumes::TreeModelVolumes(const SliceDataStorage& storage, const coord_
anti_overhang_[layer_idx].add(layer_idx == 0 ? storage.primeTower.outer_poly_first_layer : storage.primeTower.outer_poly); anti_overhang_[layer_idx].add(layer_idx == 0 ? storage.primeTower.outer_poly_first_layer : storage.primeTower.outer_poly);
} }
anti_overhang_[layer_idx] = anti_overhang_[layer_idx].unionPolygons(); anti_overhang_[layer_idx] = anti_overhang_[layer_idx].unionPolygons();
}
}); });
for (size_t idx = 0; idx < layer_outlines_.size(); idx++) for (size_t idx = 0; idx < layer_outlines_.size(); idx++)
{ {
cura::parallel_for<LayerIndex>(0, LayerIndex(anti_overhang_.size()), 1, [&](const LayerIndex layer_idx) { layer_outlines_[idx].second[layer_idx] = layer_outlines_[idx].second[layer_idx].unionPolygons(); }); tbb::parallel_for(tbb::blocked_range<size_t>(0, anti_overhang_.size()),
[&](const tbb::blocked_range<size_t> &range) {
for (const size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx)
layer_outlines_[idx].second[layer_idx] = layer_outlines_[idx].second[layer_idx].unionPolygons();
});
} }
radius_0 = config.getRadius(0); radius_0 = config.getRadius(0);
} }
@ -199,21 +209,15 @@ void TreeModelVolumes::precalculate(coord_t max_layer)
// ### Calculate the relevant avoidances in parallel as far as possible // ### Calculate the relevant avoidances in parallel as far as possible
{ {
std::future<void> placeable_waiter; tbb::task_group task_group;
task_group.run([this, relevant_avoidance_radiis]{ calculateAvoidance(relevant_avoidance_radiis); });
task_group.run([this, relevant_avoidance_radiis]{ calculateWallRestrictions(relevant_avoidance_radiis); });
if (support_rests_on_model) if (support_rests_on_model)
{ task_group.run([this, relevant_avoidance_radiis_to_model]{
placeable_waiter = calculatePlaceables(relevant_avoidance_radiis_to_model); calculatePlaceables(relevant_avoidance_radiis_to_model);
} calculateAvoidanceToModel(relevant_avoidance_radiis_to_model);
std::future<void> avoidance_waiter = calculateAvoidance(relevant_avoidance_radiis); });
std::future<void> wall_restriction_waiter = calculateWallRestrictions(relevant_avoidance_radiis); task_group.wait();
if (support_rests_on_model)
{
placeable_waiter.wait();
std::future<void> avoidance_model_waiter = calculateAvoidanceToModel(relevant_avoidance_radiis_to_model);
avoidance_model_waiter.wait();
}
avoidance_waiter.wait();
wall_restriction_waiter.wait();
} }
auto t_end = std::chrono::high_resolution_clock::now(); auto t_end = std::chrono::high_resolution_clock::now();
auto dur_col = 0.001 * std::chrono::duration_cast<std::chrono::microseconds>(t_coll - t_start).count(); auto dur_col = 0.001 * std::chrono::duration_cast<std::chrono::microseconds>(t_coll - t_start).count();
@ -549,9 +553,9 @@ LayerIndex TreeModelVolumes::getMaxCalculatedLayer(coord_t radius, const std::un
void TreeModelVolumes::calculateCollision(std::deque<RadiusLayerPair> keys) void TreeModelVolumes::calculateCollision(std::deque<RadiusLayerPair> keys)
{ {
cura::parallel_for<size_t>(0, keys.size(), 1, tbb::parallel_for(tbb::blocked_range<size_t>(0, keys.size()),
[&](const size_t i) [&](const tbb::blocked_range<size_t> &range) {
{ for (const size_t i = range.begin(); i < range.end(); ++ i) {
coord_t radius = keys[i].first; coord_t radius = keys[i].first;
RadiusLayerPair key(radius, 0); RadiusLayerPair key(radius, 0);
std::unordered_map<RadiusLayerPair, Polygons> data_outer; std::unordered_map<RadiusLayerPair, Polygons> data_outer;
@ -680,6 +684,7 @@ void TreeModelVolumes::calculateCollision(std::deque<RadiusLayerPair> keys)
placeable_areas_cache_.insert(data_placeable_outer.begin(), data_placeable_outer.end()); placeable_areas_cache_.insert(data_placeable_outer.begin(), data_placeable_outer.end());
} }
} }
}
}); });
} }
void TreeModelVolumes::calculateCollisionHolefree(std::deque<RadiusLayerPair> keys) void TreeModelVolumes::calculateCollisionHolefree(std::deque<RadiusLayerPair> keys)
@ -690,9 +695,9 @@ void TreeModelVolumes::calculateCollisionHolefree(std::deque<RadiusLayerPair> ke
max_layer = std::max(max_layer, keys[i].second); max_layer = std::max(max_layer, keys[i].second);
} }
cura::parallel_for<LayerIndex>(0, max_layer + 1, 1, tbb::parallel_for(tbb::blocked_range<size_t>(0, max_layer + 1),
[&](const LayerIndex layer_idx) [&](const tbb::blocked_range<size_t> &range) {
{ for (const size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) {
std::unordered_map<RadiusLayerPair, Polygons> data; std::unordered_map<RadiusLayerPair, Polygons> data;
for (RadiusLayerPair key : keys) for (RadiusLayerPair key : keys)
{ {
@ -708,6 +713,7 @@ void TreeModelVolumes::calculateCollisionHolefree(std::deque<RadiusLayerPair> ke
std::lock_guard<std::mutex> critical_section(*critical_collision_cache_holefree_); std::lock_guard<std::mutex> critical_section(*critical_collision_cache_holefree_);
collision_cache_holefree_.insert(data.begin(), data.end()); collision_cache_holefree_.insert(data.begin(), data.end());
} }
}
}); });
} }
@ -728,13 +734,13 @@ Polygons TreeModelVolumes::safeOffset(const Polygons& me, coord_t distance, Clip
return ret.unionPolygons(collision); return ret.unionPolygons(collision);
} }
std::future<void> TreeModelVolumes::calculateAvoidance(std::deque<RadiusLayerPair> keys) void TreeModelVolumes::calculateAvoidance(std::deque<RadiusLayerPair> keys)
{ {
// For every RadiusLayer pair there are 3 avoidances that have to be calculate, calculated in the same paralell_for loop for better paralellisation. // For every RadiusLayer pair there are 3 avoidances that have to be calculate, calculated in the same paralell_for loop for better paralellisation.
const std::vector<AvoidanceType> all_types = { AvoidanceType::SLOW, AvoidanceType::FAST_SAFE, AvoidanceType::FAST }; const std::vector<AvoidanceType> all_types = { AvoidanceType::SLOW, AvoidanceType::FAST_SAFE, AvoidanceType::FAST };
std::future<void> ret = cura::parallel_for_nowait<size_t>(0, keys.size() * 3, 1, tbb::parallel_for(tbb::blocked_range<size_t>(0, keys.size() * 3),
[&, keys, all_types](const size_t iter_idx) [&, keys, all_types](const tbb::blocked_range<size_t> &range) {
{ for (const size_t iter_idx = range.begin(); iter_idx < range.end(); ++ iter_idx) {
size_t key_idx = iter_idx / 3; size_t key_idx = iter_idx / 3;
{ {
size_t type_idx = iter_idx % all_types.size(); size_t type_idx = iter_idx % all_types.size();
@ -804,15 +810,16 @@ std::future<void> TreeModelVolumes::calculateAvoidance(std::deque<RadiusLayerPai
(slow ? avoidance_cache_slow_ : holefree ? avoidance_cache_hole_ : avoidance_cache_).insert(data.begin(), data.end()); (slow ? avoidance_cache_slow_ : holefree ? avoidance_cache_hole_ : avoidance_cache_).insert(data.begin(), data.end());
} }
} }
}
}); });
return ret; return ret;
} }
std::future<void> TreeModelVolumes::calculatePlaceables(std::deque<RadiusLayerPair> keys) void TreeModelVolumes::calculatePlaceables(std::deque<RadiusLayerPair> keys)
{ {
std::future<void> ret = cura::parallel_for_nowait<size_t>(0, keys.size(), 1, tbb::parallel_for(tbb::blocked_range<size_t>(0, keys.size()),
[&, keys](const size_t key_idx) [&, keys](const tbb::blocked_range<size_t> &range) {
{ for (const size_t key_idx = range.begin(); key_idx < range.end(); ++ key_idx) {
const coord_t radius = keys[key_idx].first; const coord_t radius = keys[key_idx].first;
const LayerIndex max_required_layer = keys[key_idx].second; const LayerIndex max_required_layer = keys[key_idx].second;
std::vector<std::pair<RadiusLayerPair, Polygons>> data(max_required_layer + 1, std::pair<RadiusLayerPair, Polygons>(RadiusLayerPair(radius, -1), Polygons())); std::vector<std::pair<RadiusLayerPair, Polygons>> data(max_required_layer + 1, std::pair<RadiusLayerPair, Polygons>(RadiusLayerPair(radius, -1), Polygons()));
@ -859,18 +866,19 @@ std::future<void> TreeModelVolumes::calculatePlaceables(std::deque<RadiusLayerPa
std::lock_guard<std::mutex> critical_section(*critical_placeable_areas_cache_); std::lock_guard<std::mutex> critical_section(*critical_placeable_areas_cache_);
placeable_areas_cache_.insert(data.begin(), data.end()); placeable_areas_cache_.insert(data.begin(), data.end());
} }
}
}); });
return ret; return ret;
} }
std::future<void> TreeModelVolumes::calculateAvoidanceToModel(std::deque<RadiusLayerPair> keys) void TreeModelVolumes::calculateAvoidanceToModel(std::deque<RadiusLayerPair> keys)
{ {
// For every RadiusLayer pair there are 3 avoidances that have to be calculated, calculated in the same parallel_for loop for better parallelization. // For every RadiusLayer pair there are 3 avoidances that have to be calculated, calculated in the same parallel_for loop for better parallelization.
const std::vector<AvoidanceType> all_types = { AvoidanceType::SLOW, AvoidanceType::FAST_SAFE, AvoidanceType::FAST }; const std::vector<AvoidanceType> all_types = { AvoidanceType::SLOW, AvoidanceType::FAST_SAFE, AvoidanceType::FAST };
std::future<void> ret = cura::parallel_for_nowait<size_t>(0, keys.size() * 3, 1, tbb::parallel_for(tbb::blocked_range<size_t>(0, keys.size() * 3),
[&, keys, all_types](const size_t iter_idx) [&, keys, all_types](const tbb::blocked_range<size_t> &range) {
{ for (const size_t iter_idx = range.begin(); iter_idx < range.end(); ++ iter_idx) {
size_t key_idx = iter_idx / 3; size_t key_idx = iter_idx / 3;
size_t type_idx = iter_idx % all_types.size(); size_t type_idx = iter_idx % all_types.size();
AvoidanceType type = all_types[type_idx]; AvoidanceType type = all_types[type_idx];
@ -940,13 +948,14 @@ std::future<void> TreeModelVolumes::calculateAvoidanceToModel(std::deque<RadiusL
std::lock_guard<std::mutex> critical_section(*(slow ? critical_avoidance_cache_to_model_slow_ : holefree ? critical_avoidance_cache_holefree_to_model_ : critical_avoidance_cache_to_model_)); std::lock_guard<std::mutex> critical_section(*(slow ? critical_avoidance_cache_to_model_slow_ : holefree ? critical_avoidance_cache_holefree_to_model_ : critical_avoidance_cache_to_model_));
(slow ? avoidance_cache_to_model_slow_ : holefree ? avoidance_cache_hole_to_model_ : avoidance_cache_to_model_).insert(data.begin(), data.end()); (slow ? avoidance_cache_to_model_slow_ : holefree ? avoidance_cache_hole_to_model_ : avoidance_cache_to_model_).insert(data.begin(), data.end());
} }
}
}); });
return ret; return ret;
} }
std::future<void> TreeModelVolumes::calculateWallRestrictions(std::deque<RadiusLayerPair> keys) void TreeModelVolumes::calculateWallRestrictions(std::deque<RadiusLayerPair> keys)
{ {
// Wall restrictions are mainly important when they represent actual walls that are printed, and not "just" the configured z_distance, because technically valid placement is no excuse for moving through a wall. // Wall restrictions are mainly important when they represent actual walls that are printed, and not "just" the configured z_distance, because technically valid placement is no excuse for moving through a wall.
// As they exist to prevent accidentially moving though a wall at high speed between layers like thie (x = wall,i = influence area,o= empty space,d = blocked area because of z distance) Assume maximum movement distance is two characters and maximum safe movement distance of one character // As they exist to prevent accidentially moving though a wall at high speed between layers like thie (x = wall,i = influence area,o= empty space,d = blocked area because of z distance) Assume maximum movement distance is two characters and maximum safe movement distance of one character
@ -983,9 +992,9 @@ std::future<void> TreeModelVolumes::calculateWallRestrictions(std::deque<RadiusL
* layer z-1: ixiiiiiiiiiii * layer z-1: ixiiiiiiiiiii
*/ */
std::future<void> ret = cura::parallel_for_nowait<size_t>(0, keys.size(), 1, tbb::parallel_for(tbb::blocked_range<size_t>(0, keys.size()),
[&, keys](const size_t key_idx) [&, keys](const tbb::blocked_range<size_t> &range) {
{ for (const size_t key_idx = range.begin(); key_idx < range.end(); ++ key_idx) {
coord_t radius = keys[key_idx].first; coord_t radius = keys[key_idx].first;
RadiusLayerPair key(radius, 0); RadiusLayerPair key(radius, 0);
coord_t min_layer_bottom; coord_t min_layer_bottom;
@ -1025,6 +1034,7 @@ std::future<void> TreeModelVolumes::calculateWallRestrictions(std::deque<RadiusL
std::lock_guard<std::mutex> critical_section(*critical_wall_restrictions_cache_min_); std::lock_guard<std::mutex> critical_section(*critical_wall_restrictions_cache_min_);
wall_restrictions_cache_min_.insert(data_min.begin(), data_min.end()); wall_restrictions_cache_min_.insert(data_min.begin(), data_min.end());
} }
}
}); });
return ret; return ret;
} }

View File

@ -196,9 +196,8 @@ class TreeModelVolumes
* The result is a 2D area that would cause nodes of radius \p radius to * The result is a 2D area that would cause nodes of radius \p radius to
* collide with the model. Result is saved in the cache. * collide with the model. Result is saved in the cache.
* \param keys RadiusLayerPairs of all requested areas. Every radius will be calculated up to the provided layer. * \param keys RadiusLayerPairs of all requested areas. Every radius will be calculated up to the provided layer.
* \return A future that has to be waited on
*/ */
[[nodiscard]] std::future<void> calculateAvoidance(std::deque<RadiusLayerPair> keys); void calculateAvoidance(std::deque<RadiusLayerPair> keys);
/*! /*!
* \brief Creates the areas that have to be avoided by the tree's branches to prevent collision with the model. * \brief Creates the areas that have to be avoided by the tree's branches to prevent collision with the model.
@ -226,10 +225,8 @@ class TreeModelVolumes
* \brief Creates the areas where a branch of a given radius can be placed on the model. * \brief Creates the areas where a branch of a given radius can be placed on the model.
* Result is saved in the cache. * Result is saved in the cache.
* \param keys RadiusLayerPair of the requested areas. The radius will be calculated up to the provided layer. * \param keys RadiusLayerPair of the requested areas. The radius will be calculated up to the provided layer.
*
* \return A future that has to be waited on
*/ */
[[nodiscard]] std::future<void> calculatePlaceables(std::deque<RadiusLayerPair> keys); void calculatePlaceables(std::deque<RadiusLayerPair> keys);
/*! /*!
* \brief Creates the areas that have to be avoided by the tree's branches to prevent collision with the model without being able to place a branch with given radius on a single layer. * \brief Creates the areas that have to be avoided by the tree's branches to prevent collision with the model without being able to place a branch with given radius on a single layer.
@ -237,10 +234,8 @@ class TreeModelVolumes
* The result is a 2D area that would cause nodes of radius \p radius to * The result is a 2D area that would cause nodes of radius \p radius to
* collide with the model in a not wanted way. Result is saved in the cache. * collide with the model in a not wanted way. Result is saved in the cache.
* \param keys RadiusLayerPairs of all requested areas. Every radius will be calculated up to the provided layer. * \param keys RadiusLayerPairs of all requested areas. Every radius will be calculated up to the provided layer.
*
* \return A future that has to be waited on
*/ */
[[nodiscard]] std::future<void> calculateAvoidanceToModel(std::deque<RadiusLayerPair> keys); void calculateAvoidanceToModel(std::deque<RadiusLayerPair> keys);
/*! /*!
* \brief Creates the areas that have to be avoided by the tree's branches to prevent collision with the model without being able to place a branch with given radius on a single layer. * \brief Creates the areas that have to be avoided by the tree's branches to prevent collision with the model without being able to place a branch with given radius on a single layer.
@ -259,10 +254,8 @@ class TreeModelVolumes
* These areas are at least xy_min_dist wide. When calculating it is always assumed that every wall is printed on top of another (as in has an overlap with the wall a layer below). Result is saved in the corresponding cache. * These areas are at least xy_min_dist wide. When calculating it is always assumed that every wall is printed on top of another (as in has an overlap with the wall a layer below). Result is saved in the corresponding cache.
* *
* \param keys RadiusLayerPairs of all requested areas. Every radius will be calculated up to the provided layer. * \param keys RadiusLayerPairs of all requested areas. Every radius will be calculated up to the provided layer.
*
* \return A future that has to be waited on
*/ */
[[nodiscard]] std::future<void> calculateWallRestrictions(std::deque<RadiusLayerPair> keys); void calculateWallRestrictions(std::deque<RadiusLayerPair> keys);
/*! /*!
* \brief Creates the areas that can not be passed when expanding an area downwards. As such these areas are an somewhat abstract representation of a wall (as in a printed object). * \brief Creates the areas that can not be passed when expanding an area downwards. As such these areas are an somewhat abstract representation of a wall (as in a printed object).

View File

@ -15,6 +15,8 @@
#include <string> #include <string>
#include <windows.h> //todo Remove! ONLY FOR PUBLIC BETA!! #include <windows.h> //todo Remove! ONLY FOR PUBLIC BETA!!
#include <tbb/parallel_for.h>
namespace Slic3r namespace Slic3r
{ {
@ -140,9 +142,9 @@ void TreeSupport::generateSupportAreas(SliceDataStorage& storage)
std::vector<Polygons> exclude(storage.support.supportLayers.size()); std::vector<Polygons> exclude(storage.support.supportLayers.size());
auto t_start = std::chrono::high_resolution_clock::now(); auto t_start = std::chrono::high_resolution_clock::now();
// get all already existing support areas and exclude them // get all already existing support areas and exclude them
cura::parallel_for<LayerIndex>(LayerIndex(0), LayerIndex(storage.support.supportLayers.size()), LayerIndex(1), tbb::parallel_for(tbb::blocked_range<size_t>(0, storage.support.supportLayers.size()),
[&](const LayerIndex layer_idx) [&](const tbb::blocked_range<size_t> &range) {
{ for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) {
Polygons exlude_at_layer; Polygons exlude_at_layer;
exlude_at_layer.add(storage.support.supportLayers[layer_idx].support_bottom); exlude_at_layer.add(storage.support.supportLayers[layer_idx].support_bottom);
exlude_at_layer.add(storage.support.supportLayers[layer_idx].support_roof); exlude_at_layer.add(storage.support.supportLayers[layer_idx].support_roof);
@ -151,6 +153,7 @@ void TreeSupport::generateSupportAreas(SliceDataStorage& storage)
exlude_at_layer.add(part.outline); exlude_at_layer.add(part.outline);
} }
exclude[layer_idx] = exlude_at_layer.unionPolygons(); exclude[layer_idx] = exlude_at_layer.unionPolygons();
}
}); });
config = processing.first; // this struct is used to easy retrieve setting. No other function except those in TreeModelVolumes and generateInitialAreas have knowledge of the existence of multiple meshes being processed. config = processing.first; // this struct is used to easy retrieve setting. No other function except those in TreeModelVolumes and generateInitialAreas have knowledge of the existence of multiple meshes being processed.
progress_multiplier = 1.0 / double(grouped_meshes.size()); progress_multiplier = 1.0 / double(grouped_meshes.size());
@ -701,9 +704,10 @@ void TreeSupport::generateInitialAreas(const SliceMeshStorage& mesh, std::vector
std::mutex critical_sections; std::mutex critical_sections;
cura::parallel_for<LayerIndex>(1, mesh.overhang_areas.size() - z_distance_delta, 1, tbb::parallel_for(tbb::blocked_range<size_t>(1, mesh.overhang_areas.size() - z_distance_delta),
[&](const LayerIndex layer_idx) [&](const tbb::blocked_range<size_t> &range) {
{ for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) {
if (mesh.overhang_areas[layer_idx + z_distance_delta].empty()) if (mesh.overhang_areas[layer_idx + z_distance_delta].empty())
{ {
return; // This is a continue if imagined in a loop context return; // This is a continue if imagined in a loop context
@ -987,6 +991,7 @@ void TreeSupport::generateInitialAreas(const SliceMeshStorage& mesh, std::vector
addLinesAsInfluenceAreas(overhang_lines, force_tip_to_roof ? support_roof_layers - dtt_roof : 0, layer_idx - dtt_roof, dtt_roof > 0, roof_enabled ? support_roof_layers - dtt_roof : 0); addLinesAsInfluenceAreas(overhang_lines, force_tip_to_roof ? support_roof_layers - dtt_roof : 0, layer_idx - dtt_roof, dtt_roof > 0, roof_enabled ? support_roof_layers - dtt_roof : 0);
} }
} }
}
}); });
delete cross_fill_provider; delete cross_fill_provider;
@ -1285,14 +1290,18 @@ void TreeSupport::mergeInfluenceAreas(std::unordered_map<SupportElement, Polygon
// precalculate the AABBs from the influence areas. // precalculate the AABBs from the influence areas.
cura::parallel_for<size_t>(1, buckets_area.size(), 2, tbb::parallel_for(tbb::blocked_range<size_t>(0, bucket_count),
[&](const size_t idx) // +=2 as in the beginning only uneven buckets will be filled [&](const tbb::blocked_range<size_t> &range) {
for (size_t idx = range.begin(); idx < range.end(); ++ idx) {
{ {
for (const std::pair<SupportElement, Polygons>& input_pair : buckets_area[idx]) // +=2 as in the beginning only uneven buckets will be filled
size_t bucket_idx = 2 * idx + 1;
for (const std::pair<SupportElement, Polygons>& input_pair : buckets_area[bucket_idx])
{ {
AABB outer_support_wall_aabb = AABB(input_pair.second); AABB outer_support_wall_aabb = AABB(input_pair.second);
outer_support_wall_aabb.expand(config.getRadius(input_pair.first)); outer_support_wall_aabb.expand(config.getRadius(input_pair.first));
buckets_aabb[idx].emplace(input_pair.first, outer_support_wall_aabb); buckets_aabb[bucket_idx].emplace(input_pair.first, outer_support_wall_aabb);
}
} }
}); });
@ -1305,13 +1314,15 @@ void TreeSupport::mergeInfluenceAreas(std::unordered_map<SupportElement, Polygon
std::vector<std::vector<SupportElement>> erase(buckets_area.size() / 2); std::vector<std::vector<SupportElement>> erase(buckets_area.size() / 2);
cura::parallel_for<size_t>(0, (coord_t)buckets_area.size() - 1, 2, tbb::parallel_for(tbb::blocked_range<size_t>(0, buckets_area.size() / 2),
[&](const size_t bucket_pair_idx) [&](const tbb::blocked_range<size_t> &range) {
{ for (size_t idx = range.begin(); idx < range.end(); ++ idx) {
const size_t bucket_pair_idx = idx * 2;
// Merge bucket_count adjacent to each other, merging uneven bucket numbers into even buckets // Merge bucket_count adjacent to each other, merging uneven bucket numbers into even buckets
mergeHelper(buckets_aabb[bucket_pair_idx], buckets_aabb[bucket_pair_idx + 1], to_bp_areas, to_model_areas, influence_areas, insert_main[bucket_pair_idx / 2], insert_secondary[bucket_pair_idx / 2], insert_influence[bucket_pair_idx / 2], erase[bucket_pair_idx / 2], layer_idx); mergeHelper(buckets_aabb[bucket_pair_idx], buckets_aabb[bucket_pair_idx + 1], to_bp_areas, to_model_areas, influence_areas, insert_main[bucket_pair_idx / 2], insert_secondary[bucket_pair_idx / 2], insert_influence[bucket_pair_idx / 2], erase[bucket_pair_idx / 2], layer_idx);
buckets_area[bucket_pair_idx + 1].clear(); // clear now irrelevant max_bucket_count, and delete them later buckets_area[bucket_pair_idx + 1].clear(); // clear now irrelevant max_bucket_count, and delete them later
buckets_aabb[bucket_pair_idx + 1].clear(); buckets_aabb[bucket_pair_idx + 1].clear();
}
}); });
for (coord_t i = 0; i < (coord_t)buckets_area.size() - 1; i = i + 2) for (coord_t i = 0; i < (coord_t)buckets_area.size() - 1; i = i + 2)
@ -1505,9 +1516,9 @@ std::optional<TreeSupport::SupportElement> TreeSupport::increaseSingleArea(AreaI
void TreeSupport::increaseAreas(std::unordered_map<SupportElement, Polygons>& to_bp_areas, std::unordered_map<SupportElement, Polygons>& to_model_areas, std::map<SupportElement, Polygons>& influence_areas, std::vector<SupportElement*>& bypass_merge_areas, const std::vector<SupportElement*>& last_layer, const LayerIndex layer_idx, const bool mergelayer) void TreeSupport::increaseAreas(std::unordered_map<SupportElement, Polygons>& to_bp_areas, std::unordered_map<SupportElement, Polygons>& to_model_areas, std::map<SupportElement, Polygons>& influence_areas, std::vector<SupportElement*>& bypass_merge_areas, const std::vector<SupportElement*>& last_layer, const LayerIndex layer_idx, const bool mergelayer)
{ {
std::mutex critical_sections; std::mutex critical_sections;
cura::parallel_for<size_t>(0, last_layer.size(), 1, tbb::parallel_for(tbb::blocked_range<size_t>(0, last_layer.size()),
[&](const size_t idx) [&](const tbb::blocked_range<size_t> &range) {
{ for (const size_t idx = range.begin(); idx < range.end(); ++ idx) {
SupportElement* parent = last_layer[idx]; SupportElement* parent = last_layer[idx];
SupportElement elem(parent); // also increases dtt SupportElement elem(parent); // also increases dtt
@ -1752,6 +1763,7 @@ void TreeSupport::increaseAreas(std::unordered_map<SupportElement, Polygons>& to
{ {
parent->result_on_layer = Point(-1, -1); // If the bottom most point of a branch is set, later functions will assume that the position is valid, and ignore it. But as branches connecting with the model that are to small have to be culled, the bottom most point has to be not set. A point can be set on the top most tip layer (maybe more if it should not move for a few layers). parent->result_on_layer = Point(-1, -1); // If the bottom most point of a branch is set, later functions will assume that the position is valid, and ignore it. But as branches connecting with the model that are to small have to be culled, the bottom most point has to be not set. A point can be set on the top most tip layer (maybe more if it should not move for a few layers).
} }
}
}); });
} }
@ -2052,9 +2064,10 @@ void TreeSupport::generateBranchAreas(std::vector<std::pair<LayerIndex, SupportE
const size_t progress_inserts_check_interval = linear_data.size() / progress_report_steps; const size_t progress_inserts_check_interval = linear_data.size() / progress_report_steps;
std::mutex critical_sections; std::mutex critical_sections;
cura::parallel_for<size_t>(0, linear_data.size(), 1, tbb::parallel_for(tbb::blocked_range<size_t>(0, linear_data.size()),
[&](const size_t idx) [&](const tbb::blocked_range<size_t> &range) {
{ for (const size_t idx = range.begin(); idx < range.end(); ++ idx) {
SupportElement* elem = linear_data[idx].second; SupportElement* elem = linear_data[idx].second;
coord_t radius = config.getRadius(*elem); coord_t radius = config.getRadius(*elem);
bool parent_uses_min = false; bool parent_uses_min = false;
@ -2165,6 +2178,7 @@ void TreeSupport::generateBranchAreas(std::vector<std::pair<LayerIndex, SupportE
Progress::messageProgress(Progress::Stage::SUPPORT, progress_total * progress_multiplier + progress_offset, TREE_PROGRESS_TOTAL); Progress::messageProgress(Progress::Stage::SUPPORT, progress_total * progress_multiplier + progress_offset, TREE_PROGRESS_TOTAL);
} }
} }
}
}); });
// single threaded combining all elements to the right layers. ONLY COPYS DATA! // single threaded combining all elements to the right layers. ONLY COPYS DATA!
@ -2185,9 +2199,10 @@ void TreeSupport::smoothBranchAreas(std::vector<std::unordered_map<SupportElemen
std::vector<std::pair<SupportElement*, Polygons>> processing; std::vector<std::pair<SupportElement*, Polygons>> processing;
processing.insert(processing.end(), layer_tree_polygons[layer_idx].begin(), layer_tree_polygons[layer_idx].end()); processing.insert(processing.end(), layer_tree_polygons[layer_idx].begin(), layer_tree_polygons[layer_idx].end());
std::vector<std::vector<std::pair<SupportElement*, Polygons>>> update_next(processing.size()); // with this a lock can be avoided std::vector<std::vector<std::pair<SupportElement*, Polygons>>> update_next(processing.size()); // with this a lock can be avoided
cura::parallel_for<size_t>(0, processing.size(), 1,
[&](const size_t processing_idx) tbb::parallel_for(tbb::blocked_range<size_t>(0, processing.size()),
{ [&](const tbb::blocked_range<size_t> &range) {
for (const size_t processing_idx = range.begin(); processing_idx < range.end(); ++ processing_idx) {
std::pair<SupportElement*, Polygons> data_pair = processing[processing_idx]; std::pair<SupportElement*, Polygons> data_pair = processing[processing_idx];
coord_t max_outer_wall_distance = 0; coord_t max_outer_wall_distance = 0;
@ -2212,6 +2227,7 @@ void TreeSupport::smoothBranchAreas(std::vector<std::unordered_map<SupportElemen
} }
} }
} }
}
}); });
for (std::vector<std::pair<SupportElement*, Polygons>> data_vector : update_next) for (std::vector<std::pair<SupportElement*, Polygons>> data_vector : update_next)
@ -2234,9 +2250,9 @@ void TreeSupport::smoothBranchAreas(std::vector<std::unordered_map<SupportElemen
processing.insert(processing.end(), layer_tree_polygons[layer_idx].begin(), layer_tree_polygons[layer_idx].end()); processing.insert(processing.end(), layer_tree_polygons[layer_idx].begin(), layer_tree_polygons[layer_idx].end());
std::vector<std::pair<SupportElement*, Polygons>> update_next(processing.size(), std::pair<SupportElement*, Polygons>(nullptr, Polygons())); // with this a lock can be avoided std::vector<std::pair<SupportElement*, Polygons>> update_next(processing.size(), std::pair<SupportElement*, Polygons>(nullptr, Polygons())); // with this a lock can be avoided
cura::parallel_for<size_t>(0, processing.size(), 1, tbb::parallel_for(tbb::blocked_range<size_t>(0, processing.size()),
[&](const size_t processing_idx) [&](const tbb::blocked_range<size_t> &range) {
{ for (const size_t processing_idx = range.begin(); processing_idx < range.end(); ++ processing_idx) {
std::pair<SupportElement*, Polygons> data_pair = processing[processing_idx]; std::pair<SupportElement*, Polygons> data_pair = processing[processing_idx];
bool do_something = false; bool do_something = false;
Polygons max_allowed_area; Polygons max_allowed_area;
@ -2266,6 +2282,7 @@ void TreeSupport::smoothBranchAreas(std::vector<std::unordered_map<SupportElemen
update_next[processing_idx] = std::pair<SupportElement*, Polygons>(data_pair.first, result); update_next[processing_idx] = std::pair<SupportElement*, Polygons>(data_pair.first, result);
} }
} }
}
}); });
updated_last_iteration.clear(); updated_last_iteration.clear();
@ -2286,9 +2303,9 @@ void TreeSupport::smoothBranchAreas(std::vector<std::unordered_map<SupportElemen
void TreeSupport::dropNonGraciousAreas(std::vector<std::unordered_map<SupportElement*, Polygons>>& layer_tree_polygons, const std::vector<std::pair<LayerIndex, SupportElement*>>& linear_data, std::vector<std::vector<std::pair<LayerIndex, Polygons>>>& dropped_down_areas, const std::map<SupportElement*, SupportElement*>& inverse_tree_order) void TreeSupport::dropNonGraciousAreas(std::vector<std::unordered_map<SupportElement*, Polygons>>& layer_tree_polygons, const std::vector<std::pair<LayerIndex, SupportElement*>>& linear_data, std::vector<std::vector<std::pair<LayerIndex, Polygons>>>& dropped_down_areas, const std::map<SupportElement*, SupportElement*>& inverse_tree_order)
{ {
cura::parallel_for<size_t>(0, linear_data.size(), 1, tbb::parallel_for(tbb::blocked_range<size_t>(0, linear_data.size()),
[&](const size_t idx) [&](const tbb::blocked_range<size_t> &range) {
{ for (const size_t idx = range.begin(); idx < range.end(); ++ idx) {
SupportElement* elem = linear_data[idx].second; SupportElement* elem = linear_data[idx].second;
bool non_gracious_model_contact = !elem->to_model_gracious && !inverse_tree_order.count(elem); // if a element has no child, it connects to whatever is below as no support further down for it will exist. bool non_gracious_model_contact = !elem->to_model_gracious && !inverse_tree_order.count(elem); // if a element has no child, it connects to whatever is below as no support further down for it will exist.
@ -2303,6 +2320,7 @@ void TreeSupport::dropNonGraciousAreas(std::vector<std::unordered_map<SupportEle
counter++; counter++;
} }
} }
}
}); });
} }
@ -2314,9 +2332,9 @@ void TreeSupport::finalizeInterfaceAndSupportAreas(std::vector<Polygons>& suppor
// Iterate over the generated circles in parallel and clean them up. Also add support floor. // Iterate over the generated circles in parallel and clean them up. Also add support floor.
std::mutex critical_sections; std::mutex critical_sections;
cura::parallel_for<LayerIndex>(0, static_cast<coord_t>(support_layer_storage.size()), 1, tbb::parallel_for(tbb::blocked_range<size_t>(0, support_layer_storage.size()),
[&](const LayerIndex layer_idx) [&](const tbb::blocked_range<size_t> &range) {
{ for (const size_t layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) {
support_layer_storage[layer_idx] = support_layer_storage[layer_idx].unionPolygons().smooth(50); // Most of the time in this function is this union call. Can take 300+ ms when a lot of areas are to be unioned. support_layer_storage[layer_idx] = support_layer_storage[layer_idx].unionPolygons().smooth(50); // Most of the time in this function is this union call. Can take 300+ ms when a lot of areas are to be unioned.
support_layer_storage[layer_idx].simplify(std::min(coord_t(30), config.maximum_resolution), std::min(coord_t(10), config.maximum_deviation)); // simplify a bit, to ensure the output does not contain outrageous amounts of vertices. Should not be necessary, just a precaution. support_layer_storage[layer_idx].simplify(std::min(coord_t(30), config.maximum_resolution), std::min(coord_t(10), config.maximum_deviation)); // simplify a bit, to ensure the output does not contain outrageous amounts of vertices. Should not be necessary, just a precaution.
// Subtract support lines of the branches from the roof // Subtract support lines of the branches from the roof
@ -2395,6 +2413,7 @@ void TreeSupport::finalizeInterfaceAndSupportAreas(std::vector<Polygons>& suppor
storage.support.layer_nr_max_filled_layer = std::max(storage.support.layer_nr_max_filled_layer, static_cast<int>(layer_idx)); storage.support.layer_nr_max_filled_layer = std::max(storage.support.layer_nr_max_filled_layer, static_cast<int>(layer_idx));
} }
} }
}
}); });
} }