FhSim  3.1.0
Marine systems simulation
Loading...
Searching...
No Matches
TiledGrid.h
1#pragma once
2
8#include "HashGrid.h"
9
10#include <algorithm>
11#include <array>
12#include <cmath>
13#include <cstddef>
14#include <cstdint>
15#include <memory>
16#include <span>
17#include <vector>
18
19namespace environment::field::aggregation
20{
21
23[[nodiscard]] double MedianLongerSide(std::span<const Box> boxes);
24
36{
37public:
39 static constexpr int kTileSide = 8;
41 static constexpr int kTileCells = kTileSide * kTileSide;
42
44 struct Item
45 {
46 std::uint32_t id = 0;
47 Box box;
48 };
49
51 TiledGrid() = default;
52
59 TiledGrid(double xMin, double xMax, double yMin, double yMax, double cellSize);
60
62 [[nodiscard]] bool HasExtent() const { return m_nx > 0; }
63
65 [[nodiscard]] double CellSize() const { return m_cellSize; }
66
68 [[nodiscard]] std::size_t CellCount() const { return static_cast<std::size_t>(m_nx) * static_cast<std::size_t>(m_ny); }
69
71 [[nodiscard]] std::size_t TileCount() const { return m_tiles.size(); }
72
74 [[nodiscard]] std::size_t SharedTileCount(const TiledGrid& other) const
75 {
76 std::size_t shared = 0;
77 for (std::size_t t = 0; t < std::min(m_tiles.size(), other.m_tiles.size()); ++t) {
78 shared += m_tiles[t] != nullptr && m_tiles[t] == other.m_tiles[t] ? 1 : 0;
79 }
80 return shared;
81 }
82
84 [[nodiscard]] std::size_t FilledTileCount() const
85 {
86 return static_cast<std::size_t>(std::count_if(m_tiles.begin(), m_tiles.end(), [](const auto& tile) { return tile != nullptr; }));
87 }
88
90 [[nodiscard]] std::size_t OverflowCount() const { return m_overflow ? m_overflow->size() : 0; }
91
93 [[nodiscard]] bool Inside(const Box& box) const
94 {
95 return box.xMin >= m_extent.xMin && box.xMax <= m_extent.xMax && box.yMin >= m_extent.yMin && box.yMax <= m_extent.yMax;
96 }
97
103 [[nodiscard]] TiledGrid With(std::span<const Item> removed, std::span<const Item> added) const;
104
106 [[nodiscard]] TiledGrid Cleared() const;
107
113 template<class Visitor>
114 void ForEachCandidate(const Box& query, Visitor&& visit) const
115 {
116 if (m_nx > 0) {
117 const int ix0 = CellX(query.xMin);
118 const int ix1 = CellX(query.xMax);
119 const int iy0 = CellY(query.yMin);
120 const int iy1 = CellY(query.yMax);
121 for (int iy = iy0; iy <= iy1; ++iy) {
122 for (int ix = ix0; ix <= ix1; ++ix) {
123 const Tile* tile = m_tiles[TileIndex(ix, iy)].get();
124 if (tile == nullptr) {
125 continue;
126 }
127 const std::size_t local = LocalCell(ix, iy);
128 for (std::uint32_t k = tile->start[local]; k < tile->start[local + 1]; ++k) {
129 const Entry& e = tile->entries[k];
130 // Report the box in the first cell that the box and the query share.
131 if (std::max(e.ix0, ix0) != ix || std::max(e.iy0, iy0) != iy) {
132 continue;
133 }
134 if (Overlaps(e.box, query)) {
135 visit(e.id);
136 }
137 }
138 }
139 }
140 }
141 if (m_overflow) {
142 for (const Entry& e : *m_overflow) {
143 if (Overlaps(e.box, query)) {
144 visit(e.id);
145 }
146 }
147 }
148 }
149
151 void Candidates(const Box& query, std::vector<std::uint32_t>& out) const;
152
153private:
154 struct Entry
155 {
156 std::uint32_t id = 0;
157 std::int32_t ix0 = 0;
158 std::int32_t iy0 = 0;
159 Box box;
160 };
161
163 struct Tile
164 {
165 std::array<std::uint32_t, kTileCells + 1> start {};
166 std::vector<Entry> entries;
167 };
168
170 struct Placed
171 {
172 std::size_t tile = 0;
173 std::uint32_t local = 0;
174 Entry entry;
175 };
176
177 [[nodiscard]] int CellX(double x) const { return CellIndex(x, m_originX, m_nx); }
178 [[nodiscard]] int CellY(double y) const { return CellIndex(y, m_originY, m_ny); }
179 [[nodiscard]] int CellIndex(double v, double origin, int count) const
180 {
181 const double cell = std::floor((v - origin) * m_inverseCell);
182 return static_cast<int>(std::clamp(cell, 0.0, static_cast<double>(count - 1)));
183 }
184 [[nodiscard]] std::size_t TileIndex(int ix, int iy) const
185 {
186 return static_cast<std::size_t>(iy / kTileSide) * static_cast<std::size_t>(m_tilesX) + static_cast<std::size_t>(ix / kTileSide);
187 }
188 [[nodiscard]] static std::size_t LocalCell(int ix, int iy)
189 {
190 return static_cast<std::size_t>(iy % kTileSide) * static_cast<std::size_t>(kTileSide) + static_cast<std::size_t>(ix % kTileSide);
191 }
192
194 void Place(const Item& item, std::vector<Placed>& out) const;
195
196 double m_cellSize = 1.0;
197 double m_inverseCell = 1.0;
198 double m_originX = 0.0;
199 double m_originY = 0.0;
200 int m_nx = 0;
201 int m_ny = 0;
202 int m_tilesX = 0;
203 Box m_extent;
204 std::vector<std::shared_ptr<const Tile>> m_tiles;
205 std::shared_ptr<const std::vector<Entry>> m_overflow;
206};
207
208} // namespace environment::field::aggregation
bool Inside(const Box &box) const
True when the box is inside the extent (so it goes into the cells, not the overflow list).
Definition TiledGrid.h:93
TiledGrid With(std::span< const Item > removed, std::span< const Item > added) const
std::size_t CellCount() const
The number of cells.
Definition TiledGrid.h:68
static constexpr int kTileCells
Cells per tile.
Definition TiledGrid.h:41
TiledGrid()=default
An empty grid with no extent; With() must not be called on it.
double CellSize() const
The cell edge in use [m].
Definition TiledGrid.h:65
bool HasExtent() const
True when the grid has an extent (was made with the extent constructor).
Definition TiledGrid.h:62
std::size_t OverflowCount() const
The number of boxes in the overflow list.
Definition TiledGrid.h:90
std::size_t TileCount() const
The number of tiles (with or without entries).
Definition TiledGrid.h:71
void ForEachCandidate(const Box &query, Visitor &&visit) const
Definition TiledGrid.h:114
static constexpr int kTileSide
Cells per tile side.
Definition TiledGrid.h:39
TiledGrid(double xMin, double xMax, double yMin, double yMax, double cellSize)
std::size_t FilledTileCount() const
The number of tiles with entries.
Definition TiledGrid.h:84
std::size_t SharedTileCount(const TiledGrid &other) const
Test hook: the number of tiles with entries that this grid shares (same object) with other.
Definition TiledGrid.h:74
void Candidates(const Box &query, std::vector< std::uint32_t > &out) const
Appends the ids of the boxes that overlap the query box to out (cleared first).
TiledGrid Cleared() const
A grid with the same geometry and no boxes.
An axis-aligned box, NED [m]. Closed: a box that only touches another one overlaps it.
Definition HashGrid.h:21
One box with its id (slot), for With().
Definition TiledGrid.h:45