12 #include <mrpt/core/bits_math.h> 13 #include <mrpt/core/format.h> 14 #include <mrpt/img/TColor.h> 15 #include <mrpt/io/vector_loadsave.h> 16 #include <mrpt/math/TPolygon2D.h> 17 #include <mrpt/poses/CPose2D.h> 18 #include <mrpt/poses/CPose3D.h> 19 #include <mrpt/system/COutputLogger.h> 20 #include <mrpt/system/filesystem.h> 21 #include <mrpt/system/string_utils.h> 29 using namespace mvsim;
36 const std::string& inStr,
const std::string& varName,
37 const std::map<std::string, std::string>& variableNamesValues,
38 const char* functionNameContext)
const 40 const std::string str =
mvsim::parse(inStr, variableNamesValues);
44 if (std::string(frmt) == std::string(
"%s"))
46 std::string& val2 = *
reinterpret_cast<std::string*
>(val);
47 val2 = mrpt::system::trim(str);
50 else if (std::string(frmt) == std::string(
"%lf_deg"))
52 if (1 != ::sscanf(str.c_str(), frmt, val))
53 throw std::runtime_error(mrpt::format(
54 "%s Error parsing attribute '%s'='%s' (Expected " 56 functionNameContext, varName.c_str(), str.c_str(), frmt));
57 double& ang = *
reinterpret_cast<double*
>(val);
58 ang = mrpt::DEG2RAD(ang);
61 else if (std::string(frmt) == std::string(
"%bool"))
63 bool& bool_val = *
reinterpret_cast<bool*
>(val);
65 const std::string sStr =
66 mrpt::system::lowerCase(mrpt::system::trim(std::string(str)));
67 if (sStr ==
"1" || sStr ==
"true")
69 else if (sStr ==
"0" || sStr ==
"false")
72 throw std::runtime_error(mrpt::format(
73 "%s Error parsing 'bool' attribute '%s'='%s' (Expected " 75 functionNameContext, varName.c_str(), str.c_str()));
78 else if (std::string(frmt) == std::string(
"%color"))
81 if (!(str.size() > 1 && str[0] ==
'#'))
82 throw std::runtime_error(mrpt::format(
83 "%s Error parsing '%s'='%s' (Expected " 84 "format:'#RRGGBB[AA]')",
85 functionNameContext, varName.c_str(), str.c_str()));
87 unsigned int r, g, b, a = 0xff;
88 int ret = ::sscanf(str.c_str() + 1,
"%2x%2x%2x%2x", &r, &g, &b, &a);
89 if (ret != 3 && ret != 4)
90 throw std::runtime_error(mrpt::format(
91 "%s Error parsing '%s'='%s' (Expected " 92 "format:'#RRGGBB[AA]')",
93 functionNameContext, varName.c_str(), str.c_str()));
94 mrpt::img::TColor& col = *
reinterpret_cast<mrpt::img::TColor*
>(val);
95 col = mrpt::img::TColor(r, g, b, a);
99 else if (!strncmp(frmt,
"%pose2d", strlen(
"%pose2d")))
102 int ret = ::sscanf(str.c_str(),
"%lf %lf %lf", &x, &y, &yaw);
104 throw std::runtime_error(mrpt::format(
105 "%s Error parsing '%s'='%s' (Expected format:'X Y " 107 functionNameContext, varName.c_str(), str.c_str()));
110 yaw = mrpt::DEG2RAD(yaw);
112 const mrpt::poses::CPose2D p(x, y, yaw);
115 if (!strcmp(frmt,
"%pose2d"))
117 mrpt::poses::CPose2D& pp =
118 *
reinterpret_cast<mrpt::poses::CPose2D*
>(val);
121 else if (!strcmp(frmt,
"%pose2d_ptr3d"))
123 mrpt::poses::CPose3D& pp =
124 *
reinterpret_cast<mrpt::poses::CPose3D*
>(val);
125 pp = mrpt::poses::CPose3D(p);
128 throw std::runtime_error(mrpt::format(
129 "%s Error: Unknown format specifier '%s'", functionNameContext,
133 else if (!strncmp(frmt,
"%point3d", strlen(
"%point3d")))
135 double x = 0, y = 0, z = 0;
136 int ret = ::sscanf(str.c_str(),
"%lf %lf %lf", &x, &y, &z);
137 if (ret != 2 && ret != 3)
138 throw std::runtime_error(mrpt::format(
139 "%s Error parsing '%s'='%s' (Expected format:'X Y [Z]')",
140 functionNameContext, varName.c_str(), str.c_str()));
142 mrpt::math::TPoint3D& pp =
143 *
reinterpret_cast<mrpt::math::TPoint3D*
>(val);
150 else if (!strncmp(frmt,
"%pose3d", strlen(
"%pose3d")))
152 double x, y, z, yawDeg, pitchDeg, rollDeg;
154 str.c_str(),
"%lf %lf %lf %lf %lf %lf", &x, &y, &z, &yawDeg,
155 &pitchDeg, &rollDeg);
157 throw std::runtime_error(mrpt::format(
158 "%s Error parsing '%s'='%s' (Expected format:'X Y Z" 159 "YAW_DEG PITCH_DEG ROLL_DEG')",
160 functionNameContext, varName.c_str(), str.c_str()));
163 const auto yaw = mrpt::DEG2RAD(yawDeg);
164 const auto pitch = mrpt::DEG2RAD(pitchDeg);
165 const auto roll = mrpt::DEG2RAD(rollDeg);
167 const mrpt::poses::CPose3D p(x, y, yaw);
169 mrpt::poses::CPose3D& pp =
170 *
reinterpret_cast<mrpt::poses::CPose3D*
>(val);
171 pp = mrpt::poses::CPose3D(x, y, z, yaw, pitch, roll);
176 if (1 != ::sscanf(str.c_str(), frmt, val))
177 throw std::runtime_error(mrpt::format(
178 "%s Error parsing attribute '%s'='%s' (Expected " 180 functionNameContext, varName.c_str(), str.c_str(), frmt));
187 const std::map<std::string, std::string>& variableNamesValues,
188 const char* functionNameContext)
190 for (
const auto&
param : params)
193 attr && attr->
value())
196 attr->value(), attr->name(), variableNamesValues,
197 functionNameContext);
205 const std::map<std::string, std::string>& variableNamesValues,
206 const char* functionNameContext)
208 if (
auto it_param = params.find(xml_node.
name()); it_param != params.end())
211 it_param->second.parse(
212 xml_node.
value(), xml_node.
name(), variableNamesValues,
213 functionNameContext);
226 const std::map<std::string, std::string>& variableNamesValues,
227 const char* functionNameContext, mrpt::system::COutputLogger* logger)
233 *node, params, variableNamesValues, functionNameContext);
234 if (!recognized && logger)
237 mrpt::system::LVL_WARN,
"Unrecognized tag '<%s>' in %s",
239 functionNameContext ? functionNameContext :
"(none)");
246 const std::string& sOrg,
bool allow_missing_angle,
247 double default_angle_radians,
248 const std::map<std::string, std::string>& variableNamesValues)
250 mrpt::math::TPose2D v;
251 v.phi = mrpt::RAD2DEG(default_angle_radians);
253 const auto s =
parse(sOrg, variableNamesValues);
254 int na = ::sscanf(
s.c_str(),
"%lf %lf %lf", &v.x, &v.y, &v.phi);
257 v.phi = mrpt::DEG2RAD(v.phi);
259 if ((na != 3 && !allow_missing_angle) ||
260 (na != 2 && na != 3 && allow_missing_angle))
261 throw std::runtime_error(
262 mrpt::format(
"Malformed pose string: '%s'",
s.c_str()));
273 const char* functionNameContext)
280 if (!pt_node->value())
281 throw std::runtime_error(mrpt::format(
282 "%s Error: <pt> node seems empty.", functionNameContext));
284 mrpt::math::TPoint2D pt;
285 const char* str_val = pt_node->value();
286 if (2 != ::sscanf(str_val,
"%lf %lf", &pt.x, &pt.y))
287 throw std::runtime_error(mrpt::format(
288 "%s Error parsing <pt> node: '%s' (Expected format:'<pt>X " 290 functionNameContext, str_val));
292 out_poly.push_back(pt);
295 if (out_poly.size() < 3)
296 throw std::runtime_error(mrpt::format(
297 "%s Error: <shape> node requires 3 or more <pt>X Y</pt> " 299 functionNameContext));
304 const std::string& xmlData,
const std::string& pathToFile)
307 using namespace std::string_literals;
310 char* input_str =
const_cast<char*
>(xmlData.c_str());
311 auto xml = std::make_shared<rapidxml::xml_document<>>();
314 xml->parse<0>(input_str);
319 static_cast<long>(std::count(input_str, e.
where<
char>(),
'\n') + 1);
320 throw std::runtime_error(mrpt::format(
321 "XML parse error (Line %u): %s", static_cast<unsigned>(line),
328 root,
"XML parse error: No root node found (empty file '"s +
329 pathToFile +
"'?)"s);
334 const std::string& pathToFile,
335 const std::map<std::string, std::string>& variables,
336 const std::set<std::string>& varsRetain)
339 using namespace std::string_literals;
341 ASSERT_FILE_EXISTS_(pathToFile);
343 auto xmlDoc = std::make_shared<XML_Doc_Data>();
346 mrpt::io::file_get_contents(pathToFile), variables, varsRetain);
349 xmlDoc->doc = std::move(xml);
351 return {xmlDoc, root};
355 size_t pos,
const std::string& s,
const char searchEndChar,
356 const char otherStartChar)
359 for (; pos < s.size(); pos++)
361 const char ch = s[pos];
362 if (ch == otherStartChar)
364 else if (ch == searchEndChar)
375 return std::string::npos;
380 const std::string& s)
382 const auto posBar = s.find(
"|");
383 if (posBar == std::string::npos)
return {s, {}};
385 return {s.substr(0, posBar), s.substr(posBar + 1)};
389 const std::string& text,
390 const std::map<std::string, std::string>& variables,
391 const std::set<std::string>& varsRetain,
const size_t searchStartPos = 0)
395 const auto start = text.find(
"${", searchStartPos);
396 if (start == std::string::npos)
return text;
398 const std::string pre = text.substr(0, start);
399 const std::string post = text.substr(start + 2);
401 const auto post_end =
findClosing(0, post,
'}',
'{');
402 if (post_end == std::string::npos)
405 "Column=%u: Cannot find matching `}` for `${` in: `%s`",
406 static_cast<unsigned int>(start), text.c_str());
409 const auto varnameOrg = post.substr(0, post_end);
413 if (varsRetain.count(varname) != 0)
416 return parseVars(text, variables, varsRetain, start + 2);
419 std::string varvalue;
420 if (
auto itVal = variables.find(varname); itVal != variables.end())
422 varvalue = itVal->second;
424 else if (
const char* v = ::getenv(varname.c_str()); v !=
nullptr)
426 varvalue = std::string(v);
430 if (!defaultValue.empty())
432 varvalue = defaultValue;
437 "MVSIM parseVars(): Undefined variable: ${%s}",
443 pre + varvalue + post.substr(post_end + 1), variables, varsRetain);
448 const std::string& in,
const std::map<std::string, std::string>& variables,
449 const std::set<std::string>& varsRetain)
451 return parseVars(in, variables, varsRetain);
bool param(const std::string ¶m_name, T ¶m_val, const T &default_val)
std::map< std::string, TParamEntry > TParameterDefinitions
virtual const char * what() const
void parse_xmlnode_children_as_param(const rapidxml::xml_node< char > &xml_node, const TParameterDefinitions ¶ms, const std::map< std::string, std::string > &variableNamesValues={}, const char *functionNameContext="", mrpt::system::COutputLogger *logger=nullptr)
bool parse_xmlnode_as_param(const rapidxml::xml_node< char > &xml_node, const TParameterDefinitions ¶ms, const std::map< std::string, std::string > &variableNamesValues={}, const char *functionNameContext="")
void parse_xmlnode_attribs(const rapidxml::xml_node< char > &xml_node, const TParameterDefinitions ¶ms, const std::map< std::string, std::string > &variableNamesValues={}, const char *functionNameContext="")
xml_node< Ch > * first_node(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
std::string parse(const std::string &input, const std::map< std::string, std::string > &variableNamesValues={})
std::tuple< XML_Doc_Data::Ptr, rapidxml::xml_node<> * > readXmlAndGetRoot(const std::string &pathToFile, const std::map< std::string, std::string > &variables, const std::set< std::string > &varsRetain={})
std::string parse_variables(const std::string &in, const std::map< std::string, std::string > &variables, const std::set< std::string > &varsRetain)
static std::string::size_type findClosing(size_t pos, const std::string &s, const char searchEndChar, const char otherStartChar)
void parse_xmlnode_shape(const rapidxml::xml_node< char > &xml_node, mrpt::math::TPolygon2D &out_poly, const char *functionNameContext="")
xml_node< Ch > * next_sibling(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
static std::tuple< std::string, std::string > splitVerticalBar(const std::string &s)
xml_attribute< Ch > * first_attribute(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
mrpt::math::TPose2D parseXYPHI(const std::string &s, bool allow_missing_angle=false, double default_angle_radians=0.0, const std::map< std::string, std::string > &variableNamesValues={})
std::tuple< std::shared_ptr< rapidxml::xml_document<> >, rapidxml::xml_node<> * > readXmlTextAndGetRoot(const std::string &xmlData, const std::string &pathToFile)
document parse(const AllocationStrategy &strategy, const StringType &string)
static std::string parseVars(const std::string &text, const std::map< std::string, std::string > &variables, const std::set< std::string > &varsRetain, const size_t searchStartPos=0)