Fixed an issue when the Lightning infill stuck in an infinite loop on some models.

Cased by two sampled points closer than chosen spacing.
This commit is contained in:
Lukáš Hejl 2022-06-10 15:19:26 +02:00
parent 3fba411d17
commit bd4b63e67d
4 changed files with 53 additions and 12 deletions

View File

@ -3043,14 +3043,18 @@ Polylines FillSupportBase::fill_surface(const Surface *surface, const FillParams
return polylines_out; return polylines_out;
} }
Points sample_grid_pattern(const ExPolygon &expolygon, coord_t spacing) // Lightning infill assumes that the distance between any two sampled points is always
// at least equal to the value of spacing. To meet this assumption, we need to use
// BoundingBox for whole layers instead of bounding box just around processing ExPolygon.
// Using just BoundingBox around processing ExPolygon could produce two points closer
// than spacing (in cases where two ExPolygon are closer than spacing).
Points sample_grid_pattern(const ExPolygon &expolygon, coord_t spacing, const BoundingBox &global_bounding_box)
{ {
ExPolygonWithOffset poly_with_offset(expolygon, 0, 0, 0); ExPolygonWithOffset poly_with_offset(expolygon, 0, 0, 0);
BoundingBox bounding_box = poly_with_offset.bounding_box_src();
std::vector<SegmentedIntersectionLine> segs = slice_region_by_vertical_lines( std::vector<SegmentedIntersectionLine> segs = slice_region_by_vertical_lines(
poly_with_offset, poly_with_offset,
(bounding_box.max.x() - bounding_box.min.x() + spacing - 1) / spacing, (global_bounding_box.max.x() - global_bounding_box.min.x() + spacing - 1) / spacing,
bounding_box.min.x(), global_bounding_box.min.x(),
spacing); spacing);
Points out; Points out;
@ -3066,17 +3070,17 @@ Points sample_grid_pattern(const ExPolygon &expolygon, coord_t spacing)
return out; return out;
} }
Points sample_grid_pattern(const ExPolygons &expolygons, coord_t spacing) Points sample_grid_pattern(const ExPolygons &expolygons, coord_t spacing, const BoundingBox &global_bounding_box)
{ {
Points out; Points out;
for (const ExPolygon &expoly : expolygons) for (const ExPolygon &expoly : expolygons)
append(out, sample_grid_pattern(expoly, spacing)); append(out, sample_grid_pattern(expoly, spacing, global_bounding_box));
return out; return out;
} }
Points sample_grid_pattern(const Polygons &polygons, coord_t spacing) Points sample_grid_pattern(const Polygons &polygons, coord_t spacing, const BoundingBox &global_bounding_box)
{ {
return sample_grid_pattern(union_ex(polygons), spacing); return sample_grid_pattern(union_ex(polygons), spacing, global_bounding_box);
} }
} // namespace Slic3r } // namespace Slic3r

View File

@ -109,9 +109,9 @@ protected:
float _layer_angle(size_t idx) const override { return 0.f; } float _layer_angle(size_t idx) const override { return 0.f; }
}; };
Points sample_grid_pattern(const ExPolygon &expolygon, coord_t spacing); Points sample_grid_pattern(const ExPolygon &expolygon, coord_t spacing, const BoundingBox &global_bounding_box);
Points sample_grid_pattern(const ExPolygons &expolygons, coord_t spacing); Points sample_grid_pattern(const ExPolygons &expolygons, coord_t spacing, const BoundingBox &global_bounding_box);
Points sample_grid_pattern(const Polygons &polygons, coord_t spacing); Points sample_grid_pattern(const Polygons &polygons, coord_t spacing, const BoundingBox &global_bounding_box);
} // namespace Slic3r } // namespace Slic3r

View File

