Files
QIDISlicer/src/libslic3r/GCode/SeamRear.cpp

125 lines
4.6 KiB
C++
Raw Normal View History

2024-11-11 14:57:19 +08:00
#include "libslic3r/GCode/SeamRear.hpp"
#include <algorithm>
#include <optional>
#include <utility>
#include "libslic3r/AABBTreeLines.hpp"
#include "libslic3r/BoundingBox.hpp"
#include "libslic3r/GCode/SeamChoice.hpp"
#include "libslic3r/GCode/SeamPerimeters.hpp"
#include "libslic3r/GCode/SeamShells.hpp"
namespace Slic3r::Seams::Rear {
using Perimeters::PointType;
using Perimeters::PointClassification;
namespace Impl {
BoundingBoxf get_bounding_box(const Shells::Shell<> &shell) {
BoundingBoxf result;
for (const Shells::Slice<> &slice : shell) {
result.merge(BoundingBoxf{slice.boundary.positions});
}
return result;
}
struct RearestPointCalculator {
double rear_tolerance;
double rear_y_offset;
BoundingBoxf bounding_box;
std::optional<SeamChoice> operator()(
const Perimeters::Perimeter &perimeter,
const PointType point_type,
const PointClassification point_classification
) {
std::vector<PerimeterLine> possible_lines;
for (std::size_t i{0}; i < perimeter.positions.size() - 1; ++i) {
if (perimeter.point_types[i] != point_type) {
continue;
}
if (perimeter.point_classifications[i] != point_classification) {
continue;
}
if (perimeter.point_types[i + 1] != point_type) {
continue;
}
if (perimeter.point_classifications[i + 1] != point_classification) {
continue;
}
possible_lines.push_back(PerimeterLine{perimeter.positions[i], perimeter.positions[i+1], i, i + 1});
}
if (possible_lines.empty()) {
return std::nullopt;
}
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};
const Vec2d prefered_position{center_x, bounding_box.max.y() + rear_y_offset};
auto [_, line_index, point] = possible_distancer.distance_from_lines_extra<false>(prefered_position);
const Vec2d location_at_bb{center_x, bounding_box.max.y()};
2025-02-08 16:06:54 +08:00
auto [_d, line_index_at_bb, point_bb] = possible_distancer.distance_from_lines_extra<false>(location_at_bb);
const double y_distance{point.y() - point_bb.y()};
2024-11-11 14:57:19 +08:00
Vec2d result{point};
if (y_distance < 0) {
2025-02-08 16:06:54 +08:00
result = point_bb;
2024-11-11 14:57:19 +08:00
} else if (y_distance <= rear_tolerance) {
const double factor{y_distance / rear_tolerance};
2025-02-08 16:06:54 +08:00
result = factor * point + (1 - factor) * point_bb;
2024-11-11 14:57:19 +08:00
}
2025-02-08 16:06:54 +08:00
if (bounding_box.max.y() - result.y() > rear_tolerance) {
for (const PerimeterLine &line : possible_lines) {
if (line.a.y() > result.y()) {
result = line.a;
}
if (line.b.y() > result.y()) {
result = line.b;
}
}
}
2024-11-11 14:57:19 +08:00
return SeamChoice{possible_lines[line_index].previous_index, possible_lines[line_index].next_index, result};
}
};
} // namespace Impl
std::vector<std::vector<SeamPerimeterChoice>> get_object_seams(
std::vector<std::vector<Perimeters::BoundedPerimeter>> &&perimeters,
const double rear_tolerance,
const double rear_y_offset
) {
std::vector<std::vector<SeamPerimeterChoice>> result;
for (std::vector<Perimeters::BoundedPerimeter> &layer : perimeters) {
result.emplace_back();
for (Perimeters::BoundedPerimeter &perimeter : layer) {
if (perimeter.perimeter.is_degenerate) {
std::optional<Seams::SeamChoice> seam_choice{
Seams::choose_degenerate_seam_point(perimeter.perimeter)};
if (seam_choice) {
result.back().push_back(
SeamPerimeterChoice{*seam_choice, std::move(perimeter.perimeter)}
);
} else {
result.back().push_back(SeamPerimeterChoice{SeamChoice{}, std::move(perimeter.perimeter)});
}
} else {
BoundingBoxf bounding_box{unscaled(perimeter.bounding_box)};
const SeamChoice seam_choice{Seams::choose_seam_point(
perimeter.perimeter,
Impl::RearestPointCalculator{rear_tolerance, rear_y_offset, bounding_box}
)};
result.back().push_back(
SeamPerimeterChoice{seam_choice, std::move(perimeter.perimeter)}
);
}
}
}
return result;
}
} // namespace Slic3r::Seams::Rear