//Copyright (c) 2021 Ultimaker B.V. //CuraEngine is released under the terms of the AGPLv3 or higher. #ifndef LIGHTNING_DISTANCE_FIELD_H #define LIGHTNING_DISTANCE_FIELD_H #include "../../BoundingBox.hpp" #include "../../Point.hpp" #include "../../Polygon.hpp" //#define LIGHTNING_DISTANCE_FIELD_DEBUG_OUTPUT namespace Slic3r::FillLightning { /*! * 2D field that maintains locations which need to be supported for Lightning * Infill. * * This field contains a set of "cells", spaced out in a grid. Each cell * maintains how far it is removed from the edge, which is used to determine * how it gets supported by Lightning Infill. */ class DistanceField { public: /*! * Construct a new field to calculate Lightning Infill with. * \param radius The radius of influence that an infill line is expected to * support in the layer above. * \param current_outline The total infill area on this layer. * \param current_overhang The overhang that needs to be supported on this * layer. */ DistanceField(const coord_t& radius, const Polygons& current_outline, const BoundingBox& current_outlines_bbox, const Polygons& current_overhang); /*! * Gets the next unsupported location to be supported by a new branch. * \param p Output variable for the next point to support. * \return ``true`` if successful, or ``false`` if there are no more points * to consider. */ bool tryGetNextPoint(Point *out_unsupported_location, size_t *out_unsupported_cell_idx, const size_t start_idx = 0) const { for (size_t point_idx = start_idx; point_idx < m_unsupported_points.size(); ++point_idx) { if (!m_unsupported_points_erased[point_idx]) { *out_unsupported_cell_idx = point_idx; *out_unsupported_location = m_unsupported_points[point_idx].loc; return true; } } return false; } /*! * Update the distance field with a newly added branch. * * The branch is a line extending from \p to_node to \p added_leaf . This * function updates the grid cells so that the distance field knows how far * off it is from being supported by the current pattern. Grid points are * updated with sampling points spaced out by the supporting radius along * the line. * \param to_node The node endpoint of the newly added branch. * \param added_leaf The location of the leaf of the newly added branch, * drawing a straight line to the node. */ void update(const Point& to_node, const Point& added_leaf); protected: /*! * Spacing between grid points to consider supporting. */ coord_t m_cell_size; /*! * The radius of the area of the layer above supported by a point on a * branch of a tree. */ coord_t m_supporting_radius; int64_t m_supporting_radius2; /*! * Represents a small discrete area of infill that needs to be supported. */ struct UnsupportedCell { // The position of the center of this cell. Point loc; // How far this cell is removed from the ``current_outline`` polygon, the edge of the infill area. coord_t dist_to_boundary; }; /*! * Cells which still need to be supported at some point. */ std::vector m_unsupported_points; std::vector m_unsupported_points_erased; /*! * BoundingBox of all points in m_unsupported_points. Used for mapping of sign integer numbers to positive integer numbers. */ const BoundingBox m_unsupported_points_bbox; /*! * Links the unsupported points to a grid point, so that we can quickly look * up the cell belonging to a certain position in the grid. */ class UnsupportedPointsGrid { public: UnsupportedPointsGrid() = default; void initialize(const std::vector &unsupported_points, const std::function &map_cell_to_grid) { if (unsupported_points.empty()) return; BoundingBox unsupported_points_bbox; for (const UnsupportedCell &cell : unsupported_points) unsupported_points_bbox.merge(cell.loc); m_size = unsupported_points.size(); m_grid_range = BoundingBox(map_cell_to_grid(unsupported_points_bbox.min), map_cell_to_grid(unsupported_points_bbox.max)); m_grid_size = m_grid_range.size() + Point::Ones(); m_data.assign(m_grid_size.y() * m_grid_size.x(), std::numeric_limits::max()); m_data_erased.assign(m_grid_size.y() * m_grid_size.x(), true); for (size_t cell_idx = 0; cell_idx < unsupported_points.size(); ++cell_idx) { const size_t flat_idx = map_to_flat_array(map_cell_to_grid(unsupported_points[cell_idx].loc)); assert(m_data[flat_idx] == std::numeric_limits::max()); m_data[flat_idx] = cell_idx; m_data_erased[flat_idx] = false; } } size_t size() const { return m_size; } size_t find_cell_idx(const Point &grid_addr) { if (!m_grid_range.contains(grid_addr)) return std::numeric_limits::max(); if (const size_t flat_idx = map_to_flat_array(grid_addr); !m_data_erased[flat_idx]) { assert(m_data[flat_idx] != std::numeric_limits::max()); return m_data[flat_idx]; } return std::numeric_limits::max(); } void mark_erased(const Point &grid_addr) { assert(m_grid_range.contains(grid_addr)); if (!m_grid_range.contains(grid_addr)) return; const size_t flat_idx = map_to_flat_array(grid_addr); assert(!m_data_erased[flat_idx] && m_data[flat_idx] != std::numeric_limits::max()); assert(m_size != 0); m_data_erased[flat_idx] = true; --m_size; } private: size_t m_size = 0; BoundingBox m_grid_range; Point m_grid_size; std::vector m_data; std::vector m_data_erased; inline size_t map_to_flat_array(const Point &loc) const { const Point offset_loc = loc - m_grid_range.min; const size_t flat_idx = m_grid_size.x() * offset_loc.y() + offset_loc.x(); assert(offset_loc.x() >= 0 && offset_loc.y() >= 0); assert(flat_idx < size_t(m_grid_size.y() * m_grid_size.x())); return flat_idx; } }; UnsupportedPointsGrid m_unsupported_points_grid; /*! * Maps the point to the grid coordinates. */ Point to_grid_point(const Point &point) const { return (point - m_unsupported_points_bbox.min) / m_cell_size; } /*! * Maps the point to the grid coordinates. */ Point from_grid_point(const Point &point) const { 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 &unsupported_points, const Points &points); #endif }; } // namespace Slic3r::FillLightning #endif //LIGHTNING_DISTANCE_FIELD_H