World_load_xml.cpp
Go to the documentation of this file.
00001 /*+-------------------------------------------------------------------------+
00002   |                       MultiVehicle simulator (libmvsim)                 |
00003   |                                                                         |
00004   | Copyright (C) 2014  Jose Luis Blanco Claraco (University of Almeria)    |
00005   | Copyright (C) 2017  Borys Tymchenko (Odessa Polytechnic University)     |
00006   | Distributed under GNU General Public License version 3                  |
00007   |   See <http://www.gnu.org/licenses/>                                    |
00008   +-------------------------------------------------------------------------+ */
00009 #include <mvsim/World.h>
00010 
00011 #include <mrpt/utils/utils_defs.h>  // mrpt::format()
00012 #include <mrpt/system/filesystem.h>  // extractFileDirectory()
00013 
00014 #include <iostream>  // for debugging
00015 #include <algorithm>  // count()
00016 #include <stdexcept>
00017 #include <map>
00018 
00019 // XML parsing:
00020 #include <rapidxml.hpp>
00021 #include <rapidxml_print.hpp>
00022 
00023 #include "xml_utils.h"
00024 
00025 using namespace mvsim;
00026 using namespace std;
00027 
00033 void World::load_from_XML(
00034         const std::string& xml_text, const std::string& fileNameForPath)
00035 {
00036         using namespace std;
00037         using namespace rapidxml;
00038 
00039         // Extract base path of file:
00040         m_base_path =
00041                 mrpt::system::trim(mrpt::system::extractFileDirectory(fileNameForPath));
00042         // printf("[World] INFO: Using base path='%s'\n",m_base_path.c_str());
00043 
00044         std::lock_guard<std::mutex> csl(m_world_cs);  // Protect multithread access
00045 
00046         // Clear the existing world.
00047         this->clear_all(false /* critical section is already acquired */);
00048 
00049         // Parse the XML input:
00050         rapidxml::xml_document<> xml;
00051         char* input_str = const_cast<char*>(xml_text.c_str());
00052         try
00053         {
00054                 xml.parse<0>(input_str);
00055         }
00056         catch (rapidxml::parse_error& e)
00057         {
00058                 unsigned int line =
00059                         static_cast<long>(std::count(input_str, e.where<char>(), '\n') + 1);
00060                 throw std::runtime_error(
00061                         mrpt::format(
00062                                 "XML parse error (Line %u): %s", static_cast<unsigned>(line),
00063                                 e.what()));
00064         }
00065 
00066         // Sanity checks:
00067         const xml_node<>* root = xml.first_node();
00068         if (!root)
00069                 throw runtime_error(
00070                         "XML parse error: No root node found (empty file?)");
00071         if (0 != strcmp(root->name(), "mvsim_world"))
00072                 throw runtime_error(
00073                         mrpt::format(
00074                                 "XML root element is '%s' ('mvsim_world' expected)",
00075                                 root->name()));
00076 
00077         // Optional: format version attrib:
00078         const xml_attribute<>* attrb_version = root->first_attribute("version");
00079         int version_major = 1, version_min = 0;
00080         if (attrb_version)
00081         {
00082                 int ret = sscanf(
00083                         attrb_version->value(), "%i.%i", &version_major, &version_min);
00084                 if (ret != 2)
00085                         throw runtime_error(
00086                                 mrpt::format(
00087                                         "Error parsing version attribute: '%s' ('%%i.%%i' "
00088                                         "expected)",
00089                                         attrb_version->value()));
00090         }
00091 
00092         // load general parameters:
00093         // ------------------------------------------------
00094         std::map<std::string, TParamEntry> other_world_params;
00095         other_world_params["gravity"] = TParamEntry("%lf", &this->m_gravity);
00096         other_world_params["simul_timestep"] =
00097                 TParamEntry("%lf", &this->m_simul_timestep);
00098         other_world_params["b2d_vel_iters"] =
00099                 TParamEntry("%i", &this->m_b2d_vel_iters);
00100         other_world_params["b2d_pos_iters"] =
00101                 TParamEntry("%i", &this->m_b2d_pos_iters);
00102 
00103         // Process all nodes:
00104         // ------------------------------------------------
00105         xml_node<>* node = root->first_node();
00106         while (node)
00107         {
00108                 // <element class='*'> entries:
00109                 if (!strcmp(node->name(), "element"))
00110                 {
00111                         WorldElementBase* we = WorldElementBase::factory(this, node);
00112                         this->m_world_elements.push_back(we);
00113                 }
00114                 // <vehicle> entries:
00115                 else if (!strcmp(node->name(), "vehicle"))
00116                 {
00117                         VehicleBase* veh = VehicleBase::factory(this, node);
00118                         veh->setVehicleIndex(
00119                                 m_vehicles.size());  // Assign each vehicle an "index" number
00120 
00121                         MRPT_TODO("Check for duplicated names")
00122                         m_vehicles.insert(TListVehicles::value_type(veh->getName(), veh));
00123                 }
00124                 // <vehicle:class> entries:
00125                 else if (!strcmp(node->name(), "vehicle:class"))
00126                 {
00127                         VehicleBase::register_vehicle_class(node);
00128                 }
00129                 // <block> entries:
00130                 else if (!strcmp(node->name(), "block"))
00131                 {
00132                         Block* block = Block::factory(this, node);
00133                         block->setBlockIndex(
00134                                 m_blocks.size());  // Assign each block an "index" number
00135 
00136                         // make sure the name is not duplicated:
00137                         m_blocks.insert(TListBlocks::value_type(block->getName(), block));
00138                 }
00139                 // <block:class> entries:
00140                 else if (!strcmp(node->name(), "block:class"))
00141                 {
00142                         Block::register_block_class(node);
00143                 }
00144                 // <gui> </gui> params:
00145                 else if (!strcmp(node->name(), "gui"))
00146                 {
00147                         m_gui_options.parse_from(*node);
00148                 }
00149                 else
00150                 {
00151                         // Default: Check if it's a parameter:
00152                         if (!parse_xmlnode_as_param(*node, other_world_params))
00153                         {
00154                                 // Unknown element!!
00155                                 std::cerr << "[World::load_from_XML] *Warning* Ignoring "
00156                                                          "unknown XML node type '"
00157                                                   << node->name() << "'\n";
00158                         }
00159                 }
00160 
00161                 // Move on to next node:
00162                 node = node->next_sibling(NULL);
00163         }
00164 }


mvsim
Author(s):
autogenerated on Thu Sep 7 2017 09:27:48