GLIM
Loading...
Searching...
No Matches
config_impl.hpp
1#pragma once
2
3#include <glim/util/config.hpp>
4
5#include <fstream>
6#include <sstream>
7#include <iostream>
8#include <iomanip>
9#include <spdlog/spdlog.h>
10#include <nlohmann/json.hpp>
11
12#include <Eigen/Core>
13#include <Eigen/Geometry>
14
15#include <glim/util/convert_to_string.hpp>
16
17namespace glim {
18
19namespace {
20
21// IO traits
22template <typename T>
23struct traits {
24 using InType = T;
25 using OutType = T;
26
27 static std::optional<OutType> convert(const InType& in) { return in; }
28
29 static InType invert(const OutType& value) { return value; }
30};
31
32// General Eigen IO
33template <typename T, int N, int M>
34struct traits<Eigen::Matrix<T, N, M>> {
35 using InType = std::vector<double>;
36 using OutType = Eigen::Matrix<T, N, M>;
37
38 static std::optional<OutType> convert(const InType& in) {
39 if (in.size() != N * M) {
40 return std::nullopt;
41 }
42 return Eigen::Map<const OutType>(in.data());
43 }
44
45 static std::vector<double> invert(const OutType& value) { return std::vector<double>(value.data(), value.data() + N * M); }
46};
47
48// Eigen Quaternion IO
49template <typename T>
50struct traits<Eigen::Quaternion<T>> {
51 using InType = std::vector<double>;
52 using OutType = Eigen::Quaternion<T>;
53
54 static std::optional<OutType> convert(const InType& in) {
55 if (in.size() != 4) {
56 return std::nullopt;
57 }
58
59 return OutType(in.data()).normalized();
60 }
61
62 static std::vector<double> invert(const OutType& value) { return std::vector<double>{value.x(), value.y(), value.z(), value.w()}; }
63};
64
65// Eigen Isometry
66template <typename T>
67struct traits<Eigen::Transform<T, 3, Eigen::Isometry>> {
68 using InType = std::vector<double>;
69 using OutType = Eigen::Transform<T, 3, Eigen::Isometry>;
70
71 static std::optional<OutType> convert(const InType& in) {
72 if (in.size() != 7) {
73 return std::nullopt;
74 }
75
76 OutType se3 = OutType::Identity();
77 se3.translation() = Eigen::Map<const Eigen::Matrix<T, 3, 1>>(in.data());
78 se3.linear() = Eigen::Quaternion<T>(in.data() + 3).normalized().toRotationMatrix();
79 return se3;
80 }
81
82 static std::vector<double> invert(const OutType& value) {
83 Eigen::Matrix<T, 3, 1> t = value.translation();
84 Eigen::Quaternion<T> q(value.linear());
85 return std::vector<double>{t.x(), t.y(), t.z(), q.x(), q.y(), q.z(), q.w()};
86 }
87};
88
89template <>
90struct traits<std::vector<Eigen::Isometry3d>> {
91 using InType = std::vector<double>;
92 using OutType = std::vector<Eigen::Isometry3d>;
93
94 static std::optional<OutType> convert(const InType& in) {
95 if (in.size() % 7) {
96 return std::nullopt;
97 }
98
99 OutType poses(in.size() / 7);
100 for (int i = 0; i < poses.size(); i++) {
101 poses[i].setIdentity();
102 poses[i].translation() << in[i * 7], in[i * 7 + 1], in[i * 7 + 2];
103 poses[i].linear() = Eigen::Quaterniond(in[i * 7 + 6], in[i * 7 + 3], in[i * 7 + 4], in[i * 7 + 5]).normalized().toRotationMatrix();
104 }
105
106 return poses;
107 }
108
109 static std::vector<double> invert(const OutType& value) {
110 std::vector<double> values(value.size() * 7);
111 for (int i = 0; i < value.size(); i++) {
112 Eigen::Vector3d t = value[i].translation();
113 Eigen::Quaterniond q(value[i].linear());
114
115 values[i * 7] = t.x();
116 values[i * 7 + 1] = t.y();
117 values[i * 7 + 2] = t.z();
118 values[i * 7 + 3] = q.x();
119 values[i * 7 + 4] = q.y();
120 values[i * 7 + 5] = q.z();
121 values[i * 7 + 6] = q.w();
122 }
123
124 return values;
125 }
126};
127
128} // namespace
129
130template <typename T>
131std::optional<T> Config::param(const std::string& module_name, const std::string& param_name) const {
132 const auto& json = std::any_cast<const nlohmann::json&>(config);
133
134 auto module = json.find(module_name);
135 if (module == json.end()) {
136 return std::nullopt;
137 }
138
139 auto parameter = module->find(param_name);
140 if (parameter == module->end()) {
141 return std::nullopt;
142 }
143
144 return traits<T>::convert(parameter->get<typename traits<T>::InType>());
145}
146
147template <typename T>
148T Config::param(const std::string& module_name, const std::string& param_name, const T& default_value) const {
149 auto found = param<T>(module_name, param_name);
150 if (!found) {
151 spdlog::warn("param {}/{} not found", module_name, param_name);
152 spdlog::warn("use default_value={}", convert_to_string(default_value));
153 return default_value;
154 }
155
156 spdlog::debug("param {}/{}={}", module_name, param_name, convert_to_string(found.value()));
157 return found.value();
158}
159
160template <typename T>
161T Config::param_cast(const std::string& module_name, const std::string& param_name) const {
162 auto found = param<T>(module_name, param_name);
163 if (!found) {
164 spdlog::critical("param {}/{} not found", module_name, param_name);
165 abort();
166 }
167
168 spdlog::debug("param {}/{}={}", module_name, param_name, convert_to_string(found.value()));
169 return *found;
170}
171
172template <typename T>
173bool Config::override_param(const std::string& module_name, const std::string& param_name, const T& value) {
174 auto& json = std::any_cast<nlohmann::json&>(config);
175
176 json[module_name][param_name] = traits<T>::invert(value);
177
178 return true;
179}
180
181template <typename T>
182std::optional<T> Config::param_nested(const std::vector<std::string>& nested_module_names, const std::string& param_name) const {
183 const auto& json = std::any_cast<const nlohmann::json&>(config);
184
185 nlohmann::json::const_iterator itr = json.find(nested_module_names[0]);
186 if (itr == json.end()) {
187 return std::nullopt;
188 }
189
190 for (int i = 1; i < nested_module_names.size(); i++) {
191 const auto next = itr->find(nested_module_names[i]);
192 if (next == itr->end()) {
193 return std::nullopt;
194 }
195
196 itr = next;
197 }
198
199 auto parameter = itr->find(param_name);
200 if (parameter == itr->end()) {
201 return std::nullopt;
202 }
203
204 return traits<T>::convert(parameter->get<typename traits<T>::InType>());
205}
206
207template <typename T>
208T Config::param_nested(const std::vector<std::string>& nested_module_names, const std::string& param_name, const T& default_value) const {
209 auto found = param_nested<T>(nested_module_names, param_name);
210 if (!found) {
211 std::stringstream param_name;
212 for (const auto& module_name : nested_module_names) {
213 param_name << module_name << "/";
214 }
215 spdlog::warn("param {} not found", param_name.str());
216 spdlog::warn("use default_value={}", convert_to_string(default_value));
217 return default_value;
218 }
219
220 return found.value();
221}
222
223template <typename T>
224T Config::param_cast_nested(const std::vector<std::string>& nested_module_names, const std::string& param_name) const {
225 auto found = param_nested<T>(nested_module_names, param_name);
226 if (!found) {
227 std::stringstream param_name;
228 for (const auto& module_name : nested_module_names) {
229 param_name << module_name << "/";
230 }
231 spdlog::critical("param {} not found", param_name.str());
232 abort();
233 }
234 return *found;
235}
236
237#define DEFINE_CONFIG_IO_SPECIALIZATION(TYPE) \
238 template std::optional<TYPE> Config::param(const std::string& module_name, const std::string& param_name) const; \
239 template TYPE Config::param(const std::string&, const std::string&, const TYPE&) const; \
240 template TYPE Config::param_cast(const std::string&, const std::string&) const; \
241 template std::optional<TYPE> Config::param_nested(const std::vector<std::string>& nested_module_names, const std::string& param_name) const; \
242 template TYPE Config::param_nested(const std::vector<std::string>&, const std::string&, const TYPE&) const; \
243 template TYPE Config::param_cast_nested(const std::vector<std::string>&, const std::string&) const; \
244 template bool Config::override_param(const std::string&, const std::string&, const TYPE&);
245
246} // namespace glim
T param_cast(const std::string &module_name, const std::string &param_name) const
Get a parameter.
Definition config_impl.hpp:161
std::optional< T > param(const std::string &module_name, const std::string &param_name) const
Get a parameter.
Definition config_impl.hpp:131
std::optional< T > param_nested(const std::vector< std::string > &nested_module_names, const std::string &param_name) const
Get a parameter from a nested module.
Definition config_impl.hpp:182
bool override_param(const std::string &module_name, const std::string &param_name, const T &value)
Override a parameter value.
Definition config_impl.hpp:173
T param_cast_nested(const std::vector< std::string > &nested_module_names, const std::string &param_name) const
Get a parameter.
Definition config_impl.hpp:224