Handle special seam case of just 2 or 3 perimeters.

If there are only 2 or 3 perimeters on a layer, exactly two of them are
external and just one of them is a hole, then the seams should be
choosen next to each other on the external perimeters.
This commit is contained in:
Martin Šach 2024-05-03 17:28:01 +02:00 committed by Lukas Matena
parent d158c0a4de
commit 9a1dcc4720
9 changed files with 54 additions and 4 deletions

View File

@ -269,6 +269,7 @@ Perimeter::PointTrees get_kd_trees(
Perimeter::Perimeter(
const double slice_z,
const std::size_t layer_index,
const bool is_hole,
std::vector<Vec2d> &&positions,
std::vector<double> &&angles,
std::vector<PointType> &&point_types,
@ -277,6 +278,7 @@ Perimeter::Perimeter(
)
: slice_z(slice_z)
, layer_index(layer_index)
, is_hole(is_hole)
, positions(std::move(positions))
, angles(std::move(angles))
, index_to_coord(IndexToCoord{tcb::span{this->positions}})
@ -304,6 +306,7 @@ Perimeter Perimeter::create_degenerate(
Perimeter perimeter{
slice_z,
layer_index,
false,
std::move(points),
std::move(angles),
std::move(point_types),
@ -368,9 +371,12 @@ Perimeter Perimeter::create(
Impl::get_angle_types(smooth_angles, params.convex_threshold, params.concave_threshold)};
angle_types = Impl::merge_angle_types(angle_types, smooth_angle_types, perimeter_points, params.smooth_angle_arm_length);
const bool is_hole{polygon.is_clockwise()};
return Perimeter{
layer_info.slice_z,
layer_info.index,
is_hole,
std::move(perimeter_points),
std::move(angles),
std::move(point_types),

View File

@ -127,6 +127,7 @@ struct Perimeter
Perimeter(
const double slice_z,
const std::size_t layer_index,
const bool is_hole,
std::vector<Vec2d> &&positions,
std::vector<double> &&angles,
std::vector<PointType> &&point_types,
@ -147,6 +148,7 @@ struct Perimeter
bool is_degenerate{false};
double slice_z{};
bool is_hole{false};
std::size_t layer_index{};
std::vector<Vec2d> positions{};
std::vector<double> angles{};

View File

@ -298,6 +298,21 @@ std::pair<SeamChoice, std::size_t> place_seam_near(
return {choice, choice_index};
}
int get_perimeter_count(const Layer *layer){
int count{0};
for (const LayerRegion *layer_region : layer->regions()) {
for (const ExtrusionEntity *ex_entity : layer_region->perimeters()) {
if (ex_entity->is_collection()) { //collection of inner, outer, and overhang perimeters
count += static_cast<const ExtrusionEntityCollection*>(ex_entity)->entities.size();
}
else {
count += 1;
}
}
}
return count;
}
Point Placer::place_seam(const Layer *layer, const ExtrusionLoop &loop, const Point &last_pos) const {
const PrintObject *po = layer->object();
// Must not be called with supprot layer.
@ -311,12 +326,33 @@ Point Placer::place_seam(const Layer *layer, const ExtrusionLoop &loop, const Po
const bool do_staggering{this->params.staggered_inner_seams && loop.role() == ExtrusionRole::Perimeter};
const double loop_width{loop.paths.empty() ? 0.0 : loop.paths.front().width()};
if (this->params.seam_preference == spNearest) {
const std::vector<BoundedPerimeter> &perimeters{this->perimeters_per_layer.at(po)[layer_index]};
const auto [seam_choice, perimeter_index] = place_seam_near(perimeters, loop, last_pos, this->params.max_nearest_detour);
return finalize_seam_position(loop_polygon, seam_choice, perimeters[perimeter_index].perimeter, loop_width, do_staggering);
} else {
const SeamPerimeterChoice &seam_perimeter_choice{choose_closest_seam(this->seams_per_object.at(po)[layer_index], loop_polygon)};
const std::vector<SeamPerimeterChoice> &seams_on_perimeters{this->seams_per_object.at(po)[layer_index]};
// Special case.
// If there are only two perimeters and the current perimeter is hole (clockwise).
const int perimeter_count{get_perimeter_count(layer)};
const bool has_2_or_3_perimeters{perimeter_count == 2 || perimeter_count == 3};
if (has_2_or_3_perimeters) {
if (seams_on_perimeters.size() == 2 &&
seams_on_perimeters[0].perimeter.is_hole !=
seams_on_perimeters[1].perimeter.is_hole) {
const SeamPerimeterChoice &seam_perimeter_choice{
seams_on_perimeters[0].perimeter.is_hole ? seams_on_perimeters[1] :
seams_on_perimeters[0]};
return finalize_seam_position(
loop_polygon, seam_perimeter_choice.choice, seam_perimeter_choice.perimeter,
loop_width, do_staggering
);
}
}
const SeamPerimeterChoice &seam_perimeter_choice{choose_closest_seam(seams_on_perimeters, loop_polygon)};
return finalize_seam_position(loop_polygon, seam_perimeter_choice.choice, seam_perimeter_choice.perimeter, loop_width, do_staggering);
}
}

View File

@ -19,10 +19,11 @@ BoundedPolygons project_to_geometry(const Geometry::Extrusions &external_perimet
external_perimeter.island_boundary_bounding_boxes
)};
const bool is_hole{choosen_index != 0};
const Polygon &adjacent_boundary{
choosen_index == 0 ? external_perimeter.island_boundary.contour :
external_perimeter.island_boundary.holes[choosen_index - 1]};
return BoundedPolygon{adjacent_boundary, external_perimeter.island_boundary_bounding_boxes[choosen_index]};
!is_hole ? external_perimeter.island_boundary.contour :
external_perimeter.island_boundary.holes[choosen_index - 1]};
return BoundedPolygon{adjacent_boundary, external_perimeter.island_boundary_bounding_boxes[choosen_index], is_hole};
}
);
return result;

View File

@ -20,6 +20,7 @@ namespace Slic3r::Seams::Shells::Impl {
struct BoundedPolygon {
Polygon polygon;
BoundingBox bounding_box;
bool is_hole{false};
};
using BoundedPolygons = std::vector<BoundedPolygon>;

View File

@ -25,6 +25,7 @@ Perimeters::Perimeter get_perimeter() {
return {
slice_z,
layer_index,
false,
std::move(positions),
std::move(angles),
std::move(point_types),

View File

@ -76,6 +76,7 @@ TEST_CASE("Perimeter constructs KD trees", "[Seams][SeamPerimeters]") {
Perimeters::Perimeter perimeter{
3.0,
2,
false,
std::move(positions),
std::move(angles),
std::move(point_types),

View File

@ -23,6 +23,7 @@ Perimeters::Perimeter get_perimeter() {
return {
slice_z,
layer_index,
false,
std::move(positions),
std::move(angles),
std::move(point_types),

View File

@ -25,6 +25,7 @@ Perimeters::Perimeter get_perimeter() {
return {
slice_z,
layer_index,
false,
std::move(positions),
std::move(angles),
std::move(point_types),