mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-31 20:51:12 -06: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
	
	 Arthur
						Arthur