Fix #13870: Prefer a corner if there is one clearly rearest corner to be picked when placing rear seam

This commit is contained in:
Martin Šach 2025-01-14 13:23:35 +01:00 committed by Lukas Matena
parent 6176dcc540
commit 6494a3badd

View File

@ -24,13 +24,48 @@ BoundingBoxf get_bounding_box(const Shells::Shell<> &shell) {
return result;
}
std::optional<SeamChoice> get_clear_max_y_corner(
const std::vector<PerimeterLine> &possible_lines,
const Perimeters::Perimeter &perimeter,
const SeamChoice &max_y_choice,
const double rear_tolerance
) {
if (perimeter.angle_types[max_y_choice.previous_index] != Perimeters::AngleType::concave) {
return std::nullopt;
}
const double epsilon{1e-2};
// Check if there are two max y corners (e.g. on a cube).
for (const PerimeterLine &line : possible_lines) {
if (
line.previous_index != max_y_choice.previous_index
&& perimeter.angle_types[line.previous_index] == Perimeters::AngleType::concave
&& max_y_choice.position.y() < line.a.y() + epsilon
&& (max_y_choice.position - line.a).norm() > epsilon
) {
return std::nullopt;
}
if (
line.next_index != max_y_choice.next_index
&& perimeter.angle_types[line.next_index] == Perimeters::AngleType::concave
&& max_y_choice.position.y() < line.b.y() + epsilon
&& (max_y_choice.position - line.b).norm() > epsilon
) {
return std::nullopt;
}
}
return max_y_choice;
}
SeamChoice get_max_y_choice(const std::vector<PerimeterLine> &possible_lines) {
if (possible_lines.empty()) {
throw std::runtime_error{"No possible lines!"};
}
Vec2d point{possible_lines.front().a};
std::size_t point_index{0};
std::size_t point_index{possible_lines.front().previous_index};
for (const PerimeterLine &line : possible_lines) {
if (line.a.y() > point.y()) {
@ -69,24 +104,37 @@ struct RearestPointCalculator {
const PointClassification point_classification
) {
std::vector<PerimeterLine> possible_lines;
for (std::size_t i{0}; i < perimeter.positions.size() - 1; ++i) {
for (std::size_t i{0}; i < perimeter.positions.size(); ++i) {
const std::size_t next_index{i == perimeter.positions.size() - 1 ? 0 : i + 1};
if (perimeter.point_types[i] != point_type) {
continue;
}
if (perimeter.point_classifications[i] != point_classification) {
continue;
}
if (perimeter.point_types[i + 1] != point_type) {
if (perimeter.point_types[next_index] != point_type) {
continue;
}
if (perimeter.point_classifications[i + 1] != point_classification) {
if (perimeter.point_classifications[next_index] != point_classification) {
continue;
}
possible_lines.push_back(PerimeterLine{perimeter.positions[i], perimeter.positions[i+1], i, i + 1});
possible_lines.push_back(PerimeterLine{perimeter.positions[i], perimeter.positions[next_index], i, next_index});
}
if (possible_lines.empty()) {
return std::nullopt;
}
const SeamChoice max_y_choice{get_max_y_choice(possible_lines)};
if (const auto clear_max_y_corner{get_clear_max_y_corner(
possible_lines,
perimeter,
max_y_choice,
rear_tolerance
)}) {
return *clear_max_y_corner;
}
const BoundingBoxf bounding_box{perimeter.positions};
const AABBTreeLines::LinesDistancer<PerimeterLine> possible_distancer{possible_lines};
const double center_x{(bounding_box.max.x() + bounding_box.min.x()) / 2.0};
@ -112,7 +160,7 @@ struct RearestPointCalculator {
}
if (bounding_box.max.y() - result.position.y() > rear_tolerance) {
return get_max_y_choice(possible_lines);
return max_y_choice;
}
return result;