TraceMaker
C++ API of the engine
Loading...
Searching...
No Matches
uniform_grid.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-3.0-or-later
2#pragma once
3// Uniform spatial hash grid over a bounding box (design doc 03 ยง2): O(1) insert, box queries return each
4// id at most once per query via a generation stamp.
5#include <algorithm>
6#include <cstdint>
7#include <vector>
8
9#include "geom/point.hpp"
10
11namespace tmk::index {
12
14 public:
15 UniformGrid(geom::Box bounds, Coord cell, std::size_t max_ids)
16 : b_(bounds), cell_(std::max<Coord>(cell, 1)), stamp_(max_ids, 0) {
17 nx_ = static_cast<int>((b_.x1 - b_.x0) / cell_) + 1;
18 ny_ = static_cast<int>((b_.y1 - b_.y0) / cell_) + 1;
19 cells_.resize(static_cast<std::size_t>(nx_) * static_cast<std::size_t>(ny_));
20 }
21
22 void insert(int id, const geom::Box& box) {
23 if (static_cast<std::size_t>(id) >= stamp_.size()) stamp_.resize(static_cast<std::size_t>(id) * 2 + 16, 0);
24 int x0, y0, x1, y1;
25 range(box, x0, y0, x1, y1);
26 for (int y = y0; y <= y1; ++y)
27 for (int x = x0; x <= x1; ++x) cells_[idx(x, y)].push_back(id);
28 }
29
30 // Calls f(id) once for every id whose inserted box shares a cell with `box`.
31 // Removes `id` from the cells of `box` (the box it was inserted with).
32 void erase(int id, const geom::Box& box) {
33 int x0, y0, x1, y1;
34 range(box, x0, y0, x1, y1);
35 for (int y = y0; y <= y1; ++y)
36 for (int x = x0; x <= x1; ++x) std::erase(cells_[idx(x, y)], id);
37 }
38
39 template <class F>
40 void query(const geom::Box& box, F&& f) {
41 if (++gen_ == 0) {
42 std::fill(stamp_.begin(), stamp_.end(), 0u);
43 gen_ = 1;
44 }
45 int x0, y0, x1, y1;
46 range(box, x0, y0, x1, y1);
47 for (int y = y0; y <= y1; ++y)
48 for (int x = x0; x <= x1; ++x)
49 for (int id : cells_[idx(x, y)]) {
50 auto& s = stamp_[static_cast<std::size_t>(id)];
51 if (s == gen_) continue;
52 s = gen_;
53 f(id);
54 }
55 }
56
57 private:
58 std::size_t idx(int x, int y) const { return static_cast<std::size_t>(y) * static_cast<std::size_t>(nx_) + static_cast<std::size_t>(x); }
59 void range(const geom::Box& box, int& x0, int& y0, int& x1, int& y1) const {
60 auto cx = [&](Coord v) { return std::clamp(static_cast<int>((v - b_.x0) / cell_), 0, nx_ - 1); };
61 auto cy = [&](Coord v) { return std::clamp(static_cast<int>((v - b_.y0) / cell_), 0, ny_ - 1); };
62 x0 = cx(box.x0); x1 = cx(box.x1); y0 = cy(box.y0); y1 = cy(box.y1);
63 }
64
65 geom::Box b_;
66 Coord cell_;
67 int nx_ = 1, ny_ = 1;
68 std::vector<std::vector<int>> cells_;
69 std::vector<std::uint32_t> stamp_;
70 std::uint32_t gen_ = 0;
71};
72
73} // namespace tmk::index
void query(const geom::Box &box, F &&f)
void erase(int id, const geom::Box &box)
Calls f(id) once for every id whose inserted box shares a cell with box.
UniformGrid(geom::Box bounds, Coord cell, std::size_t max_ids)
void insert(int id, const geom::Box &box)
std::int64_t Coord
Engine coordinate: signed 64-bit nanometres.
Definition units.hpp:12
Integer-nanometre points and KiCad-compatible rotation.
Coord y1
empty when x1 < x0
Definition point.hpp:21