Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 12 additions & 9 deletions include/PathOrderOptimizer.h
Original file line number Diff line number Diff line change
Expand Up @@ -784,17 +784,20 @@ class PathOrderOptimizer
best_candidate_finder.appendCriteriaPass(main_criteria_pass);

// ########## Step 2: add fallback passes for criteria with very similar scores (e.g. corner on a cylinder)
const AABB path_bounding_box(points);
if (path.seam_config_.type_ == EZSeamType::SHARPEST_CORNER)
{
const AABB path_bounding_box(points);

{ // First fallback strategy is to take points on the back-most position
auto fallback_criterion = std::make_shared<DistanceScoringCriterion>(points, path_bounding_box.max_, DistanceScoringCriterion::DistanceType::YOnly);
constexpr double outsider_delta_threshold = 0.01;
best_candidate_finder.appendSingleCriterionPass(fallback_criterion, outsider_delta_threshold);
}
{ // First fallback strategy is to take points on the back-most position
auto fallback_criterion = std::make_shared<DistanceScoringCriterion>(points, path_bounding_box.max_, DistanceScoringCriterion::DistanceType::YOnly);
constexpr double outsider_delta_threshold = 0.01;
best_candidate_finder.appendSingleCriterionPass(fallback_criterion, outsider_delta_threshold);
}

{ // Second fallback strategy, in case we still have multiple points that are aligned on Y (e.g. cube), take the right-most point
auto fallback_criterion = std::make_shared<DistanceScoringCriterion>(points, path_bounding_box.max_, DistanceScoringCriterion::DistanceType::XOnly);
best_candidate_finder.appendSingleCriterionPass(fallback_criterion);
{ // Second fallback strategy, in case we still have multiple points that are aligned on Y (e.g. cube), take the right-most point
auto fallback_criterion = std::make_shared<DistanceScoringCriterion>(points, path_bounding_box.max_, DistanceScoringCriterion::DistanceType::XOnly);
best_candidate_finder.appendSingleCriterionPass(fallback_criterion);
}
}

// ########## Step 3: apply the criteria to find the vertex with the best global score
Expand Down
3 changes: 2 additions & 1 deletion include/utils/scoring/BestElementFinder.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class ScoringCriterion;

/*!
* This class implements an algorithm to find an element amongst a list, regarding one or multiple scoring criteria. The
* criteria are implemented by subclassing the CriterionScoring class. It is also possible to setup multiple passes of
* criteria are implemented by subclassing the CriterionScoring class. It is also possible to set up multiple passes of
* criteria. Thus, if the first pass gives a few best candidates that are too close to each other, we keep only the best
* candidates and process a second pass with different criteria, and so on until we have a single outsider, or no more
* criteria.
Expand Down Expand Up @@ -60,6 +60,7 @@ class BestElementFinder
* Once we have calculated the global scores of each element for this pass, we calculate the score difference
* between the best candidate and the following ones. If the following ones have a score close enough to the
* best, within this threshold, they will also be considered outsiders and will be run for the next pass.
* This value will be ignored for the last pass.
*/
double outsider_delta_threshold{ 0.0 };
};
Expand Down
29 changes: 23 additions & 6 deletions src/utils/scoring/BestElementFinder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

#include <limits>

#include <range/v3/view/enumerate.hpp>

#include "utils/scoring/ScoringCriterion.h"

namespace cura
Expand Down Expand Up @@ -33,11 +35,11 @@ std::optional<size_t> cura::BestElementFinder::findBestElement(const size_t cand
const auto begin = best_candidates.begin();
auto end = best_candidates.end();

// Now run the criteria passes until we have a single outsider or no more cirteria
for (const CriteriaPass& criteria_pass : criteria_)
// Now run the criteria passes until we have a single outsider or no more criteria
for (const auto& [pass_index, criteria_pass] : criteria_ | ranges::views::enumerate)
{
// For each element, reset score, process each criterion and apply weights to get the global score
double best_score = 0.0;
auto best_candidate_iterator = end;
for (auto iterator = begin; iterator != end; ++iterator)
{
iterator->score = 0.0;
Expand All @@ -47,17 +49,32 @@ std::optional<size_t> cura::BestElementFinder::findBestElement(const size_t cand
iterator->score += weighed_criterion.criterion->computeScore(iterator->candidate_index) * weighed_criterion.weight;
}

best_score = std::max(best_score, iterator->score);
if (best_candidate_iterator == end || iterator->score > best_candidate_iterator->score)
{
best_candidate_iterator = iterator;
}
}

if (best_candidate_iterator == end)
{
// Something went wrong, we don't have a best candidate
return std::nullopt;
}

// Early out for last pass, just keep the best candidate
if (pass_index == criteria_.size() - 1)
{
return best_candidate_iterator->candidate_index;
}

// Skip candidates that have a score too far from the actual best one
const double delta_threshold = criteria_pass.outsider_delta_threshold + std::numeric_limits<double>::epsilon();
end = std::remove_if(
begin,
end,
[&best_score, &delta_threshold](const Candidate& candidate)
[&best_candidate_iterator, &delta_threshold](const Candidate& candidate)
{
return best_score - candidate.score > delta_threshold;
return best_candidate_iterator->score - candidate.score > delta_threshold;
});

if (std::distance(begin, end) == 1)
Expand Down
Loading