Tree Supports: Refactoring of RadiusLayerPolygonCache for speed.
This commit is contained in:
parent
f7f763300e
commit
fdecb30664
@ -574,7 +574,8 @@ void TreeModelVolumes::calculateCollisionHolefree(const std::vector<RadiusLayerP
|
||||
|
||||
tbb::parallel_for(tbb::blocked_range<LayerIndex>(0, max_layer + 1, keys.size()),
|
||||
[&](const tbb::blocked_range<LayerIndex> &range) {
|
||||
RadiusLayerPolygonCacheData data;
|
||||
std::vector<std::pair<RadiusLayerPair, Polygons>> data;
|
||||
data.reserve(range.size() * keys.size());
|
||||
for (LayerIndex layer_idx = range.begin(); layer_idx < range.end(); ++ layer_idx) {
|
||||
for (RadiusLayerPair key : keys)
|
||||
if (layer_idx <= key.second) {
|
||||
@ -585,10 +586,10 @@ void TreeModelVolumes::calculateCollisionHolefree(const std::vector<RadiusLayerP
|
||||
coord_t increase_radius_ceil = ceilRadius(m_increase_until_radius, false) - radius;
|
||||
assert(increase_radius_ceil > 0);
|
||||
// this union is important as otherwise holes(in form of lines that will increase to holes in a later step) can get unioned onto the area.
|
||||
data[RadiusLayerPair(radius, layer_idx)] = polygons_simplify(
|
||||
offset(union_ex(getCollision(m_increase_until_radius, layer_idx, false)),
|
||||
data.emplace_back(RadiusLayerPair(radius, layer_idx), polygons_simplify(
|
||||
offset(union_ex(this->getCollision(m_increase_until_radius, layer_idx, false)),
|
||||
5 - increase_radius_ceil, ClipperLib::jtRound, m_min_resolution),
|
||||
m_min_resolution);
|
||||
m_min_resolution));
|
||||
}
|
||||
}
|
||||
m_collision_cache_holefree.insert(std::move(data));
|
||||
@ -832,13 +833,25 @@ coord_t TreeModelVolumes::ceilRadius(const coord_t radius) const
|
||||
return out;
|
||||
}
|
||||
|
||||
void TreeModelVolumes::RadiusLayerPolygonCache::allocate_layers(size_t num_layers)
|
||||
{
|
||||
if (num_layers > m_data.size()) {
|
||||
if (num_layers > m_data.capacity())
|
||||
reserve_power_of_2(m_data, num_layers);
|
||||
m_data.resize(num_layers, {});
|
||||
}
|
||||
}
|
||||
|
||||
// For debugging purposes, sorted by layer index, then by radius.
|
||||
std::vector<std::pair<TreeModelVolumes::RadiusLayerPair, std::reference_wrapper<const Polygons>>> TreeModelVolumes::RadiusLayerPolygonCache::sorted() const
|
||||
{
|
||||
std::vector<std::pair<RadiusLayerPair, std::reference_wrapper<const Polygons>>> out;
|
||||
for (auto it = this->data.begin(); it != this->data.end(); ++ it)
|
||||
out.emplace_back(it->first, it->second);
|
||||
std::sort(out.begin(), out.end(), [](auto &l, auto &r){ return l.first.second < r.first.second || (l.first.second == r.first.second) && l.first.first < r.first.first; });
|
||||
for (auto &layer : m_data) {
|
||||
auto layer_idx = LayerIndex(&layer - m_data.data());
|
||||
for (auto &radius_polygons : layer)
|
||||
out.emplace_back(std::make_pair(radius_polygons.first, layer_idx), radius_polygons.second);
|
||||
}
|
||||
assert(std::is_sorted(out.begin(), out.end(), [](auto &l, auto &r){ return l.first.second < r.first.second || (l.first.second == r.first.second) && l.first.first < r.first.first; }));
|
||||
return out;
|
||||
}
|
||||
|
||||
|
@ -305,36 +305,36 @@ private:
|
||||
* \brief Convenience typedef for the keys to the caches
|
||||
*/
|
||||
using RadiusLayerPair = std::pair<coord_t, LayerIndex>;
|
||||
using RadiusLayerPolygonCacheData = std::unordered_map<RadiusLayerPair, Polygons, boost::hash<RadiusLayerPair>>;
|
||||
class RadiusLayerPolygonCache {
|
||||
// Map from radius to Polygons. Cache of one layer collision regions.
|
||||
using LayerData = std::map<coord_t, Polygons>;
|
||||
// Vector of layers, at each layer map of radius to Polygons.
|
||||
// Reference to Polygons returned shall be stable to insertion.
|
||||
using Layers = std::vector<LayerData>;
|
||||
public:
|
||||
RadiusLayerPolygonCache() = default;
|
||||
RadiusLayerPolygonCache(RadiusLayerPolygonCache &&rhs) : data(std::move(rhs.data)) {}
|
||||
RadiusLayerPolygonCache& operator=(RadiusLayerPolygonCache &&rhs) { data = std::move(rhs.data); return *this; }
|
||||
RadiusLayerPolygonCache(RadiusLayerPolygonCache &&rhs) : m_data(std::move(rhs.m_data)) {}
|
||||
RadiusLayerPolygonCache& operator=(RadiusLayerPolygonCache &&rhs) { m_data = std::move(rhs.m_data); return *this; }
|
||||
|
||||
RadiusLayerPolygonCache(const RadiusLayerPolygonCache&) = delete;
|
||||
RadiusLayerPolygonCache& operator=(const RadiusLayerPolygonCache&) = delete;
|
||||
|
||||
void insert(RadiusLayerPolygonCacheData &&in) {
|
||||
std::lock_guard<std::mutex> guard(this->mutex);
|
||||
for (auto& d : in)
|
||||
this->data.emplace(d.first, std::move(d.second));
|
||||
}
|
||||
void insert(std::vector<std::pair<RadiusLayerPair, Polygons>> &&in) {
|
||||
std::lock_guard<std::mutex> guard(this->mutex);
|
||||
for (auto& d : in)
|
||||
this->data.emplace(d.first, std::move(d.second));
|
||||
std::lock_guard<std::mutex> guard(m_mutex);
|
||||
for (auto &d : in)
|
||||
this->get_allocate_layer_data(d.first.second).emplace(d.first.first, std::move(d.second));
|
||||
}
|
||||
// by layer
|
||||
void insert(std::vector<std::pair<coord_t, Polygons>> &&in, coord_t radius) {
|
||||
std::lock_guard<std::mutex> guard(this->mutex);
|
||||
std::lock_guard<std::mutex> guard(m_mutex);
|
||||
for (auto &d : in)
|
||||
this->data.emplace(RadiusLayerPair{ radius, d.first }, std::move(d.second));
|
||||
this->get_allocate_layer_data(d.first).emplace(radius, std::move(d.second));
|
||||
}
|
||||
void insert(std::vector<Polygons> &&in, coord_t first_layer_idx, coord_t radius) {
|
||||
std::lock_guard<std::mutex> guard(this->mutex);
|
||||
std::lock_guard<std::mutex> guard(m_mutex);
|
||||
allocate_layers(first_layer_idx + in.size());
|
||||
for (auto &d : in)
|
||||
this->data.emplace(RadiusLayerPair{ radius, first_layer_idx ++ }, std::move(d));
|
||||
m_data[first_layer_idx ++].emplace(radius, std::move(d));
|
||||
}
|
||||
/*!
|
||||
* \brief Checks a cache for a given RadiusLayerPair and returns it if it is found
|
||||
@ -342,11 +342,30 @@ private:
|
||||
* \return A wrapped optional reference of the requested area (if it was found, an empty optional if nothing was found)
|
||||
*/
|
||||
std::optional<std::reference_wrapper<const Polygons>> getArea(const TreeModelVolumes::RadiusLayerPair &key) const {
|
||||
std::lock_guard<std::mutex> guard(this->mutex);
|
||||
const auto it = this->data.find(key);
|
||||
return it == this->data.end() ?
|
||||
std::lock_guard<std::mutex> guard(m_mutex);
|
||||
if (key.second >= m_data.size())
|
||||
return std::optional<std::reference_wrapper<const Polygons>>{};
|
||||
const auto &layer = m_data[key.second];
|
||||
auto it = layer.find(key.first);
|
||||
return it == layer.end() ?
|
||||
std::optional<std::reference_wrapper<const Polygons>>{} : std::optional<std::reference_wrapper<const Polygons>>{ it->second };
|
||||
}
|
||||
// Get a collision area at a given layer for a radius that is a lower or equial to the key radius.
|
||||
std::optional<std::pair<coord_t, std::reference_wrapper<const Polygons>>> get_lower_bound_area(const TreeModelVolumes::RadiusLayerPair &key) const {
|
||||
std::lock_guard<std::mutex> guard(m_mutex);
|
||||
if (key.second >= m_data.size())
|
||||
return {};
|
||||
const auto &layer = m_data[key.second];
|
||||
if (layer.empty())
|
||||
return {};
|
||||
auto it = layer.lower_bound(key.first);
|
||||
if (it == layer.end() || it->first != key.first) {
|
||||
if (it == layer.begin())
|
||||
return {};
|
||||
-- it;
|
||||
}
|
||||
return std::make_pair(it->first, std::reference_wrapper<const Polygons>(it->second));
|
||||
}
|
||||
/*!
|
||||
* \brief Get the highest already calculated layer in the cache.
|
||||
* \param radius The radius for which the highest already calculated layer has to be found.
|
||||
@ -355,22 +374,27 @@ private:
|
||||
* \return A wrapped optional reference of the requested area (if it was found, an empty optional if nothing was found)
|
||||
*/
|
||||
LayerIndex getMaxCalculatedLayer(coord_t radius) const {
|
||||
std::lock_guard<std::mutex> guard(this->mutex);
|
||||
int max_layer = -1;
|
||||
// the placeable on model areas do not exist on layer 0, as there can not be model below it. As such it may be possible that layer 1 is available, but layer 0 does not exist.
|
||||
if (this->data.find({ radius, 1 }) != this->data.end())
|
||||
max_layer = 1;
|
||||
while (this->data.count(TreeModelVolumes::RadiusLayerPair(radius, max_layer + 1)) > 0)
|
||||
++ max_layer;
|
||||
return max_layer;
|
||||
std::lock_guard<std::mutex> guard(m_mutex);
|
||||
auto layer_idx = LayerIndex(m_data.size()) - 1;
|
||||
for (; layer_idx > 0; -- layer_idx)
|
||||
if (const auto &layer = m_data[layer_idx]; layer.find(radius) != layer.end())
|
||||
break;
|
||||
// The placeable on model areas do not exist on layer 0, as there can not be model below it. As such it may be possible that layer 1 is available, but layer 0 does not exist.
|
||||
return layer_idx == 0 ? -1 : layer_idx;
|
||||
}
|
||||
|
||||
// For debugging purposes, sorted by layer index, then by radius.
|
||||
[[nodiscard]] std::vector<std::pair<RadiusLayerPair, std::reference_wrapper<const Polygons>>> sorted() const;
|
||||
|
||||
private:
|
||||
RadiusLayerPolygonCacheData data;
|
||||
mutable std::mutex mutex;
|
||||
LayerData& get_allocate_layer_data(LayerIndex layer_idx) {
|
||||
allocate_layers(layer_idx + 1);
|
||||
return m_data[layer_idx];
|
||||
}
|
||||
void allocate_layers(size_t num_layers);
|
||||
|
||||
Layers m_data;
|
||||
mutable std::mutex m_mutex;
|
||||
};
|
||||
|
||||
|
||||
|
@ -176,6 +176,21 @@ template<class T> size_t next_highest_power_of_2(T v,
|
||||
return next_highest_power_of_2(uint32_t(v));
|
||||
}
|
||||
|
||||
template<class VectorType> void reserve_power_of_2(VectorType &vector, size_t n)
|
||||
{
|
||||
vector.reserve(next_highest_power_of_2(n));
|
||||
}
|
||||
|
||||
template<class VectorType> void reserve_more(VectorType &vector, size_t n)
|
||||
{
|
||||
vector.reserve(vector.size() + n);
|
||||
}
|
||||
|
||||
template<class VectorType> void reserve_more_power_of_2(VectorType &vector, size_t n)
|
||||
{
|
||||
vector.reserve(next_highest_power_of_2(vector.size() + n));
|
||||
}
|
||||
|
||||
template<typename INDEX_TYPE>
|
||||
inline INDEX_TYPE prev_idx_modulo(INDEX_TYPE idx, const INDEX_TYPE count)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user