mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-11-02 20:51:23 -07:00 
			
		
		
		
	ENH: ease removal of tree supports
Previously tree supports are harder to remove than normal supports. We learn from normal supports and improve the gap between object and supports. Jira: STUDIO-3530 Change-Id: I229a7b869b334bdf4c5aba96c9450213b83457f2
This commit is contained in:
		
							parent
							
								
									73059c79af
								
							
						
					
					
						commit
						04bfe7e405
					
				
					 4 changed files with 128 additions and 38 deletions
				
			
		| 
						 | 
				
			
			@ -196,6 +196,40 @@ public:
 | 
			
		|||
    //BBS: this function calculate the maximum void grid area of sparse infill of this layer. Just estimated value
 | 
			
		||||
    coordf_t get_sparse_infill_max_void_area();
 | 
			
		||||
 | 
			
		||||
    // FN_HIGHER_EQUAL: the provided object pointer has a Z value >= of an internal threshold.
 | 
			
		||||
    // Find the first item with Z value >= of an internal threshold of fn_higher_equal.
 | 
			
		||||
    // If no vec item with Z value >= of an internal threshold of fn_higher_equal is found, return vec.size()
 | 
			
		||||
    // If the initial idx is size_t(-1), then use binary search.
 | 
			
		||||
    // Otherwise search linearly upwards.
 | 
			
		||||
    template<typename IteratorType, typename IndexType, typename FN_HIGHER_EQUAL>
 | 
			
		||||
    static IndexType idx_higher_or_equal(IteratorType begin, IteratorType end, IndexType idx, FN_HIGHER_EQUAL fn_higher_equal)
 | 
			
		||||
    {
 | 
			
		||||
        auto size = int(end - begin);
 | 
			
		||||
        if (size == 0) {
 | 
			
		||||
            idx = 0;
 | 
			
		||||
            }
 | 
			
		||||
        else if (idx == IndexType(-1)) {
 | 
			
		||||
            // First of the batch of layers per thread pool invocation. Use binary search.
 | 
			
		||||
            int idx_low = 0;
 | 
			
		||||
            int idx_high = std::max(0, size - 1);
 | 
			
		||||
            while (idx_low + 1 < idx_high) {
 | 
			
		||||
                int idx_mid = (idx_low + idx_high) / 2;
 | 
			
		||||
                if (fn_higher_equal(begin[idx_mid]))
 | 
			
		||||
                    idx_high = idx_mid;
 | 
			
		||||
                else
 | 
			
		||||
                    idx_low = idx_mid;
 | 
			
		||||
                }
 | 
			
		||||
            idx = fn_higher_equal(begin[idx_low]) ? idx_low :
 | 
			
		||||
                (fn_higher_equal(begin[idx_high]) ? idx_high : size);
 | 
			
		||||
            }
 | 
			
		||||
        else {
 | 
			
		||||
            // For the other layers of this batch of layers, search incrementally, which is cheaper than the binary search.
 | 
			
		||||
            while (int(idx) < size && !fn_higher_equal(begin[idx]))
 | 
			
		||||
                ++idx;
 | 
			
		||||
            }
 | 
			
		||||
        return idx;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    friend class PrintObject;
 | 
			
		||||
    friend std::vector<Layer*> new_layers(PrintObject*, const std::vector<coordf_t>&);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2834,41 +2834,10 @@ PrintObjectSupportMaterial::MyLayersPtr PrintObjectSupportMaterial::bottom_conta
 | 
			
		|||
    return bottom_contacts;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FN_HIGHER_EQUAL: the provided object pointer has a Z value >= of an internal threshold.
 | 
			
		||||
// Find the first item with Z value >= of an internal threshold of fn_higher_equal.
 | 
			
		||||
// If no vec item with Z value >= of an internal threshold of fn_higher_equal is found, return vec.size()
 | 
			
		||||
// If the initial idx is size_t(-1), then use binary search.
 | 
			
		||||
// Otherwise search linearly upwards.
 | 
			
		||||
template<typename IteratorType, typename IndexType, typename FN_HIGHER_EQUAL>
 | 
			
		||||
IndexType idx_higher_or_equal(IteratorType begin, IteratorType end, IndexType idx, FN_HIGHER_EQUAL fn_higher_equal)
 | 
			
		||||
{
 | 
			
		||||
    auto size = int(end - begin);
 | 
			
		||||
    if (size == 0) {
 | 
			
		||||
        idx = 0;
 | 
			
		||||
    } else if (idx == IndexType(-1)) {
 | 
			
		||||
        // First of the batch of layers per thread pool invocation. Use binary search.
 | 
			
		||||
        int idx_low  = 0;
 | 
			
		||||
        int idx_high = std::max(0, size - 1);
 | 
			
		||||
        while (idx_low + 1 < idx_high) {
 | 
			
		||||
            int idx_mid  = (idx_low + idx_high) / 2;
 | 
			
		||||
            if (fn_higher_equal(begin[idx_mid]))
 | 
			
		||||
                idx_high = idx_mid;
 | 
			
		||||
            else
 | 
			
		||||
                idx_low  = idx_mid;
 | 
			
		||||
        }
 | 
			
		||||
        idx =  fn_higher_equal(begin[idx_low])  ? idx_low  :
 | 
			
		||||
              (fn_higher_equal(begin[idx_high]) ? idx_high : size);
 | 
			
		||||
    } else {
 | 
			
		||||
        // For the other layers of this batch of layers, search incrementally, which is cheaper than the binary search.
 | 
			
		||||
        while (int(idx) < size && ! fn_higher_equal(begin[idx]))
 | 
			
		||||
            ++ idx;
 | 
			
		||||
    }
 | 
			
		||||
    return idx;
 | 
			
		||||
}
 | 
			
		||||
template<typename T, typename IndexType, typename FN_HIGHER_EQUAL>
 | 
			
		||||
IndexType idx_higher_or_equal(const std::vector<T>& vec, IndexType idx, FN_HIGHER_EQUAL fn_higher_equal)
 | 
			
		||||
{
 | 
			
		||||
    return idx_higher_or_equal(vec.begin(), vec.end(), idx, fn_higher_equal);
 | 
			
		||||
    return Layer::idx_higher_or_equal(vec.begin(), vec.end(), idx, fn_higher_equal);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FN_LOWER_EQUAL: the provided object pointer has a Z value <= of an internal threshold.
 | 
			
		||||
| 
						 | 
				
			
			@ -3353,7 +3322,7 @@ void PrintObjectSupportMaterial::trim_support_layers_by_object(
 | 
			
		|||
                assert(! support_layer.polygons.empty() && support_layer.print_z >= m_slicing_params.raft_contact_top_z + EPSILON);
 | 
			
		||||
                // Find the overlapping object layers including the extra above / below gap.
 | 
			
		||||
                coordf_t z_threshold = support_layer.bottom_print_z() - gap_extra_below + EPSILON;
 | 
			
		||||
                idx_object_layer_overlapping = idx_higher_or_equal(
 | 
			
		||||
                idx_object_layer_overlapping = Layer::idx_higher_or_equal(
 | 
			
		||||
                    object.layers().begin(), object.layers().end(), idx_object_layer_overlapping,
 | 
			
		||||
                    [z_threshold](const Layer *layer){ return layer->print_z >= z_threshold; });
 | 
			
		||||
                // Collect all the object layers intersecting with this layer.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1959,7 +1959,8 @@ coordf_t TreeSupport::calc_branch_radius(coordf_t base_radius, coordf_t mm_to_to
 | 
			
		|||
    return radius;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ExPolygons avoid_object_remove_extra_small_parts(ExPolygons &expolys, const ExPolygons &avoid_region) {
 | 
			
		||||
template<typename RegionType> // RegionType could be ExPolygons or Polygons
 | 
			
		||||
ExPolygons avoid_object_remove_extra_small_parts(ExPolygons &expolys, const RegionType&avoid_region) {
 | 
			
		||||
    ExPolygons expolys_out;
 | 
			
		||||
    for (auto expoly : expolys) {
 | 
			
		||||
        auto  expolys_avoid = diff_ex(expoly, avoid_region);
 | 
			
		||||
| 
						 | 
				
			
			@ -1977,6 +1978,82 @@ ExPolygons avoid_object_remove_extra_small_parts(ExPolygons &expolys, const ExPo
 | 
			
		|||
    return expolys_out;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Polygons TreeSupport::get_trim_support_regions(
 | 
			
		||||
    const PrintObject& object,
 | 
			
		||||
    SupportLayer* support_layer_ptr,
 | 
			
		||||
    const coordf_t       gap_extra_above,
 | 
			
		||||
    const coordf_t       gap_extra_below,
 | 
			
		||||
    const coordf_t       gap_xy)
 | 
			
		||||
{
 | 
			
		||||
    static const double sharp_tail_xy_gap = 0.2f;
 | 
			
		||||
    static const double no_overlap_xy_gap = 0.2f;
 | 
			
		||||
    double gap_xy_scaled = scale_(gap_xy);
 | 
			
		||||
    SupportLayer& support_layer = *support_layer_ptr;
 | 
			
		||||
    auto m_print_config = object.print()->config();
 | 
			
		||||
 | 
			
		||||
    size_t idx_object_layer_overlapping = size_t(-1);
 | 
			
		||||
 | 
			
		||||
    auto is_layers_overlap = [](const SupportLayer& support_layer, const Layer& object_layer, coordf_t bridging_height = 0.f) -> bool {
 | 
			
		||||
        if (std::abs(support_layer.print_z - object_layer.print_z) < EPSILON)
 | 
			
		||||
            return true;
 | 
			
		||||
 | 
			
		||||
        coordf_t object_lh = bridging_height > EPSILON ? bridging_height : object_layer.height;
 | 
			
		||||
        if (support_layer.print_z < object_layer.print_z && support_layer.print_z > object_layer.print_z - object_lh)
 | 
			
		||||
            return true;
 | 
			
		||||
 | 
			
		||||
        if (support_layer.print_z > object_layer.print_z && support_layer.bottom_z() < object_layer.print_z - EPSILON)
 | 
			
		||||
            return true;
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
    // Find the overlapping object layers including the extra above / below gap.
 | 
			
		||||
    coordf_t z_threshold = support_layer.bottom_z() - gap_extra_below + EPSILON;
 | 
			
		||||
    idx_object_layer_overlapping = Layer::idx_higher_or_equal(
 | 
			
		||||
        object.layers().begin(), object.layers().end(), idx_object_layer_overlapping,
 | 
			
		||||
        [z_threshold](const Layer* layer) { return layer->print_z >= z_threshold; });
 | 
			
		||||
    // Collect all the object layers intersecting with this layer.
 | 
			
		||||
    Polygons polygons_trimming;
 | 
			
		||||
    size_t i = idx_object_layer_overlapping;
 | 
			
		||||
    for (; i < object.layers().size(); ++i) {
 | 
			
		||||
        const Layer& object_layer = *object.layers()[i];
 | 
			
		||||
        if (object_layer.bottom_z() > support_layer.print_z + gap_extra_above - EPSILON)
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        bool is_overlap = is_layers_overlap(support_layer, object_layer);
 | 
			
		||||
        for (const ExPolygon& expoly : object_layer.lslices) {
 | 
			
		||||
            // BBS
 | 
			
		||||
            bool is_sharptail = !intersection_ex({ expoly }, object_layer.sharp_tails).empty();
 | 
			
		||||
            coordf_t trimming_offset = is_sharptail ? scale_(sharp_tail_xy_gap) :
 | 
			
		||||
                is_overlap ? gap_xy_scaled :
 | 
			
		||||
                scale_(no_overlap_xy_gap);
 | 
			
		||||
            polygons_append(polygons_trimming, offset({ expoly }, trimming_offset, SUPPORT_SURFACES_OFFSET_PARAMETERS));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    if (!m_slicing_params.soluble_interface && m_object_config->thick_bridges) {
 | 
			
		||||
        // Collect all bottom surfaces, which will be extruded with a bridging flow.
 | 
			
		||||
        for (; i < object.layers().size(); ++i) {
 | 
			
		||||
            const Layer& object_layer = *object.layers()[i];
 | 
			
		||||
            bool some_region_overlaps = false;
 | 
			
		||||
            for (LayerRegion* region : object_layer.regions()) {
 | 
			
		||||
                coordf_t bridging_height = region->region().bridging_height_avg(m_print_config);
 | 
			
		||||
                if (object_layer.print_z - bridging_height > support_layer.print_z + gap_extra_above - EPSILON)
 | 
			
		||||
                    break;
 | 
			
		||||
                some_region_overlaps = true;
 | 
			
		||||
 | 
			
		||||
                bool is_overlap = is_layers_overlap(support_layer, object_layer, bridging_height);
 | 
			
		||||
                coordf_t trimming_offset = is_overlap ? gap_xy_scaled : scale_(no_overlap_xy_gap);
 | 
			
		||||
                polygons_append(polygons_trimming,
 | 
			
		||||
                    offset(region->fill_surfaces.filter_by_type(stBottomBridge), trimming_offset, SUPPORT_SURFACES_OFFSET_PARAMETERS));
 | 
			
		||||
                }
 | 
			
		||||
            if (!some_region_overlaps)
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    return polygons_trimming;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void TreeSupport::draw_circles(const std::vector<std::vector<Node*>>& contact_nodes)
 | 
			
		||||
{
 | 
			
		||||
    const PrintObjectConfig &config = m_object->config();
 | 
			
		||||
| 
						 | 
				
			
			@ -2171,7 +2248,8 @@ void TreeSupport::draw_circles(const std::vector<std::vector<Node*>>& contact_no
 | 
			
		|||
                roof_1st_layer = std::move(offset2_ex(roof_1st_layer, contact_dist_scaled, -contact_dist_scaled));
 | 
			
		||||
 | 
			
		||||
                // avoid object
 | 
			
		||||
                auto avoid_region_interface = m_ts_data->get_collision(m_ts_data->m_xy_distance, layer_nr);
 | 
			
		||||
                //ExPolygons avoid_region_interface = m_ts_data->get_collision(m_ts_data->m_xy_distance, layer_nr);
 | 
			
		||||
                Polygons avoid_region_interface = get_trim_support_regions(*m_object, ts_layer, m_slicing_params.gap_object_support, m_slicing_params.gap_support_object, m_ts_data->m_xy_distance);
 | 
			
		||||
                if (has_circle_node) {
 | 
			
		||||
                    roof_areas = avoid_object_remove_extra_small_parts(roof_areas, avoid_region_interface);
 | 
			
		||||
                    roof_1st_layer = avoid_object_remove_extra_small_parts(roof_1st_layer, avoid_region_interface);
 | 
			
		||||
| 
						 | 
				
			
			@ -2248,7 +2326,7 @@ void TreeSupport::draw_circles(const std::vector<std::vector<Node*>>& contact_no
 | 
			
		|||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
#if 1
 | 
			
		||||
 | 
			
		||||
        if (with_lightning_infill)
 | 
			
		||||
        {
 | 
			
		||||
            const bool global_lightning_infill = true;
 | 
			
		||||
| 
						 | 
				
			
			@ -2320,7 +2398,7 @@ void TreeSupport::draw_circles(const std::vector<std::vector<Node*>>& contact_no
 | 
			
		|||
        else if (!with_infill) {
 | 
			
		||||
            // move the holes to contour so they can be well supported
 | 
			
		||||
 | 
			
		||||
        // check if poly's contour intersects with expoly's contour
 | 
			
		||||
            // check if poly's contour intersects with expoly's contour
 | 
			
		||||
            auto intersects_contour = [](Polygon poly, ExPolygon expoly, Point& pt_on_poly, Point& pt_on_expoly, Point& pt_far_on_poly, float dist_thresh = 0.01) {
 | 
			
		||||
                float min_dist = std::numeric_limits<float>::max();
 | 
			
		||||
                float max_dist = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -2433,7 +2511,7 @@ void TreeSupport::draw_circles(const std::vector<std::vector<Node*>>& contact_no
 | 
			
		|||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifdef SUPPORT_TREE_DEBUG_TO_SVG
 | 
			
		||||
    for (int layer_nr = m_object->layer_count() - 1; layer_nr >= 0; layer_nr--) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,6 +20,7 @@ namespace Slic3r
 | 
			
		|||
{
 | 
			
		||||
class PrintObject;
 | 
			
		||||
class TreeSupport;
 | 
			
		||||
class SupportLayer;
 | 
			
		||||
 | 
			
		||||
struct LayerHeightData
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -494,6 +495,14 @@ private:
 | 
			
		|||
    Polygons contact_nodes_to_polygon(const std::vector<Node*>& contact_nodes, Polygons layer_contours, int layer_nr, std::vector<double>& radiis, std::vector<bool>& is_interface);
 | 
			
		||||
    coordf_t calc_branch_radius(coordf_t base_radius, size_t layers_to_top, size_t tip_layers, double diameter_angle_scale_factor);
 | 
			
		||||
    coordf_t calc_branch_radius(coordf_t base_radius, coordf_t mm_to_top, double diameter_angle_scale_factor);
 | 
			
		||||
 | 
			
		||||
    // similar to SupportMaterial::trim_support_layers_by_object
 | 
			
		||||
    Polygons get_trim_support_regions(
 | 
			
		||||
        const PrintObject& object,
 | 
			
		||||
        SupportLayer* support_layer_ptr,
 | 
			
		||||
        const coordf_t       gap_extra_above,
 | 
			
		||||
        const coordf_t       gap_extra_below,
 | 
			
		||||
        const coordf_t       gap_xy);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue