mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-15 23:15:54 +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};
|
return {result, new_bucket_id};
|
||||||
}
|
}
|
||||||
|
|
||||||
Extrusion::Extrusion(BoundingBox bounding_box, const double width, const ExPolygon &island_boundary)
|
Extrusion::Extrusion(
|
||||||
: bounding_box(std::move(bounding_box)), width(width), island_boundary(island_boundary) {
|
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());
|
this->island_boundary_bounding_boxes.push_back(island_boundary.contour.bounding_box());
|
||||||
|
|
||||||
std::transform(
|
std::transform(
|
||||||
@ -149,9 +156,10 @@ Geometry::Extrusions get_external_perimeters(const Slic3r::Layer &layer, const L
|
|||||||
)};
|
)};
|
||||||
for (const ExtrusionEntity *entity : *collection) {
|
for (const ExtrusionEntity *entity : *collection) {
|
||||||
if (entity->role().is_external_perimeter()) {
|
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()};
|
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;
|
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(
|
std::pair<std::size_t, double> pick_closest_bounding_box(
|
||||||
const BoundingBox &to, const BoundingBoxes &choose_from
|
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) {
|
for (std::size_t i{0}; i < choose_from.size(); ++i) {
|
||||||
const BoundingBox &candidate{choose_from[i]};
|
const BoundingBox &candidate{choose_from[i]};
|
||||||
const double bb_max_distance{unscaled(Point{candidate.max - to.max}).norm()};
|
const double distance{bounding_box_distance(candidate, to)};
|
||||||
const double bb_min_distance{unscaled(Point{candidate.min - to.min}).norm()};
|
|
||||||
const double distance{std::max(bb_max_distance, bb_min_distance)};
|
|
||||||
|
|
||||||
if (distance < min_distance) {
|
if (distance < min_distance) {
|
||||||
choosen_index = i;
|
choosen_index = i;
|
||||||
|
@ -18,13 +18,19 @@ namespace Slic3r::Seams::Geometry {
|
|||||||
|
|
||||||
struct Extrusion
|
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(const Extrusion &) = delete;
|
||||||
Extrusion(Extrusion &&) = default;
|
Extrusion(Extrusion &&) = default;
|
||||||
Extrusion &operator=(const Extrusion &) = delete;
|
Extrusion &operator=(const Extrusion &) = delete;
|
||||||
Extrusion &operator=(Extrusion &&) = delete;
|
Extrusion &operator=(Extrusion &&) = delete;
|
||||||
|
|
||||||
|
Polygon polygon;
|
||||||
BoundingBox bounding_box;
|
BoundingBox bounding_box;
|
||||||
double width;
|
double width;
|
||||||
const ExPolygon &island_boundary;
|
const ExPolygon &island_boundary;
|
||||||
@ -151,6 +157,8 @@ std::vector<double> get_overhangs(
|
|||||||
// Measured from outside, convex is positive
|
// Measured from outside, convex is positive
|
||||||
std::vector<double> get_vertex_angles(const std::vector<Vec2d> &points, const double min_arm_length);
|
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(
|
std::pair<std::size_t, double> pick_closest_bounding_box(
|
||||||
const BoundingBox &to, const BoundingBoxes &choose_from
|
const BoundingBox &to, const BoundingBoxes &choose_from
|
||||||
);
|
);
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
namespace Slic3r::Seams::Shells::Impl {
|
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;
|
BoundedPolygons result;
|
||||||
result.reserve(external_perimeters.size());
|
result.reserve(external_perimeters.size());
|
||||||
|
|
||||||
@ -13,12 +13,26 @@ BoundedPolygons project_to_geometry(const Geometry::Extrusions &external_perimet
|
|||||||
|
|
||||||
transform(
|
transform(
|
||||||
external_perimeters.begin(), external_perimeters.end(), back_inserter(result),
|
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(
|
const auto [choosen_index, _]{Geometry::pick_closest_bounding_box(
|
||||||
external_perimeter.bounding_box,
|
external_perimeter.bounding_box,
|
||||||
external_perimeter.island_boundary_bounding_boxes
|
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 bool is_hole{choosen_index != 0};
|
||||||
const Polygon &adjacent_boundary{
|
const Polygon &adjacent_boundary{
|
||||||
!is_hole ? external_perimeter.island_boundary.contour :
|
!is_hole ? external_perimeter.island_boundary.contour :
|
||||||
@ -29,11 +43,11 @@ BoundedPolygons project_to_geometry(const Geometry::Extrusions &external_perimet
|
|||||||
return result;
|
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());
|
std::vector<BoundedPolygons> result(extrusions.size());
|
||||||
|
|
||||||
for (std::size_t layer_index{0}; layer_index < extrusions.size(); ++layer_index) {
|
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;
|
return result;
|
||||||
@ -61,7 +75,7 @@ namespace Slic3r::Seams::Shells {
|
|||||||
Shells<Polygon> create_shells(
|
Shells<Polygon> create_shells(
|
||||||
const std::vector<Geometry::Extrusions> &extrusions, const double max_distance
|
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;
|
std::vector<std::size_t> layer_sizes;
|
||||||
layer_sizes.reserve(projected.size());
|
layer_sizes.reserve(projected.size());
|
||||||
|
@ -25,21 +25,7 @@ struct BoundedPolygon {
|
|||||||
|
|
||||||
using BoundedPolygons = std::vector<BoundedPolygon>;
|
using BoundedPolygons = std::vector<BoundedPolygon>;
|
||||||
|
|
||||||
/**
|
BoundedPolygons project_to_geometry(const Geometry::Extrusions &extrusions, const double max_bb_distance);
|
||||||
* 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Slic3r::Seams::Shells {
|
namespace Slic3r::Seams::Shells {
|
||||||
|
@ -23,7 +23,7 @@ struct ProjectionFixture
|
|||||||
double extrusion_width{0.2};
|
double extrusion_width{0.2};
|
||||||
|
|
||||||
ProjectionFixture() {
|
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);
|
boundary_polygon.scale(1.0 + extrusion_width / 2.0 + 0.1);
|
||||||
island_boundary.contour = boundary_polygon;
|
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.size() == 1);
|
||||||
REQUIRE(result[0].polygon.size() == 4);
|
REQUIRE(result[0].polygon.size() == 4);
|
||||||
// Boundary polygon is picked.
|
// Boundary polygon is picked.
|
||||||
CHECK(result[0].polygon[0].x() == Approx(scaled(-(1.0 + extrusion_width / 2.0 + 0.1))));
|
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(
|
void serialize_shells(
|
||||||
std::ostream &out, const Shells::Shells<Polygon> &shells, const double layer_height
|
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"));
|
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