Skip to content

Commit 588a838

Browse files
committed
Improve micro-segment filtering
CURA-12352 The previous method (filtering intersections) could cause jumps between non-adjacent speed regions, causing the wrong speed to be applied. Now we filter the micro-segments after applying the speed regions, and also re-merge consecutive segments that have the same speed.
1 parent c468d03 commit 588a838

File tree

2 files changed

+86
-46
lines changed

2 files changed

+86
-46
lines changed

src/FffGcodeWriter.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3122,7 +3122,7 @@ bool FffGcodeWriter::processInsets(
31223122
std::vector<SpeedRegion> speed_regions;
31233123
speed_regions.reserve(overhang_angles_count + 2);
31243124

3125-
constexpr bool dont_chunk_first = false;
3125+
constexpr bool dont_chunk_first = false; // Never merge internal region in order to detect actual overhanging
31263126
speed_regions.push_back(SpeedRegion{ wall_overhang_angle, 1.0_r, dont_chunk_first }); // Initial internal region, always 100% speed factor
31273127

31283128
for (size_t angle_index = 1; angle_index <= overhang_angles_count; ++angle_index)

src/LayerPlan.cpp

Lines changed: 85 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,15 @@ GCodePath* LayerPlan::getLatestPathWithConfig(
5757
{
5858
return &paths.back();
5959
}
60-
paths.emplace_back(GCodePath{ .z_offset = z_offset,
61-
.config = config,
62-
.mesh = current_mesh_,
63-
.space_fill_type = space_fill_type,
64-
.flow = flow,
65-
.width_factor = width_factor,
66-
.spiralize = spiralize,
67-
.speed_factor = speed_factor });
60+
paths.emplace_back(
61+
GCodePath{ .z_offset = z_offset,
62+
.config = config,
63+
.mesh = current_mesh_,
64+
.space_fill_type = space_fill_type,
65+
.flow = flow,
66+
.width_factor = width_factor,
67+
.spiralize = spiralize,
68+
.speed_factor = speed_factor });
6869

6970
GCodePath* ret = &paths.back();
7071
ret->skip_agressive_merge_hint = mode_skip_agressive_merge_;
@@ -571,28 +572,29 @@ void LayerPlan::addExtrusionMoveWithGradualOverhang(
571572
const auto add_extrusion_move = [&](const Point3LL& target, const std::optional<size_t> speed_region_index = std::nullopt)
572573
{
573574
const Ratio overhang_speed_factor = speed_region_index.has_value() ? overhang_masks_[speed_region_index.value()].speed_ratio : 1.0_r;
575+
addExtrusionMove(target, config, space_fill_type, flow, width_factor, spiralize, speed_factor * overhang_speed_factor, fan_speed, travel_to_z);
576+
};
574577

575-
const bool is_overhanging = speed_region_index.has_value() && speed_region_index.value() > 0;
576-
578+
const auto update_is_overhanging = [this](const Point2LL& target, std::optional<Point2LL> current_position, const bool is_overhanging = false)
579+
{
577580
if (is_overhanging != currently_overhanging_)
578581
{
579582
max_overhang_length_ = std::max(current_overhang_length_, max_overhang_length_);
580583
current_overhang_length_ = 0;
581584
}
582585

583-
if (is_overhanging && last_planned_position_.has_value())
586+
if (is_overhanging && current_position.has_value())
584587
{
585-
current_overhang_length_ += vSize(target.toPoint2LL() - last_planned_position_.value());
588+
current_overhang_length_ += vSize(target - current_position.value());
586589
}
587590

588591
currently_overhanging_ = is_overhanging;
589-
590-
addExtrusionMove(target, config, space_fill_type, flow, width_factor, spiralize, speed_factor * overhang_speed_factor, fan_speed, travel_to_z);
591592
};
592593

593594
if (overhang_masks_.empty() || ! last_planned_position_.has_value())
594595
{
595596
// Unable to apply gradual overhanging (probably just disabled), just add the basic extrusion move
597+
update_is_overhanging(p.toPoint2LL(), last_planned_position_);
596598
add_extrusion_move(p);
597599
return;
598600
}
@@ -612,40 +614,12 @@ void LayerPlan::addExtrusionMoveWithGradualOverhang(
612614
// Pre-calculate the intersections of the segment with all regions (except last one, you cannot intersect an infinite plane)
613615
const Point2LL end = p.toPoint2LL();
614616
const Point2LL vector = end - start;
615-
const coord_t segment_length = vSize(vector);
616617
std::vector<std::vector<float>> speed_regions_intersections;
617618
speed_regions_intersections.reserve(overhang_masks_.size() - 1);
618619
for (const OverhangMask& overhang_region : overhang_masks_ | ranges::views::drop_last(1))
619620
{
620621
std::vector<float> intersections = overhang_region.supported_region.intersectionsWithSegment(start, end);
621622
ranges::sort(intersections);
622-
623-
// Avoid microsegments: Move intersections that are too close to the start or end of the segment slightly more to the center of the segment.
624-
for (float& intersection : intersections)
625-
{
626-
if (intersection * segment_length < MINIMUM_LINE_LENGTH)
627-
{
628-
intersection = MINIMUM_LINE_LENGTH / static_cast<float>(segment_length);
629-
}
630-
else if (intersection * segment_length > segment_length - MINIMUM_LINE_LENGTH)
631-
{
632-
intersection = (segment_length - MINIMUM_LINE_LENGTH) / static_cast<float>(segment_length);
633-
}
634-
}
635-
636-
// (Also) Avoid microsegments: Filter out pairs of intersections that are too close to each other.
637-
// This should be possible because the intersections happen in the same region.
638-
constexpr std::array<float, 1> dummy = { 2.0f };
639-
std::vector<float> temp_intersections;
640-
for (const auto& tup : ranges::views::concat(dummy, intersections, dummy) | ranges::views::sliding(3))
641-
{
642-
if (std::abs(tup[1] - tup[0]) * segment_length >= MINIMUM_LINE_LENGTH && std::abs(tup[2] - tup[1]) * segment_length >= MINIMUM_LINE_LENGTH)
643-
{
644-
temp_intersections.push_back(tup[1]);
645-
}
646-
}
647-
intersections = temp_intersections;
648-
649623
speed_regions_intersections.push_back(intersections);
650624
}
651625

@@ -664,6 +638,14 @@ void LayerPlan::addExtrusionMoveWithGradualOverhang(
664638
}
665639
};
666640

641+
struct SegmentExtrusionMove
642+
{
643+
Point2LL position;
644+
size_t speed_region_index;
645+
};
646+
647+
std::vector<SegmentExtrusionMove> extrusion_moves;
648+
667649
// Now move along segment and split it where we cross speed regions
668650
while (true)
669651
{
@@ -701,7 +683,7 @@ void LayerPlan::addExtrusionMoveWithGradualOverhang(
701683

702684
// Move to intersection at current region speed
703685
const Point2LL split_position = start + vector * intersection_parameter;
704-
add_extrusion_move(split_position, actual_speed_region_index);
686+
extrusion_moves.push_back(SegmentExtrusionMove{ split_position, actual_speed_region_index });
705687

706688
// Prepare for next move in different region
707689
actual_speed_region_index = next_speed_region_index;
@@ -710,9 +692,67 @@ void LayerPlan::addExtrusionMoveWithGradualOverhang(
710692
else
711693
{
712694
// We cross no border, which means we can reach the end of the segment within the current speed region, so we are done
713-
add_extrusion_move(p, actual_speed_region_index);
714-
return;
695+
extrusion_moves.push_back(SegmentExtrusionMove{ p.toPoint2LL(), actual_speed_region_index });
696+
break;
697+
}
698+
}
699+
700+
// Filter out micro-segments
701+
std::vector<SegmentExtrusionMove> extrusion_moves_filtered;
702+
extrusion_moves_filtered.reserve(extrusion_moves.size());
703+
Point2LL current_position = start;
704+
for (const SegmentExtrusionMove& extrusion_move : extrusion_moves | ranges::views::drop_last(1))
705+
{
706+
if (vSize2(extrusion_move.position - current_position) >= MINIMUM_SQUARED_LINE_LENGTH)
707+
{
708+
extrusion_moves_filtered.push_back(extrusion_move);
709+
}
710+
711+
current_position = extrusion_move.position;
712+
}
713+
714+
if (extrusion_moves_filtered.empty() || vSize2(extrusion_moves.back().position - current_position) >= MINIMUM_SQUARED_LINE_LENGTH)
715+
{
716+
extrusion_moves_filtered.push_back(extrusion_moves.back());
717+
}
718+
else
719+
{
720+
extrusion_moves_filtered.back().position = extrusion_moves.back().position;
721+
}
722+
723+
// Calculate max consecutive overhanging segment length
724+
current_position = start;
725+
for (const SegmentExtrusionMove& extrusion_move : extrusion_moves_filtered)
726+
{
727+
const bool is_overhanging = extrusion_move.speed_region_index > 0;
728+
update_is_overhanging(extrusion_move.position, current_position, is_overhanging);
729+
current_position = extrusion_move.position;
730+
}
731+
732+
// Merge consecutive sub-segments that in the end have the same speed
733+
std::vector<SegmentExtrusionMove> extrusion_moves_merged;
734+
extrusion_moves_merged.reserve(extrusion_moves_filtered.size());
735+
extrusion_moves_merged.push_back(extrusion_moves_filtered.front());
736+
737+
for (const SegmentExtrusionMove& extrusion_move : extrusion_moves_filtered | ranges::views::drop(1))
738+
{
739+
const Ratio previous_speed_factor = overhang_masks_[extrusion_moves_merged.back().speed_region_index].speed_ratio;
740+
const Ratio next_speed_factor = overhang_masks_[extrusion_move.speed_region_index].speed_ratio;
741+
742+
if (next_speed_factor == previous_speed_factor)
743+
{
744+
extrusion_moves_merged.back().position = extrusion_move.position;
715745
}
746+
else
747+
{
748+
extrusion_moves_merged.push_back(extrusion_move);
749+
}
750+
}
751+
752+
// Finally, add extrusion moves
753+
for (const SegmentExtrusionMove& extrusion_move : extrusion_moves_merged)
754+
{
755+
add_extrusion_move(extrusion_move.position, extrusion_move.speed_region_index);
716756
}
717757
}
718758

0 commit comments

Comments
 (0)