diff --git a/src/libslic3r/Support/TreeSupport.cpp b/src/libslic3r/Support/TreeSupport.cpp index 07586d0006..d0dfbbf9cc 100644 --- a/src/libslic3r/Support/TreeSupport.cpp +++ b/src/libslic3r/Support/TreeSupport.cpp @@ -15,8 +15,10 @@ #include #include +#include #include #include +#include #ifndef M_PI #define M_PI 3.1415926535897932384626433832795 @@ -649,7 +651,8 @@ void TreeSupport::detect_overhangs(bool check_support_necessity/* = false*/) const coordf_t max_bridge_length = scale_(config.max_bridge_length.value); const bool bridge_no_support = max_bridge_length > 0; const bool support_critical_regions_only = config.support_critical_regions_only.value; - const bool config_remove_small_overhangs = config.support_remove_small_overhang.value; + bool config_remove_small_overhangs = config.support_remove_small_overhang.value; + bool config_detect_sharp_tails = g_config_support_sharp_tails; const int enforce_support_layers = config.enforce_support_layers.value; const double area_thresh_well_supported = SQ(scale_(6)); const double length_thresh_well_supported = scale_(6); @@ -763,6 +766,10 @@ void TreeSupport::detect_overhangs(bool check_support_necessity/* = false*/) layer->lslices_extrudable = intersection_ex(layer->lslices, offset2_ex(layer->lslices, -extrusion_width_scaled / 2, extrusion_width_scaled)); } }); + + typedef std::chrono::high_resolution_clock clock_; + typedef std::chrono::duration > second_; + std::chrono::time_point t0{ clock_::now() }; // main part of overhang detection can be parallel tbb::parallel_for(tbb::blocked_range(0, m_object->layer_count()), [&](const tbb::blocked_range& range) { @@ -795,10 +802,18 @@ void TreeSupport::detect_overhangs(bool check_support_necessity/* = false*/) ExPolygons& lower_polys = lower_layer->lslices_extrudable; // normal overhang + SupportLayer* ts_layer = m_object->get_support_layer(layer_nr + m_raft_layers); ExPolygons lower_layer_offseted = offset_ex(lower_polys, support_offset_scaled, SUPPORT_SURFACES_OFFSET_PARAMETERS); - ExPolygons overhang_areas = diff_ex(curr_polys, lower_layer_offseted); + ts_layer->overhang_areas = std::move(diff_ex(curr_polys, lower_layer_offseted)); - if (is_auto(stype) && g_config_support_sharp_tails) + double duration{ std::chrono::duration_cast(clock_::now() - t0).count() }; + if (duration > 30 || ts_layer->overhang_areas.size() > 100) { + BOOST_LOG_TRIVIAL(info) << "detect_overhangs takes more than 30 secs, skip cantilever and sharp tails detection: layer_nr=" << layer_nr << " duration=" << duration; + config_detect_sharp_tails = false; + config_remove_small_overhangs = false; + continue; + } + if (is_auto(stype) && config_detect_sharp_tails) { // BBS detect sharp tail for (const ExPolygon& expoly : curr_polys) { @@ -813,7 +828,7 @@ void TreeSupport::detect_overhangs(bool check_support_necessity/* = false*/) ExPolygons overhang = diff_ex({ expoly }, lower_polys); layer->sharp_tails.push_back(expoly); layer->sharp_tails_height.push_back(layer->height); - append(overhang_areas, overhang); + append(ts_layer->overhang_areas, overhang); if (!overhang.empty()) { has_sharp_tails = true; @@ -825,31 +840,28 @@ void TreeSupport::detect_overhangs(bool check_support_necessity/* = false*/) } } - SupportLayer* ts_layer = m_object->get_support_layer(layer_nr + m_raft_layers); - for (ExPolygon& poly : overhang_areas) { - ts_layer->overhang_areas.emplace_back(poly); - // check cantilever - { - // lower_layer_offset may be very small, so we need to do max and then add 0.1 - auto cluster_boundary_ex = intersection_ex(poly, offset_ex(lower_polys, scale_(std::max(extrusion_width,lower_layer_offset)+0.1))); - Polygons cluster_boundary = to_polygons(cluster_boundary_ex); - if (cluster_boundary.empty()) continue; - double dist_max = 0; - for (auto& pt : poly.contour.points) { - double dist_pt = std::numeric_limits::max(); - for (auto& ply : cluster_boundary) { - double d = ply.distance_to(pt); - dist_pt = std::min(dist_pt, d); - } - dist_max = std::max(dist_max, dist_pt); - } - if (dist_max > scale_(3)) { // is cantilever if the farmost point is larger than 3mm away from base - max_cantilever_dist = std::max(max_cantilever_dist, dist_max); - layer->cantilevers.emplace_back(poly); - BOOST_LOG_TRIVIAL(debug) << "found a cantilever cluster. layer_nr=" << layer_nr << dist_max; - has_cantilever = true; + // check cantilever + // lower_layer_offset may be very small, so we need to do max and then add 0.1 + lower_layer_offseted = offset_ex(lower_layer_offseted, scale_(std::max(extrusion_width - lower_layer_offset, 0.) + 0.1)); + for (ExPolygon& poly : ts_layer->overhang_areas) { + auto cluster_boundary_ex = intersection_ex(poly, lower_layer_offseted); + Polygons cluster_boundary = to_polygons(cluster_boundary_ex); + if (cluster_boundary.empty()) continue; + double dist_max = 0; + for (auto& pt : poly.contour.points) { + double dist_pt = std::numeric_limits::max(); + for (auto& ply : cluster_boundary) { + double d = ply.distance_to(pt); + dist_pt = std::min(dist_pt, d); } + dist_max = std::max(dist_max, dist_pt); + } + if (dist_max > scale_(3)) { // is cantilever if the farmost point is larger than 3mm away from base + max_cantilever_dist = std::max(max_cantilever_dist, dist_max); + layer->cantilevers.emplace_back(poly); + BOOST_LOG_TRIVIAL(debug) << "found a cantilever cluster. layer_nr=" << layer_nr << dist_max; + has_cantilever = true; } } } @@ -861,7 +873,7 @@ void TreeSupport::detect_overhangs(bool check_support_necessity/* = false*/) return; // check if the sharp tails should be extended higher - if (is_auto(stype) && g_config_support_sharp_tails) { + if (is_auto(stype) && config_detect_sharp_tails) { for (size_t layer_nr = 0; layer_nr < m_object->layer_count(); layer_nr++) { if (m_object->print()->canceled()) break; @@ -945,21 +957,6 @@ void TreeSupport::detect_overhangs(bool check_support_necessity/* = false*/) } } - // group overhang clusters - for (size_t layer_nr = 0; layer_nr < m_object->layer_count(); layer_nr++) { - if (m_object->print()->canceled()) - break; - if(layer_nr+m_raft_layers>=m_object->support_layer_count()) - break; - SupportLayer* ts_layer = m_object->get_support_layer(layer_nr + m_raft_layers); - Layer* layer = m_object->get_layer(layer_nr); - for (auto& overhang : ts_layer->overhang_areas) { - OverhangCluster* cluster = find_and_insert_cluster(overhangClusters, overhang, layer_nr, extrusion_width_scaled); - if (overlaps({ overhang },layer->cantilevers)) - cluster->is_cantilever = true; - } - } - auto enforcers = m_object->slice_support_enforcers(); auto blockers = m_object->slice_support_blockers(); m_object->project_and_append_custom_facets(false, EnforcerBlockerType::ENFORCER, enforcers); @@ -967,6 +964,21 @@ void TreeSupport::detect_overhangs(bool check_support_necessity/* = false*/) if (is_auto(stype) && config_remove_small_overhangs) { if (blockers.size() < m_object->layer_count()) blockers.resize(m_object->layer_count()); + // group overhang clusters + for (size_t layer_nr = 0; layer_nr < m_object->layer_count(); layer_nr++) { + if (m_object->print()->canceled()) + break; + if (layer_nr + m_raft_layers >= m_object->support_layer_count()) + break; + SupportLayer* ts_layer = m_object->get_support_layer(layer_nr + m_raft_layers); + Layer* layer = m_object->get_layer(layer_nr); + for (auto& overhang : ts_layer->overhang_areas) { + OverhangCluster* cluster = find_and_insert_cluster(overhangClusters, overhang, layer_nr, extrusion_width_scaled); + if (overlaps({ overhang }, layer->cantilevers)) + cluster->is_cantilever = true; + } + } + // remove small overhangs for (auto& cluster : overhangClusters) { // 3. check whether the small overhang is sharp tail cluster.is_sharp_tail = false; @@ -1403,7 +1415,7 @@ void TreeSupport::generate_toolpaths() if (m_object->print()->canceled()) break; - m_object->print()->set_status(70, (boost::format(_u8L("Support: generate toolpath at layer %d")) % layer_id).str()); + //m_object->print()->set_status(70, (boost::format(_u8L("Support: generate toolpath at layer %d")) % layer_id).str()); SupportLayer* ts_layer = m_object->get_support_layer(layer_id); Flow support_flow(support_extrusion_width, ts_layer->height, nozzle_diameter); @@ -1583,7 +1595,7 @@ void TreeSupport::generate() // Generate overhang areas profiler.stage_start(STAGE_DETECT_OVERHANGS); - m_object->print()->set_status(55, _u8L("Support: detect overhangs")); + m_object->print()->set_status(55, _u8L("Generating supports")); detect_overhangs(); profiler.stage_finish(STAGE_DETECT_OVERHANGS); @@ -1604,7 +1616,7 @@ void TreeSupport::generate() //Drop nodes to lower layers. profiler.stage_start(STAGE_DROP_DOWN_NODES); - m_object->print()->set_status(60, _u8L("Support: propagate branches")); + m_object->print()->set_status(60, _u8L("Generating supports")); drop_nodes(contact_nodes); profiler.stage_finish(STAGE_DROP_DOWN_NODES); @@ -1612,22 +1624,14 @@ void TreeSupport::generate() //Generate support areas. profiler.stage_start(STAGE_DRAW_CIRCLES); - m_object->print()->set_status(65, _u8L("Support: draw polygons")); + m_object->print()->set_status(65, _u8L("Generating supports")); draw_circles(contact_nodes); profiler.stage_finish(STAGE_DRAW_CIRCLES); - for (auto& layer : contact_nodes) - { - for (SupportNode* p_node : layer) - { - delete p_node; - } - layer.clear(); - } - contact_nodes.clear(); + profiler.stage_start(STAGE_GENERATE_TOOLPATHS); - m_object->print()->set_status(69, _u8L("Support: generate toolpath")); + m_object->print()->set_status(69, _u8L("Generating supports")); generate_toolpaths(); profiler.stage_finish(STAGE_GENERATE_TOOLPATHS); @@ -1677,6 +1681,13 @@ coordf_t TreeSupport::calc_branch_radius(coordf_t base_radius, coordf_t mm_to_to return radius; } +coordf_t TreeSupport::get_radius(const SupportNode* node, coordf_t base_radius) +{ + if (node->radius == 0) + node->radius = calc_branch_radius(base_radius, node->dist_mm_to_top, node->diameter_angle_scale_factor); + return node->radius; +} + ExPolygons TreeSupport::get_avoidance(coordf_t radius, size_t obj_layer_nr) { #if USE_SUPPORT_3D @@ -2017,7 +2028,7 @@ void TreeSupport::draw_circles(const std::vector>& con } - m_object->print()->set_status(65, (boost::format( _u8L("Support: generate polygons at layer %d")) % layer_nr).str()); + //m_object->print()->set_status(65, (boost::format( _u8L("Support: generate polygons at layer %d")) % layer_nr).str()); // join roof segments double contact_dist_scaled = scale_(0.5);// scale_(m_slicing_params.gap_support_object); @@ -2204,7 +2215,7 @@ void TreeSupport::draw_circles(const std::vector>& con std::map> holePropagationInfos; for (int layer_nr = m_object->layer_count() - 1; layer_nr > 0; layer_nr--) { if (print->canceled()) break; - m_object->print()->set_status(66, (boost::format(_u8L("Support: fix holes at layer %d")) % layer_nr).str()); + //m_object->print()->set_status(66, (boost::format(_u8L("Support: fix holes at layer %d")) % layer_nr).str()); const std::vector& curr_layer_nodes = contact_nodes[layer_nr]; SupportLayer* ts_layer = m_object->get_support_layer(layer_nr + m_raft_layers); @@ -2338,14 +2349,10 @@ void TreeSupport::drop_nodes(std::vector>& contact_nod const auto nozzle_diameter = m_object->print()->config().nozzle_diameter.get_at(m_object->config().support_interface_filament-1); const auto support_line_width = config.support_line_width.get_abs_value(nozzle_diameter); - auto get_branch_angle = [this,&config](coordf_t radius) { - if (config.tree_support_branch_angle.value < 30.0) return config.tree_support_branch_angle.value; - return (radius - MIN_BRANCH_RADIUS) / (MAX_BRANCH_RADIUS - MIN_BRANCH_RADIUS) * (config.tree_support_branch_angle.value - 30.0) + 30.0; - }; auto get_max_move_dist = [this, &config, branch_radius, tip_layers, diameter_angle_scale_factor, wall_count, support_extrusion_width, support_line_width](const SupportNode *node, int power = 1) { double move_dist = node->max_move_dist; if (node->max_move_dist == 0) { - if (node->radius == 0) node->radius = calc_branch_radius(branch_radius, node->dist_mm_to_top, diameter_angle_scale_factor); + node->radius = get_radius(node, branch_radius); double angle = config.tree_support_branch_angle.value; if (angle > 30.0 && node->radius > MIN_BRANCH_RADIUS) angle = (node->radius - MIN_BRANCH_RADIUS) / (MAX_BRANCH_RADIUS - MIN_BRANCH_RADIUS) * (config.tree_support_branch_angle.value - 30.0) + 30.0; @@ -2362,7 +2369,47 @@ void TreeSupport::drop_nodes(std::vector>& contact_nod std::vector &layer_heights = m_ts_data->layer_heights; if (layer_heights.empty()) return; - std::unordered_set to_free_node_set; + // precalculate avoidance of all possible radii. + // This will cause computing more (radius, layer_nr) pairs, but it's worth to do so since we are doning this in parallel. + if (1) { + typedef std::chrono::high_resolution_clock clock_; + typedef std::chrono::duration > second_; + std::chrono::time_point t0{ clock_::now() }; + + // get all the possible radiis + std::vector > all_layer_radius(contact_nodes.size()); + std::vector> all_layer_node_dist(contact_nodes.size()); + for (size_t layer_nr = contact_nodes.size() - 1; layer_nr > 0; layer_nr--) { + if (layer_heights[layer_nr].height < EPSILON) continue; + auto& layer_radius = all_layer_radius[layer_nr]; + auto& layer_node_dist = all_layer_node_dist[layer_nr]; + for (auto* p_node : contact_nodes[layer_nr]) { + layer_node_dist.emplace(p_node->dist_mm_to_top); + } + size_t layer_nr_next = layer_heights[layer_nr].next_layer_nr; + if (layer_nr_next <= contact_nodes.size() - 1 && layer_nr_next > 0) { + for (auto node_dist : layer_node_dist) + all_layer_node_dist[layer_nr_next].emplace(node_dist + layer_heights[layer_nr].height); + } + for (auto node_dist : layer_node_dist) { + layer_radius.emplace(calc_branch_radius(branch_radius, node_dist, diameter_angle_scale_factor)); + } + } + // parallel pre-compute avoidance + tbb::parallel_for(tbb::blocked_range(0, contact_nodes.size() - 1), [&](const tbb::blocked_range &range) { + for (size_t layer_nr = range.begin(); layer_nr < range.end(); layer_nr++) { + for (auto node_radius : all_layer_radius[layer_nr]) { + m_ts_data->get_avoidance(node_radius, layer_nr); + get_collision(m_ts_data->m_xy_distance, layer_nr); + } + } + }); + + double duration{ std::chrono::duration_cast(clock_::now() - t0).count() }; + BOOST_LOG_TRIVIAL(debug) << "finish pre calculate_avoidance. before m_avoidance_cache.size()=" << m_ts_data->m_avoidance_cache.size() + << ", takes " << duration << " secs."; + } + m_spanning_trees.resize(contact_nodes.size()); //m_mst_line_x_layer_contour_caches.resize(contact_nodes.size()); @@ -2382,11 +2429,11 @@ void TreeSupport::drop_nodes(std::vector>& contact_nod std::deque> unsupported_branch_leaves; // All nodes that are leaves on this layer that would result in unsupported ('mid-air') branches. const Layer* ts_layer = m_object->get_support_layer(layer_nr); - m_object->print()->set_status(60, (boost::format(_u8L("Support: propagate branches at layer %d")) % layer_nr).str()); + m_object->print()->set_status(60 + int(10 * (1 - float(layer_nr) / contact_nodes.size())), _u8L("Generating supports"));// (boost::format(_u8L("Support: propagate branches at layer %d")) % layer_nr).str()); Polygons layer_contours = std::move(m_ts_data->get_contours_with_holes(layer_nr)); //std::unordered_map& mst_line_x_layer_contour_cache = m_mst_line_x_layer_contour_caches[layer_nr]; - std::unordered_map mst_line_x_layer_contour_cache; + tbb::concurrent_unordered_map mst_line_x_layer_contour_cache; auto is_line_cut_by_contour = [&mst_line_x_layer_contour_cache,&layer_contours](Point a, Point b) { auto iter = mst_line_x_layer_contour_cache.find({ a, b }); @@ -2408,7 +2455,7 @@ void TreeSupport::drop_nodes(std::vector>& contact_nod }; //Group together all nodes for each part. - const ExPolygons& parts = m_ts_data->m_layer_outlines_below[layer_nr];// m_ts_data->get_avoidance(0, layer_nr); + const ExPolygons& parts = m_ts_data->m_layer_outlines_below[layer_nr]; std::vector> nodes_per_part(1 + parts.size()); //All nodes that aren't inside a part get grouped together in the 0th part. for (SupportNode* p_node : layer_contact_nodes) { @@ -2480,23 +2527,24 @@ void TreeSupport::drop_nodes(std::vector>& contact_nod #endif for (size_t group_index = 0; group_index < nodes_per_part.size(); group_index++) { + auto& nodes_this_part = nodes_per_part[group_index]; const MinimumSpanningTree& mst = spanning_trees[group_index]; //In the first pass, merge all nodes that are close together. - std::unordered_set to_delete; - for (const std::pair& entry : nodes_per_part[group_index]) - { + tbb::concurrent_unordered_set to_delete; + std::vector> nodes_vec(nodes_this_part.begin(), nodes_this_part.end()); + tbb::parallel_for_each(nodes_vec.begin(), nodes_vec.end(), [&](const std::pair& entry) { SupportNode* p_node = entry.second; SupportNode& node = *p_node; if (to_delete.find(p_node) != to_delete.end()) { - continue; //Delete this node (don't create a new node for it on the next layer). + return; //Delete this node (don't create a new node for it on the next layer). } const std::vector& neighbours = mst.adjacent_nodes(node.position); if (node.type == ePolygon) { // 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_per_part[group_index][neighbour]; - if (neighbour_node->type == ePolygon) continue; + SupportNode * neighbour_node = nodes_this_part[neighbour]; + if(neighbour_node->type==ePolygon) return; 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); @@ -2512,14 +2560,12 @@ void TreeSupport::drop_nodes(std::vector>& contact_nod } } else if (neighbours.size() == 1 && vsize2_with_unscale(neighbours[0] - node.position) < max_move_distance2 && mst.adjacent_nodes(neighbours[0]).size() == 1 && - nodes_per_part[group_index][neighbours[0]]->type!=ePolygon) // We have just two nodes left, and they're very close, and the only neighbor is not ePolygon + nodes_this_part[neighbours[0]]->type!=ePolygon) // We have just two nodes left, and they're very close, and the only neighbor is not ePolygon { //Insert a completely new node and let both original nodes fade. Point next_position = (node.position + neighbours[0]) / 2; //Average position of the two nodes. - - const coordf_t branch_radius_node = calc_branch_radius(branch_radius, node.dist_mm_to_top, diameter_angle_scale_factor); - - auto avoid_layer = get_avoidance(branch_radius_node, layer_nr_next); + coordf_t next_radius = calc_branch_radius(branch_radius, node.dist_mm_to_top+height_next, diameter_angle_scale_factor); + auto avoid_layer = get_avoidance(next_radius, layer_nr_next); if (group_index == 0) { //Avoid collisions. @@ -2527,23 +2573,23 @@ void TreeSupport::drop_nodes(std::vector>& contact_nod move_out_expolys(avoid_layer, next_position, radius_sample_resolution + EPSILON, max_move_between_samples); } - SupportNode* neighbour = nodes_per_part[group_index][neighbours[0]]; - SupportNode* node_; + SupportNode* neighbour = nodes_this_part[neighbours[0]]; + SupportNode* node_parent; if (p_node->parent && neighbour->parent) - node_ = (node.dist_mm_to_top >= neighbour->dist_mm_to_top) ? p_node : neighbour; + node_parent = (node.dist_mm_to_top >= neighbour->dist_mm_to_top) ? p_node : neighbour; else - node_ = p_node->parent ? p_node : neighbour; + node_parent = p_node->parent ? p_node : neighbour; // Make sure the next pass doesn't drop down either of these (since that already happened). - node_->merged_neighbours.push_front(node_ == p_node ? neighbour : p_node); + node_parent->merged_neighbours.push_front(node_parent == p_node ? neighbour : p_node); const bool to_buildplate = !is_inside_ex(get_collision(0, layer_nr_next), next_position); - SupportNode * next_node = m_ts_data->create_node(next_position, node_->distance_to_top + 1, layer_nr_next, node_->support_roof_layers_below-1, to_buildplate, node_, - print_z_next, height_next); + SupportNode* next_node = m_ts_data->create_node(next_position, node_parent->distance_to_top + 1, layer_nr_next, node_parent->support_roof_layers_below - 1, to_buildplate, node_parent, + print_z_next, height_next); get_max_move_dist(next_node); + m_ts_data->m_mutex.lock(); contact_nodes[layer_nr_next].push_back(next_node); - - to_delete.insert(neighbour); to_delete.insert(p_node); + m_ts_data->m_mutex.unlock(); } else if (neighbours.size() > 1) //Don't merge leaf nodes because we would then incur movement greater than the maximum move distance. { @@ -2552,7 +2598,7 @@ void TreeSupport::drop_nodes(std::vector>& contact_nod { if (vsize2_with_unscale(neighbour - node.position) < /*max_move_distance2*/get_max_move_dist(&node,2)) { - SupportNode* neighbour_node = nodes_per_part[group_index][neighbour]; + SupportNode* neighbour_node = nodes_this_part[neighbour]; if (neighbour_node->type == ePolygon) continue; // only allow bigger node to merge smaller nodes. See STUDIO-6326 if(node.dist_mm_to_top < neighbour_node->dist_mm_to_top) continue; @@ -2565,15 +2611,16 @@ void TreeSupport::drop_nodes(std::vector>& contact_nod } } } + ); //In the second pass, move all middle nodes. - for (const std::pair& entry : nodes_per_part[group_index]) - { + tbb::parallel_for_each(nodes_vec.begin(), nodes_vec.end(), [&](const std::pair& entry) { + SupportNode* p_node = entry.second; const SupportNode& node = *p_node; if (to_delete.find(p_node) != to_delete.end()) { - continue; + return; } if (node.type == ePolygon) { // polygon node do not merge or move @@ -2595,15 +2642,19 @@ void TreeSupport::drop_nodes(std::vector>& contact_nod p_node, print_z_next, height_next); next_node->max_move_dist = 0; next_node->overhang = std::move(overhangs_next[index_biggest]); + m_ts_data->m_mutex.lock(); contact_nodes[layer_nr_next].emplace_back(next_node); + m_ts_data->m_mutex.unlock(); + } - continue; + return; } //If the branch falls completely inside a collision area (the entire branch would be removed by the X/Y offset), delete it. if (group_index > 0 && is_inside_ex(get_collision(m_ts_data->m_xy_distance, layer_nr), node.position)) { - const coordf_t branch_radius_node = calc_branch_radius(branch_radius, node.dist_mm_to_top, diameter_angle_scale_factor); + std::scoped_lock lock(m_ts_data->m_mutex); + const coordf_t branch_radius_node = get_radius(p_node, branch_radius); Point to_outside = projection_onto(get_collision(m_ts_data->m_xy_distance, layer_nr), node.position); double dist2_to_outside = vsize2_with_unscale(node.position - to_outside); if (dist2_to_outside >= branch_radius_node * branch_radius_node) //Too far inside. @@ -2616,21 +2667,21 @@ void TreeSupport::drop_nodes(std::vector>& contact_nod to_delete.insert(p_node); p_node->valid = false; } - continue; + return; } // if the link between parent and current is cut by contours, mark current as bottom contact node if (p_node->parent && intersection_ln({p_node->position, p_node->parent->position}, layer_contours).empty()==false) { to_delete.insert(p_node); p_node->valid = false; - continue; + return; } } Point next_layer_vertex = node.position; Point move_to_neighbor_center; std::vector moves; std::vector weights; - const std::vector neighbours = mst.adjacent_nodes(node.position); + const std::vector& neighbours = mst.adjacent_nodes(node.position); // 1. do not merge neighbors under 5mm // 2. Only merge node with single neighbor in distance between [max_move_distance, 10mm/layer_height] float dist2_to_first_neighbor = neighbours.empty() ? 0 : vsize2_with_unscale(neighbours[0] - node.position); @@ -2641,7 +2692,7 @@ void TreeSupport::drop_nodes(std::vector>& contact_nod Point sum_direction(0, 0); for (const Point &neighbour : neighbours) { // do not move to the neighbor to be deleted - SupportNode *neighbour_node = nodes_per_part[group_index][neighbour]; + SupportNode *neighbour_node = nodes_this_part[neighbour]; if (to_delete.find(neighbour_node) != to_delete.end()) continue; Point direction = neighbour - node.position; @@ -2672,14 +2723,14 @@ void TreeSupport::drop_nodes(std::vector>& contact_nod } } - const coordf_t branch_radius_node = calc_branch_radius(branch_radius, node.dist_mm_to_top/*+node.print_z*/, diameter_angle_scale_factor); #ifdef SUPPORT_TREE_DEBUG_TO_SVG if (node.position(1) > max_y) { max_y = node.position(1); - branch_radius_temp = branch_radius_node; + branch_radius_temp = get_radius(p_node, branch_radius); } #endif - auto avoidance_next = get_avoidance(branch_radius_node, layer_nr_next); + coordf_t next_radius = calc_branch_radius(branch_radius, node.dist_mm_to_top + height_next, diameter_angle_scale_factor); + auto avoidance_next = get_avoidance(next_radius, layer_nr_next); Point to_outside = projection_onto(avoidance_next, node.position); Point direction_to_outer = to_outside - node.position; @@ -2693,7 +2744,7 @@ void TreeSupport::drop_nodes(std::vector>& contact_nod Point candidate_vertex = node.position; const coordf_t max_move_between_samples = max_move_distance + radius_sample_resolution + EPSILON; // 100 micron extra for rounding errors. // use get_collision instead of get_avoidance here (See STUDIO-4252) - bool is_outside = move_out_expolys(get_collision(branch_radius_node,layer_nr_next), candidate_vertex, max_move_between_samples, max_move_between_samples); + bool is_outside = move_out_expolys(get_collision(next_radius,layer_nr_next), candidate_vertex, max_move_between_samples, max_move_between_samples); if (is_outside) { direction_to_outer = candidate_vertex - node.position; dist2_to_outer = vsize2_with_unscale(direction_to_outer); @@ -2733,8 +2784,11 @@ void TreeSupport::drop_nodes(std::vector>& contact_nod SupportNode * next_node = m_ts_data->create_node(next_layer_vertex, node.distance_to_top + 1, layer_nr_next, node.support_roof_layers_below - 1, to_buildplate, p_node, print_z_next, height_next); get_max_move_dist(next_node); + m_ts_data->m_mutex.lock(); contact_nodes[layer_nr_next].push_back(next_node); + m_ts_data->m_mutex.unlock(); } + ); } #ifdef SUPPORT_TREE_DEBUG_TO_SVG @@ -2833,8 +2887,6 @@ void TreeSupport::smooth_nodes(std::vector> &contact_ const int iterations = 100; for (size_t k = 0; k < iterations; k++) { for (size_t i = 1; i < pts.size() - 1; i++) { - size_t i2 = i >= 2 ? i - 2 : 0; - size_t i3 = i < pts.size() - 2 ? i + 2 : pts.size() - 1; Point pt = ( pts[i - 1] + pts[i] + pts[i + 1] ) / 3; pts1[i] = pt; radii1[i] = (radii[i - 1] + radii[i] + radii[i + 1] ) / 3; @@ -3325,7 +3377,7 @@ const ExPolygons& TreeSupportData::calculate_avoidance(const RadiusLayerPair& ke { const auto& radius = key.radius; const auto& layer_nr = key.layer_nr; - BOOST_LOG_TRIVIAL(debug) << "calculate_avoidance on radius=" << radius << ", layer=" << layer_nr<<", recursion="<