mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-11-02 20:51:23 -07:00 
			
		
		
		
	Reworked connection of infill lines to perimeter lines.
Added a new "infill_anchor" parameter.
This commit is contained in:
		
							parent
							
								
									84693a5810
								
							
						
					
					
						commit
						4280fdb5f2
					
				
					 12 changed files with 383 additions and 470 deletions
				
			
		| 
						 | 
				
			
			@ -37,6 +37,8 @@ struct SurfaceFillParams
 | 
			
		|||
    bool        	dont_connect = false;
 | 
			
		||||
    // Don't adjust spacing to fill the space evenly.
 | 
			
		||||
    bool        	dont_adjust = false;
 | 
			
		||||
    // Length of the infill anchor along the perimeter line.
 | 
			
		||||
    float 			anchor_length = std::numeric_limits<float>::max();
 | 
			
		||||
 | 
			
		||||
    // width, height of extrusion, nozzle diameter, is bridge
 | 
			
		||||
    // For the output, for fill generator.
 | 
			
		||||
| 
						 | 
				
			
			@ -67,6 +69,7 @@ struct SurfaceFillParams
 | 
			
		|||
		RETURN_COMPARE_NON_EQUAL(density);
 | 
			
		||||
		RETURN_COMPARE_NON_EQUAL_TYPED(unsigned, dont_connect);
 | 
			
		||||
		RETURN_COMPARE_NON_EQUAL_TYPED(unsigned, dont_adjust);
 | 
			
		||||
		RETURN_COMPARE_NON_EQUAL(anchor_length);
 | 
			
		||||
		RETURN_COMPARE_NON_EQUAL(flow.width);
 | 
			
		||||
		RETURN_COMPARE_NON_EQUAL(flow.height);
 | 
			
		||||
		RETURN_COMPARE_NON_EQUAL(flow.nozzle_diameter);
 | 
			
		||||
| 
						 | 
				
			
			@ -85,6 +88,7 @@ struct SurfaceFillParams
 | 
			
		|||
				this->density   		== rhs.density   		&&
 | 
			
		||||
				this->dont_connect  	== rhs.dont_connect 	&&
 | 
			
		||||
				this->dont_adjust   	== rhs.dont_adjust 		&&
 | 
			
		||||
				this->anchor_length		== rhs.anchor_length    &&
 | 
			
		||||
				this->flow 				== rhs.flow 			&&
 | 
			
		||||
				this->extrusion_role	== rhs.extrusion_role;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -115,16 +119,17 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
 | 
			
		|||
	        if (surface.surface_type == stInternalVoid)
 | 
			
		||||
	        	has_internal_voids = true;
 | 
			
		||||
	        else {
 | 
			
		||||
		        const PrintRegionConfig ®ion_config = layerm.region()->config();
 | 
			
		||||
		        FlowRole extrusion_role = surface.is_top() ? frTopSolidInfill : (surface.is_solid() ? frSolidInfill : frInfill);
 | 
			
		||||
		        bool     is_bridge 	    = layer.id() > 0 && surface.is_bridge();
 | 
			
		||||
		        params.extruder 	 = layerm.region()->extruder(extrusion_role);
 | 
			
		||||
		        params.pattern 		 = layerm.region()->config().fill_pattern.value;
 | 
			
		||||
		        params.density       = float(layerm.region()->config().fill_density);
 | 
			
		||||
		        params.pattern 		 = region_config.fill_pattern.value;
 | 
			
		||||
		        params.density       = float(region_config.fill_density);
 | 
			
		||||
 | 
			
		||||
		        if (surface.is_solid()) {
 | 
			
		||||
		            params.density = 100.f;
 | 
			
		||||
		            params.pattern = (surface.is_external() && ! is_bridge) ? 
 | 
			
		||||
						(surface.is_top() ? layerm.region()->config().top_fill_pattern.value : layerm.region()->config().bottom_fill_pattern.value) :
 | 
			
		||||
						(surface.is_top() ? region_config.top_fill_pattern.value : region_config.bottom_fill_pattern.value) :
 | 
			
		||||
		                ipRectilinear;
 | 
			
		||||
		        } else if (params.density <= 0)
 | 
			
		||||
		            continue;
 | 
			
		||||
| 
						 | 
				
			
			@ -136,7 +141,7 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
 | 
			
		|||
		                    (surface.is_top() ? erTopSolidInfill : erSolidInfill) :
 | 
			
		||||
		                    erInternalInfill);
 | 
			
		||||
		        params.bridge_angle = float(surface.bridge_angle);
 | 
			
		||||
		        params.angle 		= float(Geometry::deg2rad(layerm.region()->config().fill_angle.value));
 | 
			
		||||
		        params.angle 		= float(Geometry::deg2rad(region_config.fill_angle.value));
 | 
			
		||||
		        
 | 
			
		||||
		        // calculate the actual flow we'll be using for this infill
 | 
			
		||||
		        params.flow = layerm.region()->flow(
 | 
			
		||||
| 
						 | 
				
			
			@ -165,6 +170,10 @@ std::vector<SurfaceFill> group_fills(const Layer &layer)
 | 
			
		|||
		        } else
 | 
			
		||||
		            params.spacing = params.flow.spacing();
 | 
			
		||||
 | 
			
		||||
		        params.anchor_length = float(region_config.infill_anchor);
 | 
			
		||||
		        if (region_config.infill_anchor.percent)
 | 
			
		||||
		        	params.anchor_length *= 0.01 * params.spacing;
 | 
			
		||||
 | 
			
		||||
		        auto it_params = set_surface_params.find(params);
 | 
			
		||||
		        if (it_params == set_surface_params.end())
 | 
			
		||||
		        	it_params = set_surface_params.insert(it_params, params);
 | 
			
		||||
