mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-03 02:40:41 +08:00
Merge branch 'ms_fix_invalid_scarf'
This commit is contained in:
commit
2f602b3ca8
@ -2302,13 +2302,20 @@ std::pair<GCode::SmoothPath, std::size_t> split_with_seam(
|
||||
if (loop.paths.empty() || loop.paths.front().empty()) {
|
||||
return {SmoothPath{}, 0};
|
||||
}
|
||||
if (const auto seam_point{boost::get<Point>(&seam)}; seam_point != nullptr) {
|
||||
const auto seam_point{boost::get<Point>(&seam)};
|
||||
const auto scarf{boost::get<Seams::Scarf::Scarf>(&seam)};
|
||||
|
||||
if (seam_point != nullptr) {
|
||||
return {
|
||||
smooth_path_cache.resolve_or_fit_split_with_seam(
|
||||
loop, flipped, scaled_resolution, *seam_point, seam_point_merge_distance_threshold
|
||||
),
|
||||
0};
|
||||
} else if (const auto scarf{boost::get<Seams::Scarf::Scarf>(&seam)}; scarf != nullptr) {
|
||||
} else if (scarf != nullptr && scarf->start_point == scarf->end_point) {
|
||||
return {smooth_path_cache.resolve_or_fit_split_with_seam(
|
||||
loop, flipped, scaled_resolution, scarf->start_point, seam_point_merge_distance_threshold
|
||||
), 0};
|
||||
} else if (scarf != nullptr) {
|
||||
ExtrusionPaths paths{loop.paths};
|
||||
const auto apply_smoothing{[&](tcb::span<const ExtrusionPath> paths){
|
||||
return smooth_path_cache.resolve_or_fit(paths, false, scaled<double>(0.0015));
|
||||
|
@ -235,6 +235,24 @@ SeamChoice to_seam_choice(
|
||||
return result;
|
||||
}
|
||||
|
||||
Geometry::Direction1D get_direction(
|
||||
const bool flipped,
|
||||
const ExPolygon &perimeter_polygon,
|
||||
const ExtrusionLoop &loop
|
||||
) {
|
||||
using Dir = Geometry::Direction1D;
|
||||
|
||||
Dir result{flipped ? Dir::forward : Dir::backward};
|
||||
|
||||
// In rare cases it may happen that the original geometry perimeter
|
||||
// polygon has different direction to the actual extrusion loop.
|
||||
// In that case the logic is exactly opposite.
|
||||
if (perimeter_polygon.contour.is_clockwise() != loop.is_clockwise()) {
|
||||
result = result == Dir::forward ? Dir::backward : Dir::forward;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
boost::variant<Point, Scarf::Scarf> finalize_seam_position(
|
||||
const ExtrusionLoop &loop,
|
||||
const PrintRegion *region,
|
||||
@ -255,8 +273,7 @@ boost::variant<Point, Scarf::Scarf> finalize_seam_position(
|
||||
auto [loop_line_index, loop_point]{
|
||||
project_to_extrusion_loop(seam_choice, perimeter, distancer)};
|
||||
|
||||
const Geometry::Direction1D offset_direction{
|
||||
flipped ? Geometry::Direction1D::forward : Geometry::Direction1D::backward};
|
||||
const Geometry::Direction1D offset_direction{get_direction(flipped, perimeter_polygon, loop)};
|
||||
|
||||
// ExtrusionRole::Perimeter is inner perimeter.
|
||||
if (do_staggering) {
|
||||
@ -312,11 +329,15 @@ boost::variant<Point, Scarf::Scarf> finalize_seam_position(
|
||||
}
|
||||
|
||||
if (loop.role() != ExtrusionRole::Perimeter) { // Outter perimeter
|
||||
scarf.start_point = scaled(project_to_extrusion_loop(
|
||||
const Vec2d start_point_candidate{project_to_extrusion_loop(
|
||||
to_seam_choice(*outter_scarf_start_point, perimeter),
|
||||
perimeter,
|
||||
distancer
|
||||
).second);
|
||||
).second};
|
||||
if ((start_point_candidate - outter_scarf_start_point->point).norm() > 5.0) {
|
||||
return scaled(loop_point);
|
||||
}
|
||||
scarf.start_point = scaled(start_point_candidate);
|
||||
scarf.end_point = scaled(loop_point);
|
||||
scarf.end_point_previous_index = loop_line_index;
|
||||
return scarf;
|
||||
@ -359,18 +380,25 @@ boost::variant<Point, Scarf::Scarf> finalize_seam_position(
|
||||
if (!inner_scarf_start_point) {
|
||||
return scaled(inner_scarf_end_point.point);
|
||||
}
|
||||
|
||||
scarf.start_point = scaled(project_to_extrusion_loop(
|
||||
const Vec2d start_point_candidate{project_to_extrusion_loop(
|
||||
to_seam_choice(*inner_scarf_start_point, perimeter),
|
||||
perimeter,
|
||||
distancer
|
||||
).second);
|
||||
).second};
|
||||
if ((start_point_candidate - inner_scarf_start_point->point).norm() > 5.0) {
|
||||
return scaled(loop_point);
|
||||
}
|
||||
scarf.start_point = scaled(start_point_candidate);
|
||||
|
||||
const auto [end_point_previous_index, end_point]{project_to_extrusion_loop(
|
||||
to_seam_choice(inner_scarf_end_point, perimeter),
|
||||
perimeter,
|
||||
distancer
|
||||
)};
|
||||
if ((end_point - inner_scarf_end_point.point).norm() > 5.0) {
|
||||
return scaled(loop_point);
|
||||
}
|
||||
|
||||
scarf.end_point = scaled(end_point);
|
||||
scarf.end_point_previous_index = end_point_previous_index;
|
||||
return scarf;
|
||||
|
@ -24,6 +24,75 @@ 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{possible_lines.front().previous_index};
|
||||
|
||||
for (const PerimeterLine &line : possible_lines) {
|
||||
if (line.a.y() > point.y()) {
|
||||
point = line.a;
|
||||
point_index = line.previous_index;
|
||||
}
|
||||
if (line.b.y() > point.y()) {
|
||||
point = line.b;
|
||||
point_index = line.next_index;
|
||||
}
|
||||
}
|
||||
|
||||
return SeamChoice{point_index, point_index, point};
|
||||
}
|
||||
|
||||
SeamChoice get_nearest(
|
||||
const AABBTreeLines::LinesDistancer<PerimeterLine>& distancer,
|
||||
const Vec2d point
|
||||
) {
|
||||
const auto [_, line_index, resulting_point] = distancer.distance_from_lines_extra<false>(point);
|
||||
return SeamChoice{
|
||||
distancer.get_lines()[line_index].previous_index,
|
||||
distancer.get_lines()[line_index].next_index,
|
||||
resulting_point
|
||||
};
|
||||
}
|
||||
|
||||
struct RearestPointCalculator {
|
||||
double rear_tolerance;
|
||||
double rear_y_offset;
|
||||
@ -35,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};
|
||||
@ -62,26 +144,26 @@ struct RearestPointCalculator {
|
||||
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()};
|
||||
|
||||
Vec2d result{point};
|
||||
SeamChoice result{possible_lines[line_index].previous_index, possible_lines[line_index].next_index, point};
|
||||
|
||||
if (y_distance < 0) {
|
||||
result = point_bb;
|
||||
result = get_nearest(
|
||||
possible_distancer,
|
||||
point_bb
|
||||
);
|
||||
} else if (y_distance <= rear_tolerance) {
|
||||
const double factor{y_distance / rear_tolerance};
|
||||
result = factor * point + (1 - factor) * point_bb;
|
||||
result = get_nearest(
|
||||
possible_distancer,
|
||||
factor * point + (1 - factor) * point_bb
|
||||
);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
if (bounding_box.max.y() - result.position.y() > rear_tolerance) {
|
||||
return max_y_choice;
|
||||
}
|
||||
|
||||
return SeamChoice{possible_lines[line_index].previous_index, possible_lines[line_index].next_index, result};
|
||||
return result;
|
||||
}
|
||||
};
|
||||
} // namespace Impl
|
||||
|
Loading…
x
Reference in New Issue
Block a user