@ -7,11 +7,34 @@
#include <tbb/parallel_for.h> #include <tbb/parallel_for.h>
#ifdef LIGHTNING_DISTANCE_FIELD_DEBUG_OUTPUT
#include "../../SVG.hpp"
#endif
namespace Slic3r::FillLightning namespace Slic3r::FillLightning
{ {
constexpr coord_t radius_per_cell_size = 6; // The cell-size should be small compared to the radius, but not so small as to be inefficient. constexpr coord_t radius_per_cell_size = 6; // The cell-size should be small compared to the radius, but not so small as to be inefficient.
#ifdef LIGHTNING_DISTANCE_FIELD_DEBUG_OUTPUT
void export_distance_field_to_svg(const std::string &path, const Polygons &outline, const Polygons &overhang, const std::list<DistanceField::UnsupportedCell> &unsupported_points, const Points &points = {})
{
coordf_t stroke_width = scaled<coordf_t>(0.01);
BoundingBox bbox = get_extents(outline);
bbox.offset(SCALED_EPSILON);
SVG svg(path, bbox);
svg.draw_outline(outline, "green", stroke_width);
svg.draw_outline(overhang, "blue", stroke_width);
for (const DistanceField::UnsupportedCell &cell : unsupported_points)
svg.draw(cell.loc, "cyan", coord_t(stroke_width));
for (const Point &pt : points)
svg.draw(pt, "red", coord_t(stroke_width));
}
#endif
DistanceField::DistanceField(const coord_t& radius, const Polygons& current_outline, const BoundingBox& current_outlines_bbox, const Polygons& current_overhang) : DistanceField::DistanceField(const coord_t& radius, const Polygons& current_outline, const BoundingBox& current_outlines_bbox, const Polygons& current_overhang) :
m_cell_size(radius / radius_per_cell_size), m_cell_size(radius / radius_per_cell_size),
m_supporting_radius(radius), m_supporting_radius(radius),
@ -19,8 +42,9 @@ DistanceField::DistanceField(const coord_t& radius, const Polygons& current_outl
{ {
m_supporting_radius2 = Slic3r::sqr(int64_t(radius)); m_supporting_radius2 = Slic3r::sqr(int64_t(radius));
// Sample source polygons with a regular grid sampling pattern. // Sample source polygons with a regular grid sampling pattern.
const BoundingBox overhang_bbox = get_extents(current_overhang);
for (const ExPolygon &expoly : union_ex(current_overhang)) { for (const ExPolygon &expoly : union_ex(current_overhang)) {
const Points sampled_points = sample_grid_pattern(expoly, m_cell_size); const Points sampled_points = sample_grid_pattern(expoly, m_cell_size, overhang_bbox);
const size_t unsupported_points_prev_size = m_unsupported_points.size(); const size_t unsupported_points_prev_size = m_unsupported_points.size();
m_unsupported_points.resize(unsupported_points_prev_size + sampled_points.size()); m_unsupported_points.resize(unsupported_points_prev_size + sampled_points.size());
@ -59,6 +83,13 @@ DistanceField::DistanceField(const coord_t& radius, const Polygons& current_outl
// Because the distance between two points is at least one axis equal to m_cell_size, every cell // Because the distance between two points is at least one axis equal to m_cell_size, every cell
// in m_unsupported_points_grid contains exactly one point. // in m_unsupported_points_grid contains exactly one point.
assert(m_unsupported_points.size() == m_unsupported_points_grid.size()); assert(m_unsupported_points.size() == m_unsupported_points_grid.size());
#ifdef LIGHTNING_DISTANCE_FIELD_DEBUG_OUTPUT
{
static int iRun = 0;
export_distance_field_to_svg(debug_out_path("FillLightning-DistanceField-%d.svg", iRun++), current_outline, current_overhang, m_unsupported_points);
}
#endif
} }
void DistanceField::update(const Point& to_node, const Point& added_leaf) void DistanceField::update(const Point& to_node, const Point& added_leaf)

View File

@ -8,6 +8,8 @@
#include "../../Point.hpp" #include "../../Point.hpp"
#include "../../Polygon.hpp" #include "../../Polygon.hpp"
//#define LIGHTNING_DISTANCE_FIELD_DEBUG_OUTPUT
namespace Slic3r::FillLightning namespace Slic3r::FillLightning
{ {
@ -196,6 +198,10 @@ protected:
Point from_grid_point(const Point &point) const { Point from_grid_point(const Point &point) const {
return point * m_cell_size + m_unsupported_points_bbox.min; return point * m_cell_size + m_unsupported_points_bbox.min;
} }
#ifdef LIGHTNING_DISTANCE_FIELD_DEBUG_OUTPUT
friend void export_distance_field_to_svg(const std::string &path, const Polygons &outline, const Polygons &overhang, const std::list<DistanceField::UnsupportedCell> &unsupported_points, const Points &points);
#endif
}; };
} // namespace Slic3r::FillLightning } // namespace Slic3r::FillLightning