00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include <mvsim/WorldElements/ElevationMap.h>
00011 #include <mvsim/World.h>
00012 #include <mvsim/VehicleBase.h>
00013 #include "xml_utils.h"
00014
00015 #include <mrpt/opengl/COpenGLScene.h>
00016 #include <mrpt/opengl/CPointCloud.h>
00017 #include <mrpt/tfest.h>
00018 #include <rapidxml.hpp>
00019
00020 using namespace rapidxml;
00021 using namespace mvsim;
00022 using namespace std;
00023
00024 ElevationMap::ElevationMap(World* parent, const rapidxml::xml_node<char>* root)
00025 : WorldElementBase(parent), m_first_scene_rendering(true), m_resolution(1.0)
00026 {
00027 loadConfigFrom(root);
00028 }
00029
00030 ElevationMap::~ElevationMap() {}
00031 void ElevationMap::loadConfigFrom(const rapidxml::xml_node<char>* root)
00032 {
00033
00034 std::map<std::string, TParamEntry> params;
00035
00036 std::string sElevationImgFile;
00037 params["elevation_image"] = TParamEntry("%s", &sElevationImgFile);
00038 std::string sTextureImgFile;
00039 params["texture_image"] = TParamEntry("%s", &sTextureImgFile);
00040
00041 double img_min_z = 0.0, img_max_z = 5.0;
00042 params["elevation_image_min_z"] = TParamEntry("%lf", &img_min_z);
00043 params["elevation_image_max_z"] = TParamEntry("%lf", &img_max_z);
00044
00045 mrpt::utils::TColor mesh_color(0xa0, 0xe0, 0xa0);
00046 params["mesh_color"] = TParamEntry("%color", &mesh_color);
00047
00048 params["resolution"] = TParamEntry("%lf", &m_resolution);
00049
00050 parse_xmlnode_children_as_param(*root, params);
00051
00052
00053 mrpt::math::CMatrixFloat elevation_data;
00054 if (!sElevationImgFile.empty())
00055 {
00056 mrpt::utils::CImage imgElev;
00057 if (!imgElev.loadFromFile(
00058 sElevationImgFile, 0 ))
00059 throw std::runtime_error(
00060 mrpt::format(
00061 "[ElevationMap] ERROR: Cannot read elevation image '%s'",
00062 sElevationImgFile.c_str()));
00063
00064
00065 imgElev.getAsMatrix(
00066 elevation_data);
00067 ASSERT_(img_min_z != img_max_z)
00068 elevation_data.adjustRange(img_min_z, img_max_z);
00069 }
00070 else
00071 {
00072 MRPT_TODO("Imgs or txt matrix")
00073 }
00074
00075
00076 mrpt::utils::CImage mesh_image;
00077 bool has_mesh_image = false;
00078 if (!sTextureImgFile.empty())
00079 {
00080 if (!mesh_image.loadFromFile(sTextureImgFile))
00081 throw std::runtime_error(
00082 mrpt::format(
00083 "[ElevationMap] ERROR: Cannot read texture image '%s'",
00084 sTextureImgFile.c_str()));
00085 has_mesh_image = true;
00086 }
00087
00088
00089 m_gl_mesh = mrpt::make_aligned_shared<mrpt::opengl::CMesh>();
00090
00091 m_gl_mesh->enableTransparency(false);
00092
00093 if (has_mesh_image)
00094 {
00095 ASSERT_EQUAL_(mesh_image.getWidth(), (size_t)elevation_data.cols())
00096 ASSERT_EQUAL_(mesh_image.getHeight(), (size_t)elevation_data.rows())
00097
00098 m_gl_mesh->assignImage(mesh_image);
00099 m_gl_mesh->setZ(elevation_data);
00100 }
00101 else
00102 {
00103 m_gl_mesh->setZ(elevation_data);
00104 m_gl_mesh->setColor_u8(mesh_color);
00105 }
00106
00107
00108 m_mesh_z_cache = elevation_data;
00109
00110
00111 const double LX = (elevation_data.cols() - 1) * m_resolution;
00112 const double LY = (elevation_data.rows() - 1) * m_resolution;
00113 m_gl_mesh->setGridLimits(-0.5 * LX, 0.5 * LX, -0.5 * LY, 0.5 * LY);
00114 }
00115
00116 void ElevationMap::gui_update(mrpt::opengl::COpenGLScene& scene)
00117 {
00118 using namespace mrpt::math;
00119
00120 ASSERTMSG_(
00121 m_gl_mesh,
00122 "ERROR: Can't render Mesh before loading it! Have you called "
00123 "loadConfigFrom() first?")
00124
00125
00126 if (m_first_scene_rendering)
00127 {
00128 m_first_scene_rendering = false;
00129 SCENE_INSERT_Z_ORDER(scene, 0, m_gl_mesh);
00130 }
00131 }
00132
00133 void ElevationMap::simul_pre_timestep(const TSimulContext& context)
00134 {
00135
00136
00137
00138 const double gravity = getWorldObject()->get_gravity();
00139
00140 ASSERT_(m_gl_mesh)
00141
00142
00143 const World::TListVehicles& lstVehs = this->m_world->getListOfVehicles();
00144 for (World::TListVehicles::const_iterator itVeh = lstVehs.begin();
00145 itVeh != lstVehs.end(); ++itVeh)
00146 {
00147 m_world->getTimeLogger().enter("elevationmap.handle_vehicle");
00148
00149 const size_t nWheels = itVeh->second->getNumWheels();
00150
00151
00152
00153
00154
00155
00156
00157 mrpt::math::TPoint3D dir_down;
00158
00159
00160 for (int iter = 0; iter < 3; iter++)
00161 {
00162 const mrpt::math::TPose3D& cur_pose = itVeh->second->getPose();
00163 const mrpt::poses::CPose3D cur_cpose(cur_pose);
00164
00165
00166
00167
00168 mrpt::math::TPose3D new_pose = cur_pose;
00169
00170
00171
00172 corrs.clear();
00173
00174 bool out_of_area = false;
00175 for (size_t iW = 0; !out_of_area && iW < nWheels; iW++)
00176 {
00177 const Wheel& wheel = itVeh->second->getWheelInfo(iW);
00178
00179
00180 mrpt::utils::TMatchingPair corr;
00181
00182 corr.other_idx = iW;
00183 corr.other_x = wheel.x;
00184 corr.other_y = wheel.y;
00185 corr.other_z = 0;
00186
00187
00188 mrpt::math::TPoint3D gPt;
00189 cur_cpose.composePoint(
00190 wheel.x, wheel.y, 0.0, gPt.x, gPt.y, gPt.z);
00191 float z;
00192 if (!getElevationAt(gPt.x , gPt.y , z ))
00193 {
00194 out_of_area = true;
00195 continue;
00196 }
00197
00198 corr.this_idx = iW;
00199 corr.this_x = gPt.x;
00200 corr.this_y = gPt.y;
00201 corr.this_z = z;
00202
00203 corrs.push_back(corr);
00204 }
00205 if (out_of_area) continue;
00206
00207
00208 double transf_scale;
00209 mrpt::poses::CPose3DQuat tmpl;
00210
00211 mrpt::tfest::se3_l2(
00212 corrs, tmpl, transf_scale, true );
00213
00214 m_optimal_transf = mrpt::poses::CPose3D(tmpl);
00215 new_pose.z = m_optimal_transf.z();
00216 new_pose.yaw = m_optimal_transf.yaw();
00217 new_pose.pitch = m_optimal_transf.pitch();
00218 new_pose.roll = m_optimal_transf.roll();
00219
00220
00221
00222 itVeh->second->setPose(new_pose);
00223
00224 }
00225
00226 {
00227 mrpt::poses::CPose3D rot_only;
00228 rot_only.setRotationMatrix(m_optimal_transf.getRotationMatrix());
00229 rot_only.inverseComposePoint(
00230 .0, .0, -1.0, dir_down.x, dir_down.y, dir_down.z);
00231 }
00232
00233
00234
00235 {
00236
00237 const double chassis_weight =
00238 itVeh->second->getChassisMass() * gravity;
00239 const mrpt::math::TPoint2D chassis_com =
00240 itVeh->second->getChassisCenterOfMass();
00241 itVeh->second->apply_force(
00242 dir_down.x * chassis_weight, dir_down.y * chassis_weight,
00243 chassis_com.x, chassis_com.y);
00244
00245
00246 for (size_t iW = 0; iW < nWheels; iW++)
00247 {
00248 const Wheel& wheel = itVeh->second->getWheelInfo(iW);
00249 const double wheel_weight = wheel.mass * gravity;
00250 itVeh->second->apply_force(
00251 dir_down.x * wheel_weight, dir_down.y * wheel_weight,
00252 wheel.x, wheel.y);
00253 }
00254 }
00255
00256 m_world->getTimeLogger().leave("elevationmap.handle_vehicle");
00257 }
00258 }
00259
00260 void ElevationMap::simul_post_timestep(const TSimulContext& context)
00261 {
00262 MRPT_TODO(
00263 "Save all elements positions in prestep, then here scale their "
00264 "movements * cos(angle)")
00265 }
00266 float calcz(
00267 const mrpt::math::TPoint3Df& p1, const mrpt::math::TPoint3Df& p2,
00268 const mrpt::math::TPoint3Df& p3, float x, float y)
00269 {
00270 const float det =
00271 (p2.x - p3.x) * (p1.y - p3.y) + (p3.y - p2.y) * (p1.x - p3.x);
00272 ASSERT_(det != 0.0f)
00273
00274 const float l1 =
00275 ((p2.x - p3.x) * (y - p3.y) + (p3.y - p2.y) * (x - p3.x)) / det;
00276 const float l2 =
00277 ((p3.x - p1.x) * (y - p3.y) + (p1.y - p3.y) * (x - p3.x)) / det;
00278 const float l3 = 1.0f - l1 - l2;
00279
00280 return l1 * p1.z + l2 * p2.z + l3 * p3.z;
00281 }
00282
00283 bool ElevationMap::getElevationAt(double x, double y, float& z) const
00284 {
00285 const mrpt::opengl::CMesh* mesh = m_gl_mesh.get();
00286 const float x0 = mesh->getXMin();
00287 const float y0 = mesh->getYMin();
00288 const size_t nCellsX = m_mesh_z_cache.rows();
00289 const size_t nCellsY = m_mesh_z_cache.cols();
00290
00291
00292 const int cx00 = ::floor((x - x0) / m_resolution);
00293 const int cy00 = ::floor((y - y0) / m_resolution);
00294 if (cx00 < 1 || cx00 >= int(nCellsX - 1) || cy00 < 1 ||
00295 cy00 >= int(nCellsY - 1))
00296 return false;
00297
00298
00299 const float z00 = m_mesh_z_cache(cx00, cy00);
00300 const float z01 = m_mesh_z_cache(cx00, cy00 + 1);
00301 const float z10 = m_mesh_z_cache(cx00 + 1, cy00);
00302 const float z11 = m_mesh_z_cache(cx00 + 1, cy00 + 1);
00303
00304
00305
00306
00307
00308
00309 const mrpt::math::TPoint3Df p00(.0f, .0f, z00);
00310 const mrpt::math::TPoint3Df p01(.0f, m_resolution, z01);
00311 const mrpt::math::TPoint3Df p10(m_resolution, .0f, z10);
00312 const mrpt::math::TPoint3Df p11(m_resolution, m_resolution, z11);
00313
00314 const float lx = x - (x0 + cx00 * m_resolution);
00315 const float ly = y - (y0 + cy00 * m_resolution);
00316
00317 if (ly >= lx)
00318 z = calcz(p00, p01, p11, lx, ly);
00319 else
00320 z = calcz(p00, p10, p11, lx, ly);
00321
00322 return true;
00323 }