VIPRA Documentation
Loading...
Searching...
No Matches
spatial_map.hpp
1#pragma once
2
3// TODO(rolland): issue #16 complete proper implementation
4
5#include <stdexcept>
6#include <vector>
7
8#include "vipra/geometry/f3d.hpp"
9
10#include "vipra/macros/performance.hpp"
11
12#include "vipra/types/float.hpp"
13#include "vipra/types/idx.hpp"
14#include "vipra/types/size.hpp"
15
16namespace VIPRA::DataStructures {
17template <typename data_t>
19 public:
20 void clear() { _grid.clear(); }
21
22 void update_grids(std::vector<VIPRA::f3d> const& oldPositions,
23 std::vector<VIPRA::f3d> const& newPositions)
24 {
25 // for all of the data, check if they moved grids, if they did update both
26 for ( VIPRA::idx currIdx = 0; currIdx < newPositions.size(); ++currIdx ) {
27 auto& oldGrid = get_grid(oldPositions[currIdx]);
28 auto& newGrid = get_grid(newPositions[currIdx]);
29
30 if ( &oldGrid == &newGrid ) continue;
31
32 oldGrid.erase(std::remove(oldGrid.begin(), oldGrid.end(), currIdx), oldGrid.end());
33 newGrid.push_back(currIdx);
34 }
35 }
36
37 void for_each_neighbor(VIPRA::f3d const& pos, auto&& func) const
38 {
39 // TODO(rolland, issue #40) this only gets the surrounding 9 grids
40
41 // Loop through the surrounding grids and call the provided function with each pedestrian in each grid
42 for ( int i = -1; i <= 1; ++i ) {
43 for ( int j = -1; j <= 1; ++j ) {
44 if ( out_of_bounds(pos.x + i * _cellSize, pos.y + j * _cellSize) ) continue;
45
46 auto const& neighbor =
47 get_grid(VIPRA::f3d{pos.x + i * _cellSize, pos.y + j * _cellSize});
48
49 for ( auto value : neighbor ) {
50 func(value);
51 }
52 }
53 }
54 }
55
56 void initialize(VIPRA::f_pnt cellSize, VIPRA::f_pnt width, VIPRA::f_pnt height,
57 std::vector<VIPRA::f3d> const& positions,
58 std::vector<data_t> const& data)
59 {
60 assert(cellSize != 0);
61 assert(width != 0);
62 assert(height != 0);
63
64 _cellSize = cellSize;
65 set_grids(width, height);
66 initialize_grids(positions, data);
67 }
68
69 private:
70 std::vector<std::vector<data_t>> _grid;
71 VIPRA::size _rows{};
72 VIPRA::size _cols{};
73 VIPRA::f_pnt _cellSize{};
74
75 void set_grids(VIPRA::f_pnt width, VIPRA::f_pnt height)
76 {
77 _rows = static_cast<size_t>(std::ceil(height / _cellSize));
78 _cols = static_cast<size_t>(std::ceil(width / _cellSize));
79 _grid.resize(_rows * _cols);
80 }
81
82 void initialize_grids(std::vector<VIPRA::f3d> const& positions,
83 std::vector<data_t> const& data)
84 {
85 if ( positions.size() != data.size() )
86 throw std::logic_error(
87 "Spatial Map initialized with differing counts of data and "
88 "positions");
89
90 // Create grids
91 for ( auto& grid : _grid ) {
92 grid = std::vector<data_t>();
93 }
94
95 // Add all of the pedestrians in each grid to their respective grid
96 for ( VIPRA::idx currIdx = 0; currIdx < positions.size(); ++currIdx ) {
97 auto& grid = get_grid(positions[currIdx]);
98 grid.push_back(data[currIdx]);
99 }
100 }
101
108 [[nodiscard]] VIPRA_INLINE auto get_grid(VIPRA::f3d pos) -> std::vector<VIPRA::idx>&
109 {
110 assert(! out_of_bounds(pos));
111
112 auto gridX = static_cast<size_t>(pos.x / _cellSize);
113 auto gridY = static_cast<size_t>(pos.y / _cellSize);
114
115 return _grid[gridX + gridY * _cols];
116 }
117
124 [[nodiscard]] VIPRA_INLINE auto get_grid(VIPRA::f3d pos) const
125 -> std::vector<VIPRA::idx> const&
126 {
127 assert(! out_of_bounds(pos));
128
129 return _grid[static_cast<size_t>(pos.x / _cellSize) +
130 static_cast<size_t>(pos.y / _cellSize) * _cols];
131 }
132
141 [[nodiscard]] VIPRA_INLINE auto out_of_bounds(VIPRA::f_pnt gridX,
142 VIPRA::f_pnt gridY) const -> bool
143 {
144 return gridX < 0 || gridX >= _cols * _cellSize || gridY < 0 ||
145 gridY >= _rows * _cellSize;
146 }
147
156 [[nodiscard]] VIPRA_INLINE auto out_of_bounds(VIPRA::f3d pos) const -> bool
157 {
158 return out_of_bounds(pos.x, pos.y);
159 }
160};
161} // namespace VIPRA::DataStructures
Definition spatial_map.hpp:18
Definition f3d.hpp:27