12#include <nlohmann/json.hpp>
14#include "vipra/geometry/f3d.hpp"
16#include "vipra/modules/map_input.hpp"
17#include "vipra/modules/param_reader.hpp"
18#include "vipra/modules/pedestrian_input.hpp"
19#include "vipra/modules/serializable.hpp"
21#include "vipra/geometry/polygon.hpp"
23#include "vipra/macros/errors.hpp"
24#include "vipra/util/is_map.hpp"
25#include "vipra/util/template_specialization.hpp"
27namespace VIPRA::Input {
37 using json_cref = std::reference_wrapper<const nlohmann::json>;
40 static constexpr auto module_name() ->
const char* {
return "JSON"; }
42 void load(std::string
const& filepath)
override;
44 template <
typename data_t>
45 [[nodiscard]]
auto get(std::vector<std::string>
const& keys)
const
46 -> std::optional<data_t>;
48 [[nodiscard]]
auto serialize() -> std::string
override {
return _json.dump(); }
50 [[nodiscard]]
auto get_pedestrians()
const -> std::optional<VIPRA::f3dVec>
override;
52 -> std::optional<std::vector<VIPRA::Geometry::Polygon>>
override;
54 -> std::optional<std::vector<VIPRA::Geometry::Polygon>>
override;
57 std::map<std::string, std::vector<VIPRA::Geometry::Polygon>>>
override;
59 -> std::optional<std::map<std::string, VIPRA::Geometry::Polygon>>
override;
64 template <
typename data_t>
65 [[nodiscard]]
auto get_value(json_cref
const& value)
const -> std::optional<data_t>;
67 [[nodiscard]]
static auto is_f3d(nlohmann::json
const& value) -> bool;
68 [[nodiscard]]
static auto is_f2d(nlohmann::json
const& value) -> bool;
69 [[nodiscard]]
static auto get_f3d(json_cref
const& value) -> std::optional<VIPRA::f3d>;
70 [[nodiscard]]
static auto get_f3d_vec(json_cref
const& value)
71 -> std::optional<VIPRA::f3dVec>;
73 template <
typename data_t>
74 [[nodiscard]]
auto get_vector(json_cref
const& value)
const
75 -> std::optional<std::vector<data_t>>;
77 template <
typename data_t>
78 [[nodiscard]]
auto get_map(json_cref
const& value)
const
79 -> std::optional<std::map<std::string, data_t>>;
81 [[nodiscard]]
static auto get_polygons(json_cref
const& value)
82 -> std::optional<std::vector<VIPRA::Geometry::Polygon>>;
84 [[nodiscard]]
auto get_value_at_key(std::vector<std::string>
const& keys)
const
85 -> std::optional<json_cref>
87 auto value = std::cref(_json);
90 std::for_each(keys.begin(), keys.end(), [&](std::string
const& key) {
91 if ( ! found ) return;
93 if ( ! value.get().contains(key) ) {
98 value = std::cref(value.get().at(key));
101 if ( ! found )
return std::nullopt;
107 void parse(std::string
const& data)
override
110 _json = nlohmann::json::parse(data);
112 catch ( nlohmann::json::parse_error
const& e ) {
113 VIPRA_MODULE_ERROR(
"Could not parse JSON data\n");
129template <
typename data_t>
131 -> std::optional<data_t>
133 auto value = get_value_at_key(keys);
134 if ( ! value )
return std::nullopt;
136 return get_value<data_t>(value.value());
146template <
typename data_t>
147[[nodiscard]]
auto VIPRA::Input::JSON::get_vector(json_cref
const& value)
const
148 -> std::optional<std::vector<data_t>>
150 if ( ! value.get().is_array() )
return std::nullopt;
152 std::vector<data_t> vec;
153 for (
auto const& element : value.get() ) {
154 auto elementValue = get_value<data_t>(std::cref(element));
155 if ( elementValue ) vec.emplace_back(*elementValue);
167[[nodiscard]]
inline auto VIPRA::Input::JSON::get_f3d_vec(json_cref
const& value)
168 -> std::optional<VIPRA::f3dVec>
170 if ( ! value.get().is_array() )
return std::nullopt;
172 VIPRA::f3dVec f3dVec;
173 for (
auto const& f3d : value.get() ) {
174 if ( ! is_f3d(f3d) ) {
175 if ( ! is_f2d(f3d) )
return std::nullopt;
177 f3dVec.emplace_back(f3d.at(
"x").get<VIPRA::f_pnt>(),
178 f3d.at(
"y").get<VIPRA::f_pnt>(), 0);
182 f3dVec.emplace_back(f3d.at(
"x").get<VIPRA::f_pnt>(), f3d.at(
"y").get<VIPRA::f_pnt>(),
183 f3d.at(
"z").get<VIPRA::f_pnt>());
195[[nodiscard]]
inline auto VIPRA::Input::JSON::get_f3d(json_cref
const& value)
196 -> std::optional<VIPRA::f3d>
198 if ( ! is_f3d(value.get()) )
return std::nullopt;
200 return VIPRA::f3d(value.get().at(
"x").get<VIPRA::f_pnt>(),
201 value.get().at(
"y").get<VIPRA::f_pnt>(),
202 value.get().at(
"z").get<VIPRA::f_pnt>());
212 if ( ! std::filesystem::exists(filepath) )
213 VIPRA_MODULE_ERROR(
"File does not exist at: {}", filepath);
215 if ( ! std::filesystem::is_regular_file(filepath) )
216 VIPRA_MODULE_ERROR(
"{} is not a file", filepath);
218 std::ifstream file(filepath, std::ios::in);
219 if ( ! file.is_open() ) VIPRA_MODULE_ERROR(
"Could not open file at: ", filepath);
222 _json = nlohmann::json::parse(file);
224 catch ( nlohmann::json::parse_error
const& e ) {
225 VIPRA_MODULE_ERROR(
"Could not parse JSON file at: {}\nnlohmann json error: {}",
239template <
typename data_t>
240[[nodiscard]]
auto VIPRA::Input::JSON::get_value(json_cref
const& value)
const
241 -> std::optional<data_t>
243 if constexpr ( std::is_same_v<data_t, VIPRA::f3d> ) {
244 return get_f3d(value);
247 else if constexpr ( std::is_same_v<data_t, VIPRA::f3dVec> ) {
248 return get_f3d_vec(value);
251 else if constexpr ( std::is_same_v<data_t, std::vector<VIPRA::Geometry::Polygon>> ) {
252 return get_polygons(value);
255 else if constexpr ( VIPRA::Util::is_specialization<data_t, std::vector>::value ) {
256 using value_t =
typename VIPRA::Util::get_specialization_internal<data_t>::type;
257 return get_vector<value_t>(value);
260 else if constexpr ( VIPRA::Util::is_map_v<data_t> ) {
261 using value_t =
typename VIPRA::Util::get_map_specialization<data_t>::value_t;
262 return get_map<value_t>(value);
267 return value.get().get<data_t>();
269 catch ( nlohmann::json::type_error
const& e ) {
277template <
typename data_t>
278auto VIPRA::Input::JSON::get_map(json_cref
const& value)
const
279 -> std::optional<std::map<std::string, data_t>>
282 return value.get().get<std::map<std::string, data_t>>();
284 catch ( nlohmann::json::type_error
const& e ) {
296[[nodiscard]]
inline auto VIPRA::Input::JSON::is_f3d(nlohmann::json
const& value) ->
bool
298 if ( ! value.is_object() )
return false;
299 if ( ! value.contains(
"x") || ! value.contains(
"y") || ! value.contains(
"z") )
301 if ( ! value.at(
"x").is_number() || ! value.at(
"y").is_number() ||
302 ! value.at(
"z").is_number() )
314[[nodiscard]]
inline auto VIPRA::Input::JSON::is_f2d(nlohmann::json
const& value) ->
bool
316 if ( ! value.is_object() )
return false;
317 if ( ! value.contains(
"x") || ! value.contains(
"y") )
return false;
318 if ( ! value.at(
"x").is_number() || ! value.at(
"y").is_number() )
return false;
Base ParamReader Module.
Definition param_reader.hpp:21
Definition serializable.hpp:7