Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
vpXmlParserHomogeneousMatrix.cpp
1/*
2 * ViSP, open source Visual Servoing Platform software.
3 * Copyright (C) 2005 - 2025 by Inria. All rights reserved.
4 *
5 * This software is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 * See the file LICENSE.txt at the root directory of this source
10 * distribution for additional information about the GNU GPL.
11 *
12 * For using ViSP with software that can not be combined with the GNU
13 * GPL, please contact Inria about acquiring a ViSP Professional
14 * Edition License.
15 *
16 * See https://visp.inria.fr for more information.
17 *
18 * This software was developed at:
19 * Inria Rennes - Bretagne Atlantique
20 * Campus Universitaire de Beaulieu
21 * 35042 Rennes Cedex
22 * France
23 *
24 * If you have questions regarding the use of this file, please contact
25 * Inria at visp@inria.fr
26 *
27 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29 *
30 * Description:
31 * XML parser to load and save Homogeneous Matrix in a XML file
32 */
33
40#include <visp3/core/vpXmlParserHomogeneousMatrix.h>
41
42#if defined(VISP_HAVE_PUGIXML)
43#include <pugixml.hpp>
44
45/* ----------------------------- LABEL XML ----------------------------- */
46/* --------------------------------------------------------------------- */
47#define LABEL_XML_ROOT "root"
48#define LABEL_XML_M "homogeneous_transformation"
49#define LABEL_XML_M_NAME "name"
50#define LABEL_XML_VALUE "values"
51#define LABEL_XML_TX "tx"
52#define LABEL_XML_TY "ty"
53#define LABEL_XML_TZ "tz"
54#define LABEL_XML_TUX "theta_ux"
55#define LABEL_XML_TUY "theta_uy"
56#define LABEL_XML_TUZ "theta_uz"
57
59#ifndef DOXYGEN_SHOULD_SKIP_THIS
60class vpXmlParserHomogeneousMatrix::Impl
61{
62private:
63 /* --- XML Code------------------------------------------------------------
64 */
65 enum vpXmlCodeType
66 {
67 CODE_XML_BAD = -1,
68 CODE_XML_OTHER,
69 CODE_XML_M,
70 CODE_XML_M_NAME,
71 CODE_XML_VALUE,
72 CODE_XML_TX,
73 CODE_XML_TY,
74 CODE_XML_TZ,
75 CODE_XML_TUX,
76 CODE_XML_TUY,
77 CODE_XML_TUZ
78 };
79
80public:
81 Impl() : m_M(), m_name() { }
82
83 int parse(vpHomogeneousMatrix &M, const std::string &filename, const std::string &name)
84 {
85 pugi::xml_document doc;
86 if (!doc.load_file(filename.c_str())) {
87 std::cerr << std::endl << "ERROR:" << std::endl;
88 std::cerr << " I cannot open the file " << filename << std::endl;
89
90 return SEQUENCE_ERROR;
91 }
92
93 pugi::xml_node node = doc.document_element();
94 if (!node) {
95 return SEQUENCE_ERROR;
96 }
97
98 int ret = read(node, name);
99
100 M = m_M;
101
102 return ret;
103 }
104
112 int read(const pugi::xml_node &node_, const std::string &name)
113 {
114 vpXmlCodeType prop;
115
116 vpXmlCodeSequenceType back = SEQUENCE_OK;
117 unsigned int nbM = 0;
118
119 for (pugi::xml_node node = node_.first_child(); node; node = node.next_sibling()) {
120 if (node.type() == pugi::node_element) {
121 if (SEQUENCE_OK != str2xmlcode(node.name(), prop)) {
122 prop = CODE_XML_OTHER;
123 back = SEQUENCE_ERROR;
124 }
125
126 if (prop == CODE_XML_M) {
127 if (SEQUENCE_OK == read_matrix(node, name)) {
128 nbM++;
129 }
130 }
131 else {
132 back = SEQUENCE_ERROR;
133 }
134 }
135 }
136
137 if (nbM == 0) {
138 back = SEQUENCE_ERROR;
139 std::cerr << "No Homogeneous matrix is available" << std::endl << "with name: " << name << std::endl;
140 }
141 else if (nbM > 1) {
142 back = SEQUENCE_ERROR;
143 std::cerr << nbM << " There are more Homogeneous matrix" << std::endl
144 << "with the same name : " << std::endl
145 << "precise your choice..." << std::endl;
146 }
147
148 return back;
149 }
150
159 int read_matrix(const pugi::xml_node &node_, const std::string &name)
160 {
161 vpXmlCodeType prop;
162 /* read value in the XML file. */
163 std::string M_name_tmp = "";
164 vpHomogeneousMatrix M_tmp;
165
166 vpXmlCodeSequenceType back = SEQUENCE_OK;
167
168 for (pugi::xml_node node = node_.first_child(); node; node = node.next_sibling()) {
169 if (node.type() == pugi::node_element) {
170 if (SEQUENCE_OK != str2xmlcode(node.name(), prop)) {
171 prop = CODE_XML_OTHER;
172 back = SEQUENCE_ERROR;
173 }
174
175 switch (prop) {
176 case CODE_XML_M_NAME: {
177 M_name_tmp = node.text().as_string();
178 break;
179 }
180
181 case CODE_XML_VALUE: // VALUE
182 if (name == M_name_tmp) {
183 std::cout << "Found Homogeneous Matrix with name: \"" << M_name_tmp << "\"" << std::endl;
184 back = read_values(node, M_tmp);
185 }
186 break;
187
188 case CODE_XML_BAD:
189 case CODE_XML_OTHER:
190 case CODE_XML_M:
191 case CODE_XML_TX:
192 case CODE_XML_TY:
193 case CODE_XML_TZ:
194 case CODE_XML_TUX:
195 case CODE_XML_TUY:
196 case CODE_XML_TUZ:
197 default:
198 back = SEQUENCE_ERROR;
199 break;
200 }
201 }
202 }
203
204 if (!(name == M_name_tmp)) {
205 back = SEQUENCE_ERROR;
206 }
207 else {
208 this->m_M = M_tmp;
209 // --comment: std::cout << "Convert in Homogeneous Matrix:"<< std::endl;
210 // --comment: std::cout << this-> M << std::endl;
211 this->m_name = M_name_tmp;
212 }
213 return back;
214 }
215
224 vpXmlCodeSequenceType read_values(const pugi::xml_node &node_, vpHomogeneousMatrix &M)
225 {
226 // counter of the number of read parameters
227 int nb = 0;
228 vpXmlCodeType prop;
229 /* read value in the XML file. */
230
231 double tx_ = 0.;
232 double ty_ = 0.;
233 double tz_ = 0.;
234 double tux_ = 0.;
235 double tuy_ = 0.;
236 double tuz_ = 0.;
237
238 vpXmlCodeSequenceType back = SEQUENCE_OK;
239
240 for (pugi::xml_node node = node_.first_child(); node; node = node.next_sibling()) {
241 if (node.type() == pugi::node_element) {
242 if (SEQUENCE_OK != str2xmlcode(node.name(), prop)) {
243 prop = CODE_XML_OTHER;
244 back = SEQUENCE_ERROR;
245 }
246
247 switch (prop) {
248 case CODE_XML_TX:
249 tx_ = node.text().as_double();
250 nb++;
251 break;
252 case CODE_XML_TY:
253 ty_ = node.text().as_double();
254 nb++;
255 break;
256 case CODE_XML_TZ:
257 tz_ = node.text().as_double();
258 nb++;
259 break;
260 case CODE_XML_TUX:
261 tux_ = node.text().as_double();
262 nb++;
263 break;
264 case CODE_XML_TUY:
265 tuy_ = node.text().as_double();
266 nb++;
267 break;
268 case CODE_XML_TUZ:
269 tuz_ = node.text().as_double();
270 nb++;
271 break;
272
273 case CODE_XML_BAD:
274 case CODE_XML_OTHER:
275 case CODE_XML_M:
276 case CODE_XML_M_NAME:
277 case CODE_XML_VALUE:
278 default:
279 back = SEQUENCE_ERROR;
280 break;
281 }
282 }
283 }
284
285 if (nb != 6) {
286 std::cerr << "ERROR in 'model' field:\n";
287 std::cerr << "it must contain 6 parameters\n";
288
289 return SEQUENCE_ERROR;
290 }
291
292 // Create the Homogeneous matrix
293 M.buildFrom(tx_, ty_, tz_, tux_, tuy_, tuz_);
294
295 // --comment: std::cout << "Read values from file:" << std::endl;
296 // --comment: std::cout << "tx:" << tx_<< std::endl;
297 // --comment: std::cout << "ty:" << ty_<< std::endl;
298 // --comment: std::cout << "tz:" << tz_<< std::endl;
299 // --comment: std::cout << "tux:" << tux_<< std::endl;
300 // --comment: std::cout << "tuy:" << tuy_<< std::endl;
301 // --comment: std::cout << "tuz:" << tuz_<< std::endl;
302
303 return back;
304 }
305
306 int save(const vpHomogeneousMatrix &M, const std::string &filename, const std::string &name)
307 {
308 pugi::xml_document doc;
309 pugi::xml_node node;
310
311 if (!doc.load_file(filename.c_str(), pugi::parse_default | pugi::parse_comments)) {
312 node = doc.append_child(pugi::node_declaration);
313 node.append_attribute("version") = "1.0";
314 node = doc.append_child(LABEL_XML_ROOT);
315 pugi::xml_node nodeComment = node.append_child(pugi::node_comment);
316 nodeComment.set_value("This file stores homogeneous matrix used\n"
317 " in the vpHomogeneousMatrix Class of ViSP available\n"
318 " at https://visp.inria.fr/download/ .\n"
319 " It can be read with the parse method of\n"
320 " the vpXmlParserHomogeneousMatrix class.");
321 }
322
323 node = doc.document_element();
324 if (!node) {
325 return SEQUENCE_ERROR;
326 }
327
328 m_M = M;
329
330 int M_isFound = count(node, name);
331
332 if (M_isFound) {
333 std::cout << "There is already an homogeneous matrix " << std::endl
334 << "available in the file with the input name: " << name << "." << std::endl
335 << "Please delete it manually from the xml file." << std::endl;
336 return SEQUENCE_ERROR;
337 }
338
339 write(node, name);
340
341 doc.save_file(filename.c_str(), PUGIXML_TEXT(" "));
342
343 return SEQUENCE_OK;
344 }
345
356 int count(const pugi::xml_node &node_, const std::string &name)
357 {
358 vpXmlCodeType prop;
359 int nbM = 0;
360
361 for (pugi::xml_node node = node_.first_child(); node; node = node.next_sibling()) {
362 if (node.type() == pugi::node_element) {
363 if (SEQUENCE_OK != str2xmlcode(node.name(), prop)) {
364 prop = CODE_XML_OTHER;
365 }
366 if (prop == CODE_XML_M) {
367 if (SEQUENCE_OK == read_matrix(node, name)) {
368 nbM++;
369 }
370 }
371 }
372 }
373
374 return nbM;
375 }
376
385 int write(pugi::xml_node &node, const std::string &name)
386 {
387 int back = SEQUENCE_OK;
388
389 pugi::xml_node node_tmp;
390 pugi::xml_node node_matrix;
391 pugi::xml_node node_values;
392
393 // Convert from Rotational matrix to Theta-U vector
394 vpRotationMatrix R;
395 m_M.extract(R);
396
397 vpThetaUVector tu(R);
398
399 // <homogeneous_transformation>
400 node_tmp = node.append_child(pugi::node_comment);
401 node_tmp.set_value("Homogeneous Matrix");
402 node_matrix = node.append_child(LABEL_XML_M);
403 {
404 // <name>
405 if (!name.empty()) {
406 node_tmp = node_matrix.append_child(pugi::node_comment);
407 node_tmp.set_value("Name of the homogeneous matrix");
408 node_matrix.append_child(LABEL_XML_M_NAME).append_child(pugi::node_pcdata).set_value(name.c_str());
409 }
410
411 // <values>
412 node_values = node_matrix.append_child(LABEL_XML_VALUE);
413 {
414 node_tmp = node_values.append_child(pugi::node_comment);
415 node_tmp.set_value("Translation vector with values in meters");
416
417 // <tx>
418 node_values.append_child(LABEL_XML_TX).append_child(pugi::node_pcdata).text() = m_M[0][3];
419
420 // <ty>
421 node_values.append_child(LABEL_XML_TY).append_child(pugi::node_pcdata).text() = m_M[1][3];
422
423 // <tz>
424 node_values.append_child(LABEL_XML_TZ).append_child(pugi::node_pcdata).text() = m_M[2][3];
425
426 node_tmp = node_values.append_child(pugi::node_comment);
427 node_tmp.set_value("Rotational vector expressed in angle axis "
428 "representation with values in radians");
429
430 // <tux>
431 node_values.append_child(LABEL_XML_TUX).append_child(pugi::node_pcdata).text() = tu[0];
432
433 // <tuy>
434 node_values.append_child(LABEL_XML_TUY).append_child(pugi::node_pcdata).text() = tu[1];
435
436 // <tuz>
437 node_values.append_child(LABEL_XML_TUZ).append_child(pugi::node_pcdata).text() = tu[2];
438 }
439 }
440
441 return back;
442 }
443
451 vpXmlCodeSequenceType str2xmlcode(const char *str, vpXmlCodeType &res)
452 {
453 vpXmlCodeType val_int = CODE_XML_BAD;
454 vpXmlCodeSequenceType back = vpXmlParserHomogeneousMatrix::SEQUENCE_OK;
455
456 if (!strcmp(str, LABEL_XML_M)) {
457 val_int = CODE_XML_M;
458 }
459 else if (!strcmp(str, LABEL_XML_M_NAME)) {
460 val_int = CODE_XML_M_NAME;
461 }
462 else if (!strcmp(str, LABEL_XML_VALUE)) {
463 val_int = CODE_XML_VALUE;
464 }
465 else if (!strcmp(str, LABEL_XML_TX)) {
466 val_int = CODE_XML_TX;
467 }
468 else if (!strcmp(str, LABEL_XML_TY)) {
469 val_int = CODE_XML_TY;
470 }
471 else if (!strcmp(str, LABEL_XML_TZ)) {
472 val_int = CODE_XML_TZ;
473 }
474 else if (!strcmp(str, LABEL_XML_TUX)) {
475 val_int = CODE_XML_TUX;
476 }
477 else if (!strcmp(str, LABEL_XML_TUY)) {
478 val_int = CODE_XML_TUY;
479 }
480 else if (!strcmp(str, LABEL_XML_TUZ)) {
481 val_int = CODE_XML_TUZ;
482 }
483 else {
484 val_int = CODE_XML_OTHER;
485 }
486 res = val_int;
487
488 return back;
489 }
490
491 vpHomogeneousMatrix getHomogeneousMatrix() const { return m_M; }
492 std::string getHomogeneousMatrixName() const { return m_name; }
493
494 void setHomogeneousMatrixName(const std::string &name) { m_name = name; }
495
496private:
497 vpHomogeneousMatrix m_M;
498 std::string m_name;
499};
500#endif // DOXYGEN_SHOULD_SKIP_THIS
501
503
505
514int vpXmlParserHomogeneousMatrix::parse(vpHomogeneousMatrix &M, const std::string &filename, const std::string &name)
515{
516 return m_impl->parse(M, filename, name);
517}
518
527int vpXmlParserHomogeneousMatrix::save(const vpHomogeneousMatrix &M, const std::string &filename,
528 const std::string &name)
529{
530 return m_impl->save(M, filename, name);
531}
532
534{
535 return m_impl->getHomogeneousMatrix();
536}
537
539{
540 return m_impl->getHomogeneousMatrixName();
541}
542
544{
545 m_impl->setHomogeneousMatrixName(name);
546}
547END_VISP_NAMESPACE
548#elif !defined(VISP_BUILD_SHARED_LIBS)
549// Work around to avoid warning: libvisp_core.a(vpXmlParserHomogeneousMatrix.cpp.o) has no symbols
550void dummy_vpXmlParserHomogeneousMatrix() { }
551
552#endif
Implementation of an homogeneous matrix and operations on such kind of matrices.
vpHomogeneousMatrix & buildFrom(const vpTranslationVector &t, const vpRotationMatrix &R)
vpHomogeneousMatrix getHomogeneousMatrix() const
int parse(vpHomogeneousMatrix &M, const std::string &filename, const std::string &name)
int save(const vpHomogeneousMatrix &M, const std::string &filename, const std::string &name)
void setHomogeneousMatrixName(const std::string &name)