FIX: solve tree support crash

jira: STUDIO-8509
Change-Id: I8658538d7919136efbbf0d48cbf3d366e0621ded
(cherry picked from commit d5b14e5c094fd68426f1be4d78734f7b86888eb2)
This commit is contained in:
Arthur 2024-10-21 17:13:24 +08:00 committed by Noisyfox
parent 7a26dde977
commit 07c7e2f910
2 changed files with 34 additions and 48 deletions

View file

@ -1947,7 +1947,7 @@ void TreeSupport::draw_circles()
return; return;
BOOST_LOG_TRIVIAL(info) << "draw_circles for object: " << m_object->model_object()->name; BOOST_LOG_TRIVIAL(info) << "draw_circles for object: " << m_object->model_object()->name;
tbb::parallel_for(tbb::blocked_range<size_t>(0, contact_nodes.size()), tbb::parallel_for(tbb::blocked_range<size_t>(0, m_ts_data->layer_heights.size()),
[&](const tbb::blocked_range<size_t>& range) [&](const tbb::blocked_range<size_t>& range)
{ {
for (size_t layer_nr = range.begin(); layer_nr < range.end(); layer_nr++) for (size_t layer_nr = range.begin(); layer_nr < range.end(); layer_nr++)
@ -2597,7 +2597,8 @@ void TreeSupport::drop_nodes()
// Remove all circle neighbours that are completely inside the polygon and merge them into this node. // Remove all circle neighbours that are completely inside the polygon and merge them into this node.
for (const Point &neighbour : neighbours) { for (const Point &neighbour : neighbours) {
SupportNode * neighbour_node = nodes_this_part[neighbour]; SupportNode * neighbour_node = nodes_this_part[neighbour];
if(neighbour_node->type==ePolygon) continue; if (neighbour_node->valid == false) continue;
if (neighbour_node->type == ePolygon) continue;
coord_t neighbour_radius = scale_(neighbour_node->radius); coord_t neighbour_radius = scale_(neighbour_node->radius);
Point pt_north = neighbour + Point(0, neighbour_radius), pt_south = neighbour - Point(0, neighbour_radius), Point pt_north = neighbour + Point(0, neighbour_radius), pt_south = neighbour - Point(0, neighbour_radius),
pt_west = neighbour - Point(neighbour_radius, 0), pt_east = neighbour + Point(neighbour_radius, 0); pt_west = neighbour - Point(neighbour_radius, 0), pt_east = neighbour + Point(neighbour_radius, 0);
@ -2871,8 +2872,6 @@ void TreeSupport::drop_nodes()
for (; i_node != nullptr; i_node = i_node->parent) for (; i_node != nullptr; i_node = i_node->parent)
{ {
size_t i_layer = i_node->obj_layer_nr; size_t i_layer = i_node->obj_layer_nr;
std::vector<SupportNode*>::iterator to_erase = std::find(contact_nodes[i_layer].begin(), contact_nodes[i_layer].end(), i_node);
if (to_erase != contact_nodes[i_layer].end())
{ {
// update the parent-child chain // update the parent-child chain
if (i_node->parent) { if (i_node->parent) {
@ -2887,18 +2886,23 @@ void TreeSupport::drop_nodes()
i_node->child->parents.erase(std::find(i_node->child->parents.begin(), i_node->child->parents.end(), i_node)); i_node->child->parents.erase(std::find(i_node->child->parents.begin(), i_node->child->parents.end(), i_node));
append(i_node->child->parents, i_node->parents); append(i_node->child->parents, i_node->parents);
} }
contact_nodes[i_layer].erase(to_erase); i_node->is_processed = true; // mark to be deleted later
i_node->valid = false;
for (SupportNode* neighbour : i_node->merged_neighbours) for (SupportNode* neighbour : i_node->merged_neighbours)
{ {
unsupported_branch_leaves.push_front({ i_layer, neighbour }); if (neighbour && !neighbour->is_processed)
unsupported_branch_leaves.push_front({ i_layer, neighbour });
} }
} }
} }
} }
for (auto &layer_contact_nodes : contact_nodes) {
if (!layer_contact_nodes.empty())
layer_contact_nodes.erase(std::remove_if(layer_contact_nodes.begin(), layer_contact_nodes.end(), [](SupportNode *node) { return node->is_processed; }),
layer_contact_nodes.end());
}
} }
BOOST_LOG_TRIVIAL(debug) << "after m_avoidance_cache.size()=" << m_ts_data->m_avoidance_cache.size(); BOOST_LOG_TRIVIAL(debug) << "after m_avoidance_cache.size()=" << m_ts_data->m_avoidance_cache.size();
} }
@ -3419,32 +3423,20 @@ SupportNode* TreeSupportData::create_node(const Point position, const int distan
{ {
// this function may be called from multiple threads, need to lock // this function may be called from multiple threads, need to lock
m_mutex.lock(); m_mutex.lock();
SupportNode* node = new SupportNode(position, distance_to_top, obj_layer_nr, support_roof_layers_below, to_buildplate, parent, print_z_, height_, dist_mm_to_top_, radius_); std::unique_ptr<SupportNode> node = std::make_unique<SupportNode>(position, distance_to_top, obj_layer_nr, support_roof_layers_below, to_buildplate, parent, print_z_, height_, dist_mm_to_top_, radius_);
contact_nodes.emplace_back(node); SupportNode* raw_ptr = node.get();
contact_nodes.emplace_back(std::move(node));
m_mutex.unlock(); m_mutex.unlock();
if (parent) if (parent)
node->movement = position - parent->position; raw_ptr->movement = position - parent->position;
return node; return raw_ptr;
} }
void TreeSupportData::clear_nodes() void TreeSupportData::clear_nodes()
{ {
for (auto node : contact_nodes) { tbb::spin_mutex::scoped_lock guard(m_mutex);
delete node;
}
contact_nodes.clear(); contact_nodes.clear();
} }
void TreeSupportData::remove_invalid_nodes()
{
for (auto it = contact_nodes.begin(); it != contact_nodes.end();) {
if ((*it)->valid==false) {
delete (*it);
it = contact_nodes.erase(it);
}
else {
it++;
}
}
}
coordf_t TreeSupportData::ceil_radius(coordf_t radius) const coordf_t TreeSupportData::ceil_radius(coordf_t radius) const
{ {
@ -3473,27 +3465,22 @@ const ExPolygons& TreeSupportData::calculate_avoidance(const RadiusLayerPair& ke
{ {
const auto &radius = key.radius; const auto &radius = key.radius;
const auto &layer_nr = key.layer_nr; const auto &layer_nr = key.layer_nr;
if (layer_nr == 0) { ExPolygons avoidance_areas;
// avoid ExPolygons:~ExPolygons() in multi-threading case, as it's not thread-safe and may if (layer_nr > 0) {
// cause crash in some cases. See STUDIO-8313. // Avoidance for a given layer depends on all layers beneath it so could have very deep recursion depths if
if (m_avoidance_cache.find(key) == m_avoidance_cache.end()) // called at high layer heights. We can limit the reqursion depth to N by checking if the layer N
m_avoidance_cache[key] = get_collision(radius, 0); // below the current one exists and if not, forcing the calculation of that layer. This may cause another recursion
return m_avoidance_cache[key]; // if the layer at 2N below the current one but we won't exceed our limit unless there are N*N uncalculated layers
} // below our current one.
constexpr auto max_recursion_depth = 100;
// Check if we would exceed the recursion limit by trying to process this layer
if (layer_nr >= max_recursion_depth && m_avoidance_cache.find({radius, layer_nr - max_recursion_depth}) == m_avoidance_cache.end()) {
// Force the calculation of the layer `max_recursion_depth` below our current one, ignoring the result.
get_avoidance(radius, layer_nr - max_recursion_depth);
}
// Avoidance for a given layer depends on all layers beneath it so could have very deep recursion depths if avoidance_areas = offset_ex(get_avoidance(radius, layer_nr - 1), scale_(-m_max_move_distances[layer_nr-1]));
// called at high layer heights. We can limit the reqursion depth to N by checking if the layer N
// below the current one exists and if not, forcing the calculation of that layer. This may cause another recursion
// if the layer at 2N below the current one but we won't exceed our limit unless there are N*N uncalculated layers
// below our current one.
constexpr auto max_recursion_depth = 100;
// Check if we would exceed the recursion limit by trying to process this layer
if (layer_nr >= max_recursion_depth && m_avoidance_cache.find({radius, layer_nr - max_recursion_depth}) == m_avoidance_cache.end()) {
// Force the calculation of the layer `max_recursion_depth` below our current one, ignoring the result.
get_avoidance(radius, layer_nr - max_recursion_depth);
} }
ExPolygons avoidance_areas = offset_ex(get_avoidance(radius, layer_nr - 1), scale_(-m_max_move_distances[layer_nr-1]));
const ExPolygons &collision = get_collision(radius, layer_nr); const ExPolygons &collision = get_collision(radius, layer_nr);
avoidance_areas.insert(avoidance_areas.end(), collision.begin(), collision.end()); avoidance_areas.insert(avoidance_areas.end(), collision.begin(), collision.end());
avoidance_areas = std::move(union_ex(avoidance_areas)); avoidance_areas = std::move(union_ex(avoidance_areas));

View file

@ -247,10 +247,9 @@ public:
SupportNode* create_node(const Point position, const int distance_to_top, const int obj_layer_nr, const int support_roof_layers_below, const bool to_buildplate, SupportNode* parent, SupportNode* create_node(const Point position, const int distance_to_top, const int obj_layer_nr, const int support_roof_layers_below, const bool to_buildplate, SupportNode* parent,
coordf_t print_z_, coordf_t height_, coordf_t dist_mm_to_top_ = 0, coordf_t radius_ = 0); coordf_t print_z_, coordf_t height_, coordf_t dist_mm_to_top_ = 0, coordf_t radius_ = 0);
void clear_nodes(); void clear_nodes();
void remove_invalid_nodes();
std::vector<LayerHeightData> layer_heights; std::vector<LayerHeightData> layer_heights;
std::vector<SupportNode*> contact_nodes; std::vector<std::unique_ptr<SupportNode>> contact_nodes;
// ExPolygon m_machine_border; // ExPolygon m_machine_border;
private: private: