FhSim  3.1.0
Marine systems simulation
Loading...
Searching...
No Matches
HashGrid.h
1#pragma once
2
8#include <algorithm>
9#include <cmath>
10#include <cstddef>
11#include <cstdint>
12#include <limits>
13#include <span>
14#include <vector>
15
16namespace environment::field::aggregation
17{
18
20struct Box
21{
22 float xMin = 0.0F;
23 float xMax = 0.0F;
24 float yMin = 0.0F;
25 float yMax = 0.0F;
26 float zMin = 0.0F;
27 float zMax = 0.0F;
28};
29
31[[nodiscard]] inline float RoundDown(double v)
32{
33 const float f = static_cast<float>(v);
34 return static_cast<double>(f) > v ? std::nextafter(f, -std::numeric_limits<float>::infinity()) : f;
35}
36
38[[nodiscard]] inline float RoundUp(double v)
39{
40 const float f = static_cast<float>(v);
41 return static_cast<double>(f) < v ? std::nextafter(f, std::numeric_limits<float>::infinity()) : f;
42}
43
45[[nodiscard]] inline bool Overlaps(const Box& a, const Box& b)
46{
47 return a.xMax >= b.xMin && a.xMin <= b.xMax && a.yMax >= b.yMin && a.yMin <= b.yMax && a.zMax >= b.zMin && a.zMin <= b.zMax;
48}
49
59{
60public:
62 static constexpr std::size_t kMaxCells = 4'000'000;
63
65 HashGrid() = default;
66
73 HashGrid(std::span<const Box> boxes, double cellSize);
74
76 [[nodiscard]] double CellSize() const { return m_cellSize; }
77
79 [[nodiscard]] std::size_t CellCount() const { return static_cast<std::size_t>(m_nx) * static_cast<std::size_t>(m_ny); }
80
85 template <class Visitor>
86 void ForEachCandidate(const Box& query, Visitor&& visit) const
87 {
88 if (m_entries.empty()) {
89 return;
90 }
91 const int ix0 = CellX(query.xMin);
92 const int ix1 = CellX(query.xMax);
93 const int iy0 = CellY(query.yMin);
94 const int iy1 = CellY(query.yMax);
95 for (int iy = iy0; iy <= iy1; ++iy) {
96 for (int ix = ix0; ix <= ix1; ++ix) {
97 const std::size_t cell = static_cast<std::size_t>(iy) * static_cast<std::size_t>(m_nx) + static_cast<std::size_t>(ix);
98 for (std::uint32_t k = m_cellStart[cell]; k < m_cellStart[cell + 1]; ++k) {
99 const Entry& e = m_entries[k];
100 // Report the box in the first cell that the box and the query share.
101 if (std::max(e.ix0, ix0) != ix || std::max(e.iy0, iy0) != iy) {
102 continue;
103 }
104 if (Overlaps(e.box, query)) {
105 visit(e.id);
106 }
107 }
108 }
109 }
110 }
111
113 void Candidates(const Box& query, std::vector<std::uint32_t>& out) const;
114
115private:
116 struct Entry
117 {
118 std::uint32_t id = 0;
119 std::int32_t ix0 = 0;
120 std::int32_t iy0 = 0;
121 Box box;
122 };
123
124 [[nodiscard]] int CellX(double x) const { return CellIndex(x, m_originX, m_nx); }
125 [[nodiscard]] int CellY(double y) const { return CellIndex(y, m_originY, m_ny); }
126 [[nodiscard]] int CellIndex(double v, double origin, int count) const
127 {
128 const double cell = std::floor((v - origin) * m_inverseCell);
129 return static_cast<int>(std::clamp(cell, 0.0, static_cast<double>(count - 1)));
130 }
131
132 double m_cellSize = 1.0;
133 double m_inverseCell = 1.0;
134 double m_originX = 0.0;
135 double m_originY = 0.0;
136 int m_nx = 0;
137 int m_ny = 0;
138 std::vector<std::uint32_t> m_cellStart;
139 std::vector<Entry> m_entries;
140};
141
142} // namespace environment::field::aggregation
HashGrid(std::span< const Box > boxes, double cellSize)
HashGrid()=default
An empty grid; every query reports nothing.
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).
void ForEachCandidate(const Box &query, Visitor &&visit) const
Definition HashGrid.h:86
double CellSize() const
The cell edge in use [m].
Definition HashGrid.h:76
static constexpr std::size_t kMaxCells
The largest number of cells; a larger domain gets larger cells.
Definition HashGrid.h:62
std::size_t CellCount() const
The number of cells.
Definition HashGrid.h:79
An axis-aligned box, NED [m]. Closed: a box that only touches another one overlaps it.
Definition HashGrid.h:21