mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-14 06:35:58 +08:00
Gracefuly handle cases where the geometetry is not the same as generated perimeters
This commit is contained in:
parent
9bf4a5f14b
commit
8ed0614b90
@ -127,9 +127,16 @@ std::pair<Mapping, std::size_t> get_mapping(
|
||||
return {result, new_bucket_id};
|
||||
}
|
||||
|
||||
Extrusion::Extrusion(BoundingBox bounding_box, const double width, const ExPolygon &island_boundary)
|
||||
: bounding_box(std::move(bounding_box)), width(width), island_boundary(island_boundary) {
|
||||
|
||||
Extrusion::Extrusion(
|
||||
Polygon &&polygon,
|
||||
BoundingBox bounding_box,
|
||||
const double width,
|
||||
const ExPolygon &island_boundary
|
||||
)
|
||||
: polygon(polygon)
|
||||
, bounding_box(std::move(bounding_box))
|
||||
, width(width)
|
||||
, island_boundary(island_boundary) {
|
||||
this->island_boundary_bounding_boxes.push_back(island_boundary.contour.bounding_box());
|
||||
|
||||
std::transform(
|
||||
@ -149,9 +156,10 @@ Geometry::Extrusions get_external_perimeters(const Slic3r::Layer &layer, const L
|
||||
)};
|
||||
for (const ExtrusionEntity *entity : *collection) {
|
||||
if (entity->role().is_external_perimeter()) {
|
||||
const BoundingBox bounding_box{entity->as_polyline().points};
|
||||
Polygon polygon{entity->as_polyline().points};
|
||||
const BoundingBox bounding_box{polygon.bounding_box()};
|
||||
const double width{layer_region.flow(FlowRole::frExternalPerimeter).width()};
|
||||
result.emplace_back(bounding_box, width, island.boundary);
|
||||
result.emplace_back(std::move(polygon), bounding_box, width, island.boundary);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -325,6 +333,12 @@ std::vector<double> get_vertex_angles(const std::vector<Vec2d> &points, const do
|
||||
return result;
|
||||
}
|
||||
|
||||
double bounding_box_distance(const BoundingBox &a, const BoundingBox &b) {
|
||||
const double bb_max_distance{unscaled(Point{a.max - b.max}).norm()};
|
||||
const double bb_min_distance{unscaled(Point{a.min - b.min}).norm()};
|
||||
return std::max(bb_max_distance, bb_min_distance);
|
||||
}
|
||||
|
||||
std::pair<std::size_t, double> pick_closest_bounding_box(
|
||||
const BoundingBox &to, const BoundingBoxes &choose_from
|
||||
) {
|
||||
@ -333,9 +347,7 @@ std::pair<std::size_t, double> pick_closest_bounding_box(
|
||||
|
||||
for (std::size_t i{0}; i < choose_from.size(); ++i) {
|
||||
const BoundingBox &candidate{choose_from[i]};
|
||||
const double bb_max_distance{unscaled(Point{candidate.max - to.max}).norm()};
|
||||
const double bb_min_distance{unscaled(Point{candidate.min - to.min}).norm()};
|
||||
const double distance{std::max(bb_max_distance, bb_min_distance)};
|
||||
const double distance{bounding_box_distance(candidate, to)};
|
||||
|
||||
if (distance < min_distance) {
|
||||
choosen_index = i;
|
||||
|
@ -18,13 +18,19 @@ namespace Slic3r::Seams::Geometry {
|
||||
|
||||
struct Extrusion
|
||||
{
|
||||
Extrusion(BoundingBox bounding_box, const double width, const ExPolygon &island_boundary);
|
||||
Extrusion(
|
||||
Polygon &&polygon,
|
||||
BoundingBox bounding_box,
|
||||
const double width,
|
||||
const ExPolygon &island_boundary
|
||||
);
|
||||
|
||||
Extrusion(const Extrusion &) = delete;
|
||||
Extrusion(Extrusion &&) = default;
|
||||
Extrusion &operator=(const Extrusion &) = delete;
|
||||
Extrusion &operator=(Extrusion &&) = delete;
|
||||
|
||||
Polygon polygon;
|
||||
BoundingBox bounding_box;
|
||||
double width;
|
||||
const ExPolygon &island_boundary;
|
||||
@ -151,6 +157,8 @@ std::vector<double> get_overhangs(
|
||||
// Measured from outside, convex is positive
|
||||
std::vector<double> get_vertex_angles(const std::vector<Vec2d> &points, const double min_arm_length);
|
||||
|
||||
double bounding_box_distance(const BoundingBox &a, const BoundingBox &b);
|
||||
|
||||
std::pair<std::size_t, double> pick_closest_bounding_box(
|
||||
const BoundingBox &to, const BoundingBoxes &choose_from
|
||||
);
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
namespace Slic3r::Seams::Shells::Impl {
|
||||
|
||||
BoundedPolygons project_to_geometry(const Geometry::Extrusions &external_perimeters) {
|
||||
BoundedPolygons project_to_geometry(const Geometry::Extrusions &external_perimeters, const double max_bb_distance) {
|
||||
BoundedPolygons result;
|
||||
result.reserve(external_perimeters.size());
|
||||
|
||||
@ -13,12 +13,26 @@ BoundedPolygons project_to_geometry(const Geometry::Extrusions &external_perimet
|
||||
|
||||
transform(
|
||||
external_perimeters.begin(), external_perimeters.end(), back_inserter(result),
|
||||
[](const Geometry::Extrusion &external_perimeter) {
|
||||
[&](const Geometry::Extrusion &external_perimeter) {
|
||||
const auto [choosen_index, _]{Geometry::pick_closest_bounding_box(
|
||||
external_perimeter.bounding_box,
|
||||
external_perimeter.island_boundary_bounding_boxes
|
||||
)};
|
||||
|
||||
const double distance{Geometry::bounding_box_distance(
|
||||
external_perimeter.island_boundary_bounding_boxes[choosen_index],
|
||||
external_perimeter.bounding_box
|
||||
)};
|
||||
|
||||
if (distance > max_bb_distance) {
|
||||
Polygons expanded_extrusion{expand(external_perimeter.polygon, external_perimeter.width / 2.0)};
|
||||
if (!expanded_extrusion.empty()) {
|
||||
return BoundedPolygon{
|
||||
expanded_extrusion.front(), expanded_extrusion.front().bounding_box(), external_perimeter.polygon.is_clockwise()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const bool is_hole{choosen_index != 0};
|
||||
const Polygon &adjacent_boundary{
|
||||
!is_hole ? external_perimeter.island_boundary.contour :
|
||||
@ -29,11 +43,11 @@ BoundedPolygons project_to_geometry(const Geometry::Extrusions &external_perimet
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<BoundedPolygons> project_to_geometry(const std::vector<Geometry::Extrusions> &extrusions) {
|
||||
std::vector<BoundedPolygons> project_to_geometry(const std::vector<Geometry::Extrusions> &extrusions, const double max_bb_distance) {
|
||||
std::vector<BoundedPolygons> result(extrusions.size());
|
||||
|
||||
for (std::size_t layer_index{0}; layer_index < extrusions.size(); ++layer_index) {
|
||||
result[layer_index] = project_to_geometry(extrusions[layer_index]);
|
||||
result[layer_index] = project_to_geometry(extrusions[layer_index], max_bb_distance);
|
||||
}
|
||||
|
||||
return result;
|
||||
@ -61,7 +75,7 @@ namespace Slic3r::Seams::Shells {
|
||||
Shells<Polygon> create_shells(
|
||||
const std::vector<Geometry::Extrusions> &extrusions, const double max_distance
|
||||
) {
|
||||
std::vector<Impl::BoundedPolygons> projected{Impl::project_to_geometry(extrusions)};
|
||||
std::vector<Impl::BoundedPolygons> projected{Impl::project_to_geometry(extrusions, max_distance)};
|
||||
|
||||
std::vector<std::size_t> layer_sizes;
|
||||
layer_sizes.reserve(projected.size());
|
||||
|
@ -25,21 +25,7 @@ struct BoundedPolygon {
|
||||
|
||||
using BoundedPolygons = std::vector<BoundedPolygon>;
|
||||
|
||||
/**
|
||||
* Project extrusion path to the original mesh.
|
||||
*
|
||||
* Takes the extrusion path and finds the closest polygon to it in
|
||||
* the extruison island boundary.
|
||||
*
|
||||
* Then it expands the extrusion path so it roughly tracks the island boundary
|
||||
* and check that all points in expanded extrusion path are within a reasonable
|
||||
* distance (extrusion width) from the closes polygon.
|
||||
*
|
||||
* If the expanded extrusion path matches the boundary it returns the
|
||||
* closeset polygon from the island boundary. Otherwise it returns
|
||||
* the expanded extrusion.
|
||||
*/
|
||||
BoundedPolygons project_to_geometry(const Geometry::Extrusions &extrusions);
|
||||
BoundedPolygons project_to_geometry(const Geometry::Extrusions &extrusions, const double max_bb_distance);
|
||||
}
|
||||
|
||||
namespace Slic3r::Seams::Shells {
|
||||
|
@ -23,7 +23,7 @@ struct ProjectionFixture
|
||||
double extrusion_width{0.2};
|
||||
|
||||
ProjectionFixture() {
|
||||
extrusions.emplace_back(extrusion_path.bounding_box(), extrusion_width, island_boundary);
|
||||
extrusions.emplace_back(Polygon{extrusion_path}, extrusion_path.bounding_box(), extrusion_width, island_boundary);
|
||||
}
|
||||
};
|
||||
|
||||
@ -33,13 +33,31 @@ TEST_CASE_METHOD(ProjectionFixture, "Project to geometry matches", "[Seams][Seam
|
||||
boundary_polygon.scale(1.0 + extrusion_width / 2.0 + 0.1);
|
||||
island_boundary.contour = boundary_polygon;
|
||||
|
||||
Shells::Impl::BoundedPolygons result{Shells::Impl::project_to_geometry(extrusions)};
|
||||
Shells::Impl::BoundedPolygons result{Shells::Impl::project_to_geometry(extrusions, 5.0)};
|
||||
REQUIRE(result.size() == 1);
|
||||
REQUIRE(result[0].polygon.size() == 4);
|
||||
// Boundary polygon is picked.
|
||||
CHECK(result[0].polygon[0].x() == Approx(scaled(-(1.0 + extrusion_width / 2.0 + 0.1))));
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(ProjectionFixture, "Project to geometry does not match", "[Seams][SeamShells]") {
|
||||
Polygon boundary_polygon{extrusion_path};
|
||||
|
||||
// Island boundary is far from the extrusion.
|
||||
boundary_polygon.scale(5.0);
|
||||
|
||||
island_boundary.contour = boundary_polygon;
|
||||
|
||||
Shells::Impl::BoundedPolygons result{Shells::Impl::project_to_geometry(extrusions, 1.0)};
|
||||
REQUIRE(result.size() == 1);
|
||||
REQUIRE(result[0].polygon.size() == 4);
|
||||
|
||||
const Polygon expanded{expand(extrusions.front().polygon, extrusion_width / 2.0).front()};
|
||||
|
||||
// The extrusion is expanded and returned.
|
||||
CHECK(result[0].polygon == expanded);
|
||||
}
|
||||
|
||||
void serialize_shells(
|
||||
std::ostream &out, const Shells::Shells<Polygon> &shells, const double layer_height
|
||||
) {
|
||||
@ -69,5 +87,5 @@ TEST_CASE_METHOD(Test::SeamsFixture, "Create shells", "[Seams][SeamShells][Integ
|
||||
serialize_shells(csv, shell_polygons, print->full_print_config().opt_float("layer_height"));
|
||||
}
|
||||
|
||||
CHECK(shell_polygons.size() == 39);
|
||||
CHECK(shell_polygons.size() == 36);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user