| 
						 | 
				
			
			@ -367,8 +376,9 @@ void Layer::make_fills(FillAdaptive::Octree* adaptive_fill_octree, FillAdaptive:
 | 
			
		|||
 | 
			
		||||
        // apply half spacing using this flow's own spacing and generate infill
 | 
			
		||||
        FillParams params;
 | 
			
		||||
        params.density 		= float(0.01 * surface_fill.params.density);
 | 
			
		||||
        params.dont_adjust 	= surface_fill.params.dont_adjust; // false
 | 
			
		||||
        params.density 		 = float(0.01 * surface_fill.params.density);
 | 
			
		||||
        params.dont_adjust 	 = surface_fill.params.dont_adjust; // false
 | 
			
		||||
        params.anchor_length = surface_fill.params.anchor_length;
 | 
			
		||||
 | 
			
		||||
        for (ExPolygon &expoly : surface_fill.expolygons) {
 | 
			
		||||
			// Spacing is modified by the filler to indicate adjustments. Reset it for each expolygon.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -639,7 +639,6 @@ static inline Intersection* get_nearest_intersection(std::vector<std::pair<Inter
 | 
			
		|||
// translated in the direction of the intersection line (intersection.intersect_line).
 | 
			
		||||
static Line create_offset_line(Line offset_line, const Intersection &intersection, const double scaled_offset)
 | 
			
		||||
{
 | 
			
		||||
    // 50% overlap of the extrusion lines to achieve strong bonding.
 | 
			
		||||
    offset_line.translate((perp(intersection.closest_line->vector().cast<double>().normalized()) * (intersection.left ? scaled_offset : - scaled_offset)).cast<coord_t>());
 | 
			
		||||
    // Extend the line by a small value to guarantee a collision with adjacent lines
 | 
			
		||||
    offset_line.extend(coord_t(scaled_offset * 1.16)); // / cos(PI/6)
 | 
			
		||||
| 
						 | 
				
			
			@ -767,8 +766,10 @@ static Polylines connect_lines_using_hooks(Polylines &&lines, const ExPolygon &b
 | 
			
		|||
    lines_src.reserve(lines.size());
 | 
			
		||||
    std::transform(lines.begin(), lines.end(), std::back_inserter(lines_src), [](const Line& l) { return Polyline{ l.a, l.b }; });
 | 
			
		||||
 | 
			
		||||
    const float scaled_offset           = float(scale_(spacing) * 0.7); // 30% overlap
 | 
			
		||||
    const float scaled_trim_distance    = float(scale_(spacing) * 0.5 * 0.75); // 25% overlap
 | 
			
		||||
    // 19% overlap, slightly lower than the allowed overlap in Fill::connect_infill()
 | 
			
		||||
    const float scaled_offset           = float(scale_(spacing) * 0.81);
 | 
			
		||||
    // 25% overlap
 | 
			
		||||
    const float scaled_trim_distance    = float(scale_(spacing) * 0.5 * 0.75);
 | 
			
		||||
 | 
			
		||||
    // Keeping the vector of closest points outside the loop, so the vector does not need to be reallocated.
 | 
			
		||||
    std::vector<std::pair<rtree_segment_t, size_t>> closest;
 | 
			
		||||
| 
						 | 
				
			
			@ -1199,9 +1200,6 @@ static Polylines connect_lines_using_hooks(Polylines &&lines, const ExPolygon &b
 | 
			
		|||
    return polylines_out;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//coord_t get_hook_length(const double spacing) { return coord_t(scale_(spacing)) * 2; }
 | 
			
		||||
coord_t get_hook_length(const double spacing) { return coord_t(scale_(spacing)) * 5; }
 | 
			
		||||
 | 
			
		||||
#ifndef NDEBUG
 | 
			
		||||
bool has_no_collinear_lines(const Polylines &polylines)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -1323,7 +1321,8 @@ void Filler::_fill_surface_single(
 | 
			
		|||
    }
 | 
			
		||||
#endif /* ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT */
 | 
			
		||||
 | 
			
		||||
    coord_t   hook_length = get_hook_length(this->spacing);
 | 
			
		||||
    const auto hook_length = coord_t(std::min(scale_(this->spacing * 5), scale_(params.anchor_length)));
 | 
			
		||||
 | 
			
		||||
    Polylines all_polylines_with_hooks = all_polylines.size() > 1 ? connect_lines_using_hooks(std::move(all_polylines), expolygon, this->spacing, hook_length) : std::move(all_polylines);
 | 
			
		||||
 | 
			
		||||
#ifdef ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT
 | 
			
		||||
| 
						 | 
				
			
			@ -1336,7 +1335,7 @@ void Filler::_fill_surface_single(
 | 
			
		|||
    if (params.dont_connect || all_polylines_with_hooks.size() <= 1)
 | 
			
		||||
        append(polylines_out, std::move(all_polylines_with_hooks));
 | 
			
		||||
    else
 | 
			
		||||
        connect_infill(chain_polylines(std::move(all_polylines_with_hooks)), expolygon, polylines_out, this->spacing, params, hook_length);
 | 
			
		||||
        connect_infill(chain_polylines(std::move(all_polylines_with_hooks)), expolygon, polylines_out, this->spacing, params);
 | 
			
		||||
 | 
			
		||||
#ifdef ADAPTIVE_CUBIC_INFILL_DEBUG_OUTPUT
 | 
			
		||||
    {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
				
			
			@ -37,6 +37,9 @@ struct FillParams
 | 
			
		|||
    // Fill density, fraction in <0, 1>
 | 
			
		||||
    float       density 		{ 0.f };
 | 
			
		||||
 | 
			
		||||
    // Length of an infill anchor along the perimeter.
 | 
			
		||||
    float       anchor_length   { std::numeric_limits<float>::max() };
 | 
			
		||||
 | 
			
		||||
    // Don't connect the fill lines around the inner perimeter.
 | 
			
		||||
    bool        dont_connect 	{ false };
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -124,9 +127,9 @@ protected:
 | 
			
		|||
    virtual std::pair<float, Point> _infill_direction(const Surface *surface) const;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    static void connect_infill(Polylines &&infill_ordered, const ExPolygon &boundary, Polylines &polylines_out, const double spacing, const FillParams ¶ms, const int hook_length = 0);
 | 
			
		||||
    static void connect_infill(Polylines &&infill_ordered, const Polygons &boundary, const BoundingBox& bbox, Polylines &polylines_out, const double spacing, const FillParams ¶ms, const int hook_length = 0);
 | 
			
		||||
    static void connect_infill(Polylines &&infill_ordered, const std::vector<const Polygon*> &boundary, const BoundingBox &bbox, Polylines &polylines_out, double spacing, const FillParams ¶ms, const int hook_length = 0);
 | 
			
		||||
    static void connect_infill(Polylines &&infill_ordered, const ExPolygon &boundary, Polylines &polylines_out, const double spacing, const FillParams ¶ms);
 | 
			
		||||
    static void connect_infill(Polylines &&infill_ordered, const Polygons &boundary, const BoundingBox& bbox, Polylines &polylines_out, const double spacing, const FillParams ¶ms);
 | 
			
		||||
    static void connect_infill(Polylines &&infill_ordered, const std::vector<const Polygon*> &boundary, const BoundingBox &bbox, Polylines &polylines_out, double spacing, const FillParams ¶ms);
 | 
			
		||||
 | 
			
		||||
    static coord_t  _adjust_solid_spacing(const coord_t width, const coord_t distance);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2778,6 +2778,7 @@ bool FillRectilinear2::fill_surface_by_multilines(const Surface *surface, FillPa
 | 
			
		|||
        return true;
 | 
			
		||||
 | 
			
		||||
    Polylines fill_lines;
 | 
			
		||||
    coord_t line_width   = coord_t(scale_(this->spacing));
 | 
			
		||||
    coord_t line_spacing = coord_t(scale_(this->spacing) / params.density);
 | 
			
		||||
    std::pair<float, Point> rotate_vector = this->_infill_direction(surface);
 | 
			
		||||
    for (const SweepParams &sweep : sweep_params) {
 | 
			
		||||
| 
						 | 
				
			
			@ -2787,6 +2788,9 @@ bool FillRectilinear2::fill_surface_by_multilines(const Surface *surface, FillPa
 | 
			
		|||
        double angle = rotate_vector.first + sweep.angle_base;
 | 
			
		||||
        ExPolygonWithOffset poly_with_offset(poly_with_offset_base, - angle);
 | 
			
		||||
        BoundingBox bounding_box = poly_with_offset.bounding_box_src();
 | 
			
		||||
        // Don't produce infill lines, which fully overlap with the infill perimeter.
 | 
			
		||||
        coord_t     x_min = bounding_box.min.x() + line_width + coord_t(SCALED_EPSILON);
 | 
			
		||||
        coord_t     x_max = bounding_box.max.x() - line_width - coord_t(SCALED_EPSILON);
 | 
			
		||||
        // extend bounding box so that our pattern will be aligned with other layers
 | 
			
		||||
        // Transform the reference point to the rotated coordinate system.
 | 
			
		||||
        Point refpt = rotate_vector.second.rotated(- angle);
 | 
			
		||||
| 
						 | 
				
			
			@ -2800,20 +2804,23 @@ bool FillRectilinear2::fill_surface_by_multilines(const Surface *surface, FillPa
 | 
			
		|||
        const size_t n_vlines = (bounding_box.max.x() - bounding_box.min.x() + line_spacing - 1) / line_spacing;
 | 
			
		||||
        const double cos_a    = cos(angle);
 | 
			
		||||
        const double sin_a    = sin(angle);
 | 
			
		||||
        for (const SegmentedIntersectionLine &vline : slice_region_by_vertical_lines(poly_with_offset, n_vlines, bounding_box.min.x(), line_spacing)) {
 | 
			
		||||
            for (auto it = vline.intersections.begin(); it != vline.intersections.end();) {
 | 
			
		||||
                auto it_low  = it ++;
 | 
			
		||||
                assert(it_low->type == SegmentIntersection::OUTER_LOW);
 | 
			
		||||
                if (it_low->type != SegmentIntersection::OUTER_LOW)
 | 
			
		||||
                    continue;
 | 
			
		||||
                auto it_high = it;
 | 
			
		||||
                assert(it_high->type == SegmentIntersection::OUTER_HIGH);
 | 
			
		||||
                if (it_high->type == SegmentIntersection::OUTER_HIGH) {
 | 
			
		||||
                    fill_lines.emplace_back(Point(vline.pos, it_low->pos()).rotated(cos_a, sin_a), Point(vline.pos, it_high->pos()).rotated(cos_a, sin_a));
 | 
			
		||||
                    ++ it;
 | 
			
		||||
        for (const SegmentedIntersectionLine &vline : slice_region_by_vertical_lines(poly_with_offset, n_vlines, bounding_box.min.x(), line_spacing))
 | 
			
		||||
            if (vline.pos > x_min) {
 | 
			
		||||
                if (vline.pos >= x_max)
 | 
			
		||||
                    break;
 | 
			
		||||
                for (auto it = vline.intersections.begin(); it != vline.intersections.end();) {
 | 
			
		||||
                    auto it_low  = it ++;
 | 
			
		||||
                    assert(it_low->type == SegmentIntersection::OUTER_LOW);
 | 
			
		||||
                    if (it_low->type != SegmentIntersection::OUTER_LOW)
 | 
			
		||||
                        continue;
 | 
			
		||||
                    auto it_high = it;
 | 
			
		||||
                    assert(it_high->type == SegmentIntersection::OUTER_HIGH);
 | 
			
		||||
                    if (it_high->type == SegmentIntersection::OUTER_HIGH) {
 | 
			
		||||
                        fill_lines.emplace_back(Point(vline.pos, it_low->pos()).rotated(cos_a, sin_a), Point(vline.pos, it_high->pos()).rotated(cos_a, sin_a));
 | 
			
		||||
                        ++ it;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (fill_lines.size() > 1)
 | 
			
		||||
| 
						 | 
				
			
			@ -2821,11 +2828,8 @@ bool FillRectilinear2::fill_surface_by_multilines(const Surface *surface, FillPa
 | 
			
		|||
 | 
			
		||||
    if (params.dont_connect || fill_lines.size() <= 1)
 | 
			
		||||
        append(polylines_out, std::move(fill_lines));
 | 
			
		||||
    else {
 | 
			
		||||
//        coord_t hook_length = 0;
 | 
			
		||||
        coord_t hook_length = coord_t(scale_(this->spacing)) * 5;
 | 
			
		||||
        connect_infill(std::move(fill_lines), poly_with_offset_base.polygons_outer, get_extents(surface->expolygon.contour), polylines_out, this->spacing, params, hook_length);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
        connect_infill(std::move(fill_lines), poly_with_offset_base.polygons_outer, get_extents(surface->expolygon.contour), polylines_out, this->spacing, params);
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue