VIPRA Documentation
Loading...
Searching...
No Matches
potential_field.hpp
1#pragma once
2
3#include <stdexcept>
4
5#include "vipra/geometry/f3d.hpp"
6#include "vipra/macros/goals.hpp"
7#include "vipra/macros/module.hpp"
8#include "vipra/macros/parameters.hpp"
9
10#include "vipra/modules/goals.hpp"
11#include "vipra/modules/module.hpp"
12#include "vipra/types/float.hpp"
13
14#include "density_grid.hpp"
15#include "grid.hpp"
16
17namespace VIPRA::Goals {
18class PotentialField : public VIPRA::Modules::Module<PotentialField>,
20 public:
21 VIPRA_MODULE_NAME("PotentialField")
22 VIPRA_MODULE_TYPE(Goals)
23
24 VIPRA_REGISTER_PARAMS(VIPRA_PARAM("endGoalType", _endGoalType),
25 VIPRA_PARAM("cellSize", _cellSize),
26 VIPRA_PARAM("densityUpdateFrequency", _densityUpdateFrequency),
27 VIPRA_PARAM("densityCellSize", _densityCellSize),
28 VIPRA_PARAM("densityWeight", _densityWeight))
29
30 VIPRA_GOALS_RESET {}
31
32 // NOLINTNEXTLINE(misc-unused-parameters)
33 VIPRA_GOALS_INIT_STEP
34 {
35 _field.intialize(map, _cellSize);
36 _densityMap.intialize(map, _densityCellSize);
37 fill_grid(map);
38
39 for ( VIPRA::idx pedIdx = 0; pedIdx < pedset.num_pedestrians(); ++pedIdx ) {
40 VIPRA::f3d pos = pedset.ped_coords(pedIdx);
41 auto const& grid = _field.get_grid(pos);
42
43 if ( grid.end == _emptyf3d_ )
44 VIPRA_MODULE_ERROR(
45 "No path found for pedestrian {}, Start: ({}, {}), End: ({}, {})", pedIdx,
46 pos.x, pos.y, end_goal(pedIdx).x, end_goal(pedIdx).y);
47
48 set_current_goal(pedIdx, pos + grid.direction);
49 set_end_goal(pedIdx, grid.end);
50 }
51 }
52
53 // NOLINTNEXTLINE(misc-unused-parameters)
54 VIPRA_GOALS_UPDATE_STEP
55 {
56 _densityCheckCounter++;
57
58 // Probably a better way to do this that doesn't reuse code, but this avoids repeating the same check every single loop.
59 // Who knows, maybe compiler would have already optimized this.
60 if ( _densityCheckCounter >= _densityUpdateFrequency ) {
61 fill_grid(map);
62
63 for ( VIPRA::idx pedIdx = 0; pedIdx < pedset.num_pedestrians(); ++pedIdx ) {
64 VIPRA::f3d pos = pedset.ped_coords(pedIdx);
65 VIPRA::f3d direction = _field.get_grid(pos).direction;
66
67 set_current_goal(pedIdx, pos + direction);
68 update_ped_density(pos);
69 }
70
71 _densityMap.clear_grid();
72
73 _densityCheckCounter = 0;
74 return;
75 }
76
77 for ( VIPRA::idx pedIdx = 0; pedIdx < pedset.num_pedestrians(); ++pedIdx ) {
78 VIPRA::f3d pos = pedset.ped_coords(pedIdx);
79 VIPRA::f3d direction = _field.get_grid(pos).direction;
80
81 set_current_goal(pedIdx, pos + direction);
82 }
83 }
84
85 // NOLINTNEXTLINE(misc-unused-parameters)
86 VIPRA_GOALS_NEXT_GOAL { return false; }
87
88 // NOLINTNEXTLINE(misc-unused-parameters)
89 VIPRA_GOALS_CHANGE_GOAL
90 {
91 throw std::runtime_error("Potential Field Goals is unable to change goals");
92 }
93
94 private:
95 // TODO(rolland): update SpatialMap to handle this use case
96 Grid _field;
97 DensityGrid _densityMap;
98
99 int _densityCheckCounter;
100
101 VIPRA::f_pnt _cellSize{};
102 VIPRA::f_pnt _densityCellSize{};
103 VIPRA::f_pnt _densityWeight{};
104
105 std::string _endGoalType;
106 int _densityUpdateFrequency;
107
108 void fill_grid(VIPRA::Modules::Map const& map)
109 { // find the end goals, provided as a module parameter
110 auto const& objectives = map.get_objectives(_endGoalType);
111 if ( objectives.empty() ) {
112 throw std::runtime_error("No objectives of type " + _endGoalType + " found in map");
113 }
114
115 for ( auto const& objective : objectives ) {
116 _field.flood_fill(objective.center(), map, _densityMap);
117 }
118 }
119
120 void update_ped_density(VIPRA::f3d const& ped) { _densityMap.incr_gridpoint(ped); }
121};
122} // namespace VIPRA::Goals
Definition density_grid.hpp:20
void incr_gridpoint(VIPRA::f3d const &pos)
Increments the pedestrian count at the grid index that contains the point.
Definition density_grid.hpp:68
Definition grid.hpp:21
Definition potential_field.hpp:19
Goals module mixin.
Definition goals.hpp:26
Base Map Module Class.
Definition map.hpp:23
VIPRA Module Base CRTP Class.
Definition module.hpp:36
Definition f3d.hpp:27