@@ -558,6 +558,124 @@ void LayerPlan::addExtrusionMove(
558558 last_planned_position_ = p.toPoint2LL ();
559559}
560560
561+ void LayerPlan::addExtrusionMoveWithGradualOverhang (
562+ const Point3LL& p,
563+ const GCodePathConfig& config,
564+ const SpaceFillType space_fill_type,
565+ const Ratio& flow,
566+ const Ratio width_factor,
567+ const bool spiralize,
568+ const Ratio speed_factor,
569+ const double fan_speed,
570+ const bool travel_to_z)
571+ {
572+ const auto add_extrusion_move = [&](const Point3LL& target, const Ratio& overhang_speed_factor = 1 .0_r)
573+ {
574+ addExtrusionMove (target, config, space_fill_type, flow, width_factor, spiralize, speed_factor * overhang_speed_factor, fan_speed, travel_to_z);
575+ };
576+
577+ if (overhang_masks_.empty () || ! last_planned_position_.has_value ())
578+ {
579+ // Unable to apply gradual overhanging (probably just disabled), just add the basic extrusion move
580+ add_extrusion_move (p);
581+ return ;
582+ }
583+
584+ // First, find the speed region where the segment starts
585+ const Point2LL start = last_planned_position_.value ();
586+ size_t actual_speed_region_index = overhang_masks_.size () - 1 ; // Default to last region, which is infinity and beyond
587+ for (const auto & [index, overhang_region] : overhang_masks_ | ranges::views::drop_last (1 ) | ranges::views::enumerate)
588+ {
589+ if (overhang_region.supported_region .inside (start, true ))
590+ {
591+ actual_speed_region_index = index;
592+ break ;
593+ }
594+ }
595+
596+ // Pre-calculate the intersections of the segment with all regions (except last one, you cannot intersect an infinite plane)
597+ const Point2LL end = p.toPoint2LL ();
598+ const Point2LL vector = end - start;
599+ std::vector<std::vector<float >> speed_regions_intersections;
600+ speed_regions_intersections.reserve (overhang_masks_.size () - 1 );
601+ for (const OverhangMask& overhang_region : overhang_masks_ | ranges::views::drop_last (1 ))
602+ {
603+ std::vector<float > intersections = overhang_region.supported_region .intersectionsWithSegment (start, end);
604+ ranges::sort (intersections);
605+ speed_regions_intersections.push_back (intersections);
606+ if (! intersections.empty ())
607+ {
608+ spdlog::debug (" coucou" );
609+ }
610+ }
611+
612+ const auto remove_previous_intersections = [&speed_regions_intersections](const float current_intersection)
613+ {
614+ for (std::vector<float >& intersections : speed_regions_intersections)
615+ {
616+ auto iterator = ranges::find_if (
617+ intersections,
618+ [¤t_intersection](const float next_intersection)
619+ {
620+ return next_intersection > current_intersection;
621+ });
622+
623+ intersections.erase (intersections.begin (), iterator);
624+ }
625+ };
626+
627+ // Now move along segment and split it where we cross speed regions
628+ while (true )
629+ {
630+ // First, see if we cross either the border or our current region (go out) or the border of the inner region (go in)
631+ auto get_first_intersection = [](const std::vector<float >* intersections) -> std::optional<float >
632+ {
633+ return intersections != nullptr && ! intersections->empty () ? std::make_optional (intersections->front ()) : std::nullopt ;
634+ };
635+
636+ std::vector<float >* intersections_current_region
637+ = actual_speed_region_index < speed_regions_intersections.size () ? &speed_regions_intersections[actual_speed_region_index] : nullptr ;
638+ const std::optional<float > first_intersection_current_region = get_first_intersection (intersections_current_region);
639+
640+ std::vector<float >* intersections_inner_region = actual_speed_region_index > 0 ? &speed_regions_intersections[actual_speed_region_index - 1 ] : nullptr ;
641+ const std::optional<float > first_intersection_inner_region = get_first_intersection (intersections_inner_region);
642+
643+ if (first_intersection_current_region.has_value () || first_intersection_inner_region.has_value ())
644+ {
645+ float intersection_parameter;
646+ size_t next_speed_region_index;
647+
648+ if (first_intersection_current_region.has_value ()
649+ && (! first_intersection_inner_region.has_value () || first_intersection_inner_region.value () > first_intersection_current_region.value ()))
650+ {
651+ // We crossed the border of the current region, which means we are getting out of it to an outer region
652+ intersection_parameter = first_intersection_current_region.value ();
653+ next_speed_region_index = actual_speed_region_index + 1 ;
654+ }
655+ else
656+ {
657+ // We crossed the border of the inner region, which means we are getting inside of it
658+ intersection_parameter = first_intersection_inner_region.value ();
659+ next_speed_region_index = actual_speed_region_index - 1 ;
660+ }
661+
662+ // Move to intersection at current region speed
663+ const Point2LL split_position = start + vector * intersection_parameter;
664+ add_extrusion_move (split_position, overhang_masks_[actual_speed_region_index].speed_ratio );
665+
666+ // Prepare for next move in different region
667+ actual_speed_region_index = next_speed_region_index;
668+ remove_previous_intersections (intersection_parameter);
669+ }
670+ else
671+ {
672+ // We cross no border, which means we can reach the end of the segment within the current speed region, so we are done
673+ add_extrusion_move (p, overhang_masks_[actual_speed_region_index].speed_ratio );
674+ return ;
675+ }
676+ }
677+ }
678+
561679template <class PathType >
562680void LayerPlan::addWipeTravel (const PathAdapter<PathType>& path, const coord_t wipe_distance, const bool backwards, const size_t start_index, const Point2LL& last_path_position)
563681{
@@ -732,8 +850,6 @@ void LayerPlan::addWallLine(
732850
733851 const coord_t min_bridge_line_len = settings.get <coord_t >(" bridge_wall_min_length" );
734852 const Ratio bridge_wall_coast = settings.get <Ratio>(" bridge_wall_coast" );
735- const Ratio overhang_speed_factor = settings.get <Ratio>(" wall_overhang_speed_factor" );
736- const auto overhang_speed_factors = settings.get <std::vector<int >>(" wall_overhang_speed_factors" );
737853
738854 Point3LL cur_point = p0;
739855
@@ -799,14 +915,14 @@ void LayerPlan::addWallLine(
799915 else
800916 {
801917 // no coasting required, just normal segment using non-bridge config
802- addExtrusionMove (
918+ addExtrusionMoveWithGradualOverhang (
803919 segment_end,
804920 default_config,
805921 SpaceFillType::Polygons,
806922 segment_flow,
807923 width_factor,
808924 spiralize,
809- segmentIsOnOverhang (p0, p1) ? overhang_speed_factor : speed_factor,
925+ speed_factor,
810926 GCodePathConfig::FAN_SPEED_DEFAULT,
811927 travel_to_z);
812928 }
@@ -816,14 +932,14 @@ void LayerPlan::addWallLine(
816932 else
817933 {
818934 // no coasting required, just normal segment using non-bridge config
819- addExtrusionMove (
935+ addExtrusionMoveWithGradualOverhang (
820936 segment_end,
821937 default_config,
822938 SpaceFillType::Polygons,
823939 segment_flow,
824940 width_factor,
825941 spiralize,
826- segmentIsOnOverhang (p0, p1) ? overhang_speed_factor : speed_factor,
942+ speed_factor,
827943 GCodePathConfig::FAN_SPEED_DEFAULT,
828944 travel_to_z);
829945 }
@@ -921,14 +1037,14 @@ void LayerPlan::addWallLine(
9211037 else if (bridge_wall_mask_.empty ())
9221038 {
9231039 // no bridges required
924- addExtrusionMove (
1040+ addExtrusionMoveWithGradualOverhang (
9251041 p1,
9261042 default_config,
9271043 SpaceFillType::Polygons,
9281044 flow,
9291045 width_factor,
9301046 spiralize,
931- segmentIsOnOverhang (p0, p1) ? overhang_speed_factor : speed_factor,
1047+ speed_factor,
9321048 GCodePathConfig::FAN_SPEED_DEFAULT,
9331049 travel_to_z);
9341050 }
@@ -1948,15 +2064,6 @@ void LayerPlan::addLinesInGivenOrder(
19482064 }
19492065}
19502066
1951- bool LayerPlan::segmentIsOnOverhang (const Point3LL& p0, const Point3LL& p1) const
1952- {
1953- // const OpenPolyline segment{ p0.toPoint2LL(), p1.toPoint2LL() };
1954- // const OpenLinesSet intersected_lines = overhang_mask_.intersection(OpenLinesSet{ segment });
1955- // return ! intersected_lines.empty() && (static_cast<double>(intersected_lines.length()) / segment.length()) > 0.5;
1956-
1957- return false ;
1958- }
1959-
19602067void LayerPlan::sendLineTo (const GCodePath& path, const Point3LL& position, const double extrude_speed)
19612068{
19622069 Application::getInstance ().communication_ ->sendLineTo (
0 commit comments