FIX: solve tree support crash

jira: STUDIO-8509
Change-Id: I8658538d7919136efbbf0d48cbf3d366e0621ded
This commit is contained in:
Arthur 2024-10-21 17:13:24 +08:00 committed by Lane.Wei
parent ebdfa82845
commit d5b14e5c09
2 changed files with 32 additions and 49 deletions

View File

@ -2004,7 +2004,7 @@ void TreeSupport::draw_circles()
return;
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)
{
for (size_t layer_nr = range.begin(); layer_nr < range.end(); layer_nr++)
@ -2662,7 +2662,8 @@ void TreeSupport::drop_nodes()
// Remove all circle neighbours that are completely inside the polygon and merge them into this node.
for (const Point &neighbour : neighbours) {
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);
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);
@ -2938,8 +2939,6 @@ void TreeSupport::drop_nodes()
for (; i_node != nullptr; i_node = i_node->parent)
{
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
if (i_node->parent) {
@ -2954,20 +2953,24 @@ void TreeSupport::drop_nodes()
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);
}
contact_nodes[i_layer].erase(to_erase);
i_node->valid = false;
i_node->is_processed = true; // mark to be deleted later
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();
}
void TreeSupport::smooth_nodes()
@ -3607,35 +3610,21 @@ SupportNode* TreeSupportData::create_node(const Point position, const int distan
{
// this function may be called from multiple threads, need to 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_);
contact_nodes.emplace_back(node);
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_);
SupportNode* raw_ptr = node.get();
contact_nodes.emplace_back(std::move(node));
m_mutex.unlock();
if (parent)
node->movement = position - parent->position;
return node;
raw_ptr->movement = position - parent->position;
return raw_ptr;
}
void TreeSupportData::clear_nodes()
{
for (auto node : contact_nodes) {
delete node;
}
tbb::spin_mutex::scoped_lock guard(m_mutex);
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
{
size_t factor = (size_t)(radius / m_radius_sample_resolution);
@ -3663,27 +3652,22 @@ const ExPolygons& TreeSupportData::calculate_avoidance(const RadiusLayerPair& ke
{
const auto &radius = key.radius;
const auto &layer_nr = key.layer_nr;
if (layer_nr == 0) {
// avoid ExPolygons:~ExPolygons() in multi-threading case, as it's not thread-safe and may
// cause crash in some cases. See STUDIO-8313.
if (m_avoidance_cache.find(key) == m_avoidance_cache.end())
m_avoidance_cache[key] = get_collision(radius, 0);
return m_avoidance_cache[key];
}
ExPolygons avoidance_areas;
if (layer_nr > 0) {
// Avoidance for a given layer depends on all layers beneath it so could have very deep recursion depths if
// 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);
}
// Avoidance for a given layer depends on all layers beneath it so could have very deep recursion depths if
// 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);
avoidance_areas = std::move(offset_ex(get_avoidance(radius, layer_nr - 1), scale_(-m_max_move_distances[layer_nr-1])));
}
ExPolygons avoidance_areas = std::move(offset_ex(get_avoidance(radius, layer_nr - 1), scale_(-m_max_move_distances[layer_nr-1])));
const ExPolygons &collision = get_collision(radius, layer_nr);
avoidance_areas.insert(avoidance_areas.end(), collision.begin(), collision.end());
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,
coordf_t print_z_, coordf_t height_, coordf_t dist_mm_to_top_ = 0, coordf_t radius_ = 0);
void clear_nodes();
void remove_invalid_nodes();
std::vector<LayerHeightData> layer_heights;
std::vector<SupportNode*> contact_nodes;
std::vector<std::unique_ptr<SupportNode>> contact_nodes;
// ExPolygon m_machine_border;
private: