Refactored Lightning infill to get rid of unnecessary std::list and std::unordered_map, which was slow.
This commit is contained in:
parent
3e5272868d
commit
5205753787
@ -35,16 +35,18 @@ DistanceField::DistanceField(const coord_t& radius, const Polygons& current_outl
|
||||
assert(m_unsupported_points_bbox.contains(p));
|
||||
}
|
||||
}
|
||||
m_unsupported_points.sort([&radius](const UnsupportedCell &a, const UnsupportedCell &b) {
|
||||
std::stable_sort(m_unsupported_points.begin(), m_unsupported_points.end(), [&radius](const UnsupportedCell &a, const UnsupportedCell &b) {
|
||||
constexpr coord_t prime_for_hash = 191;
|
||||
return std::abs(b.dist_to_boundary - a.dist_to_boundary) > radius ?
|
||||
a.dist_to_boundary < b.dist_to_boundary :
|
||||
(PointHash{}(a.loc) % prime_for_hash) < (PointHash{}(b.loc) % prime_for_hash);
|
||||
});
|
||||
for (auto it = m_unsupported_points.begin(); it != m_unsupported_points.end(); ++it) {
|
||||
UnsupportedCell& cell = *it;
|
||||
m_unsupported_points_grid.emplace(this->to_grid_point(cell.loc), it);
|
||||
}
|
||||
|
||||
m_unsupported_points_erased.resize(m_unsupported_points.size());
|
||||
std::fill(m_unsupported_points_erased.begin(), m_unsupported_points_erased.end(), false);
|
||||
|
||||
m_unsupported_points_grid.initialize(m_unsupported_points, [&self = std::as_const(*this)](const Point &p) -> Point { return self.to_grid_point(p); });
|
||||
|
||||
// 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.
|
||||
assert(m_unsupported_points.size() == m_unsupported_points_grid.size());
|
||||
@ -96,12 +98,11 @@ void DistanceField::update(const Point& to_node, const Point& added_leaf)
|
||||
}
|
||||
// Inside a circle at the end of the new leaf, or inside a rotated rectangle.
|
||||
// Remove unsupported leafs at this grid location.
|
||||
if (auto it = m_unsupported_points_grid.find(grid_addr); it != m_unsupported_points_grid.end()) {
|
||||
std::list<UnsupportedCell>::iterator& list_it = it->second;
|
||||
UnsupportedCell& cell = *list_it;
|
||||
if (const size_t cell_idx = m_unsupported_points_grid.find_cell_idx(grid_addr); cell_idx != std::numeric_limits<size_t>::max()) {
|
||||
const UnsupportedCell &cell = m_unsupported_points[cell_idx];
|
||||
if ((cell.loc - added_leaf).cast<int64_t>().squaredNorm() <= m_supporting_radius2) {
|
||||
m_unsupported_points.erase(list_it);
|
||||
m_unsupported_points_grid.erase(it);
|
||||
m_unsupported_points_erased[cell_idx] = true;
|
||||
m_unsupported_points_grid.mark_erased(grid_addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -38,12 +38,18 @@ public:
|
||||
* \return ``true`` if successful, or ``false`` if there are no more points
|
||||
* to consider.
|
||||
*/
|
||||
bool tryGetNextPoint(Point* p) const {
|
||||
if (m_unsupported_points.empty())
|
||||
return false;
|
||||
*p = m_unsupported_points.front().loc;
|
||||
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.
|
||||
@ -87,7 +93,8 @@ protected:
|
||||
/*!
|
||||
* Cells which still need to be supported at some point.
|
||||
*/
|
||||
std::list<UnsupportedCell> m_unsupported_points;
|
||||
std::vector<UnsupportedCell> m_unsupported_points;
|
||||
std::vector<bool> m_unsupported_points_erased;
|
||||
|
||||
/*!
|
||||
* BoundingBox of all points in m_unsupported_points. Used for mapping of sign integer numbers to positive integer numbers.
|
||||
@ -98,7 +105,84 @@ protected:
|
||||
* 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.
|
||||
*/
|
||||
std::unordered_map<Point, std::list<UnsupportedCell>::iterator, PointHash> m_unsupported_points_grid;
|
||||
|
||||
class UnsupportedPointsGrid
|
||||
{
|
||||
public:
|
||||
UnsupportedPointsGrid() = default;
|
||||
void initialize(const std::vector<UnsupportedCell> &unsupported_points, const std::function<Point(const Point &)> &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<size_t>::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<size_t>::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<size_t>::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<size_t>::max());
|
||||
return m_data[flat_idx];
|
||||
}
|
||||
|
||||
return std::numeric_limits<size_t>::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<size_t>::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<size_t> m_data;
|
||||
std::vector<bool> 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 < m_grid_size.y() * m_grid_size.x());
|
||||
return flat_idx;
|
||||
}
|
||||
};
|
||||
|
||||
UnsupportedPointsGrid m_unsupported_points_grid;
|
||||
|
||||
/*!
|
||||
* Maps the point to the grid coordinates.
|
||||
|
@ -56,8 +56,9 @@ void Layer::generateNewTrees
|
||||
|
||||
// Until no more points need to be added to support all:
|
||||
// Determine next point from tree/outline areas via distance-field
|
||||
size_t unsupported_cell_idx = 0;
|
||||
Point unsupported_location;
|
||||
while (distance_field.tryGetNextPoint(&unsupported_location)) {
|
||||
while (distance_field.tryGetNextPoint(&unsupported_location, &unsupported_cell_idx, unsupported_cell_idx)) {
|
||||
throw_on_cancel_callback();
|
||||
GroundingLocation grounding_loc = getBestGroundingLocation(
|
||||
unsupported_location, current_outlines, current_outlines_bbox, outlines_locator, supporting_radius, wall_supporting_radius, tree_node_locator);
|
||||
|
Loading…
Reference in New Issue
Block a user