World_walls.cpp
Go to the documentation of this file.
1 /*+-------------------------------------------------------------------------+
2  | MultiVehicle simulator (libmvsim) |
3  | |
4  | Copyright (C) 2014-2024 Jose Luis Blanco Claraco |
5  | Copyright (C) 2017 Borys Tymchenko (Odessa Polytechnic University) |
6  | Distributed under 3-clause BSD License |
7  | See COPYING |
8  +-------------------------------------------------------------------------+ */
9 
10 #include <mrpt/core/exceptions.h>
11 #include <mrpt/maps/CSimplePointsMap.h>
12 #include <mrpt/opengl/CAssimpModel.h>
13 #include <mrpt/system/filesystem.h>
14 #include <mvsim/World.h>
15 
16 #include <rapidxml.hpp>
17 #include <rapidxml_print.hpp>
18 #include <rapidxml_utils.hpp>
19 
20 #include "xml_utils.h"
21 
22 using namespace mvsim;
23 using namespace std;
24 
26 {
27  double height = 2.0;
28  double thickness = 0.10;
29 };
30 
32  World* parent, const mrpt::math::TPoint3D& rawEnd1, const mrpt::math::TPoint3D& rawEnd2,
33  const WallProperties& wp, mrpt::maps::CSimplePointsMap& allPts)
34 {
35  Block::Ptr b = std::make_shared<Block>(parent);
36 
37  {
38  static int cnt = 0;
39  b->setName(mrpt::format("wall_%04i", ++cnt));
40  }
41 
42  float pt1Dist = std::numeric_limits<float>::max(), pt2Dist = std::numeric_limits<float>::max();
43 
44  if (!allPts.empty())
45  {
46  allPts.kdTreeClosestPoint2D(rawEnd1.x, rawEnd1.y, pt1Dist);
47  allPts.kdTreeClosestPoint2D(rawEnd2.x, rawEnd2.y, pt2Dist);
48  }
49 
50  // Do we need to move these points due to former points already there, to
51  // avoid "collisions"?
52  const bool end1move = pt1Dist < mrpt::square(1.01 * wp.thickness);
53  const bool end2move = pt2Dist < mrpt::square(1.01 * wp.thickness);
54 
55  const auto vec12 = rawEnd2 - rawEnd1;
56  ASSERT_(vec12.norm() > 0);
57  const auto u12 = vec12.unitarize();
58 
59  const double t_hf = 0.5 * wp.thickness;
60  const double t = 0.5 * wp.thickness;
61 
62  const auto end1 = end1move ? (rawEnd1 + u12 * (-t)) : rawEnd1;
63  const auto end2 = end2move ? (rawEnd2 + u12 * t) : rawEnd2;
64 
65  const auto ptCenter = (end1 + end2) * 0.5;
66  const double wallLineAngle = std::atan2(vec12.y, vec12.x);
67 
68  allPts.insertPoint(rawEnd1);
69  allPts.insertPoint(rawEnd2);
70 
71  // initial pose:
72  b->setPose({ptCenter.x, ptCenter.y, 0, wallLineAngle, 0, 0});
73 
74  // Shape:
75  {
76  const double l_hf = 0.5 * (end2 - end1).norm();
77 
78  ASSERT_(l_hf > 0);
79  ASSERT_(t_hf > 0);
80 
81  auto bbmin = mrpt::math::TPoint3D(-l_hf, -t_hf, 0);
82  auto bbmax = mrpt::math::TPoint3D(+l_hf, +t_hf, 0);
83 
84  mrpt::math::TPolygon2D p;
85  p.emplace_back(bbmin.x, bbmin.y);
86  p.emplace_back(bbmin.x, bbmax.y);
87  p.emplace_back(bbmax.x, bbmax.y);
88  p.emplace_back(bbmax.x, bbmin.y);
89 
90  b->blockShape(p);
91 
92  b->block_z_min(.0);
93  b->block_z_max(wp.height);
94  }
95 
96  // make the walls non-movable:
97  b->ground_friction(1e5);
98  b->mass(1e5);
99 
100  // Register bodies, fixtures, etc. in Box2D simulator:
101  // ----------------------------------------------------
102  b->create_multibody_system(*parent->getBox2DWorld());
103  // This makes the walls non-mobile:
104  b->setIsStatic(true);
105 
106  if (auto bb = b->b2d_body(); bb != nullptr)
107  {
108  // Init pos:
109  const auto q = b->getPose();
110 
111  bb->SetTransform(b2Vec2(q.x, q.y), q.yaw);
112  // Init vel:
113  bb->SetLinearVelocity({0, 0});
114  bb->SetAngularVelocity(0);
115  }
116 
117  return b;
118 }
119 
121 {
122  MRPT_START
123 
124  // Sanity checks:
125  ASSERT_(0 == strcmp(node.name(), "walls"));
126 
127  std::string wallModelFileName;
128  std::string sTransformation;
129  double scale = 1.0;
130  mrpt::img::TColor wallColor{0x32, 0x32, 0x32, 0xff};
131  WallProperties wp;
132 
133  TParameterDefinitions params;
134  params["model_uri"] = TParamEntry("%s", &wallModelFileName);
135  params["transformation"] = TParamEntry("%s", &sTransformation);
136  params["wallThickness"] = TParamEntry("%lf", &wp.thickness);
137  params["wallHeight"] = TParamEntry("%lf", &wp.height);
138  params["scale"] = TParamEntry("%lf", &scale);
139  params["color"] = TParamEntry("%color", &wallColor);
140 
141  // Parse XML params:
142  parse_xmlnode_children_as_param(node, params, user_defined_variables());
143 
144  // Optional transformation:
145  auto HM = mrpt::math::CMatrixDouble44::Identity();
146  if (!sTransformation.empty())
147  {
148  std::stringstream ssError;
149  bool ok = HM.fromMatlabStringFormat(sTransformation, ssError);
150  if (!ok)
151  THROW_EXCEPTION_FMT(
152  "Error parsing 'transformation=\"%s\"' parameter of walls:\n%s",
153  sTransformation.c_str(), ssError.str().c_str());
154  MRPT_LOG_DEBUG_STREAM("Walls: using transformation: " << HM.asString());
155  }
156  const auto tf = mrpt::poses::CPose3D(HM);
157 
158  // Walls shape can come from external model file, or from a "shape" entry:
159  const auto* xml_shape = node.first_node("shape");
160 
161  // Final coordinates for wall perimeter are defined here:
162  std::vector<mrpt::math::TPoint3Df> tfPts;
163 
164  if (xml_shape)
165  {
166  // Load wall segments from "<shape>" tag.
167  mrpt::math::TPolygon2D segments;
168 
169  mvsim::parse_xmlnode_shape(*xml_shape, segments, "[World::process_load_walls]");
170 
171  MRPT_LOG_DEBUG_STREAM("Walls loaded from <shape> tag, " << segments.size() << " segments.");
172 
173  // Transform them:
174  tfPts.reserve(segments.size());
175  for (const auto& pt : segments)
176  tfPts.emplace_back(tf.composePoint(mrpt::math::TPoint3D(pt)));
177  }
178  else
179  {
180  // Load wall segments from external file.
181  ASSERT_(!wallModelFileName.empty());
182  const std::string localFileName = xmlPathToActualPath(wallModelFileName);
183  ASSERT_FILE_EXISTS_(localFileName);
184 
185  MRPT_LOG_DEBUG_STREAM("Loading walls definition model from: " << localFileName);
186 
187  auto glModel = mrpt::opengl::CAssimpModel::Create();
188  glModel->loadScene(localFileName);
189 
190  const auto& points = glModel->shaderWireframeVertexPointBuffer();
191  MRPT_LOG_DEBUG_STREAM("Walls loaded from model file, " << points.size() << " segments.");
192 
193  // Transform them:
194  tfPts.reserve(points.size());
195  for (const auto& pt : points) tfPts.emplace_back(tf.composePoint(pt));
196  }
197 
198  // Insert all points for KD-tree lookup:
199  mrpt::maps::CSimplePointsMap ptsMap;
200 
201  // Create walls themselves:
202  ASSERT_(tfPts.size() % 2 == 0);
203  for (size_t i = 0; i < tfPts.size() / 2; i++)
204  {
205  const auto& pt1 = tfPts[i * 2 + 0];
206  const auto& pt2 = tfPts[i * 2 + 1];
207  auto block = create_wall_segment(this, pt1, pt2, wp, ptsMap);
208  block->block_color(wallColor);
209  insertBlock(block);
210  }
211 
212  MRPT_END
213 }
WallProperties::height
double height
Definition: World_walls.cpp:27
mvsim
Definition: Client.h:21
mvsim::TParamEntry
Definition: TParameterDefinitions.h:38
mvsim::parse_xmlnode_children_as_param
void parse_xmlnode_children_as_param(const rapidxml::xml_node< char > &xml_node, const TParameterDefinitions &params, const std::map< std::string, std::string > &variableNamesValues={}, const char *functionNameContext="", mrpt::system::COutputLogger *logger=nullptr)
Definition: xml_utils.cpp:215
mvsim::World::process_load_walls
void process_load_walls(const rapidxml::xml_node< char > &node)
Definition: World_walls.cpp:120
World.h
WallProperties::thickness
double thickness
Definition: World_walls.cpp:28
WallProperties
Definition: World_walls.cpp:25
b2Vec2
A 2D column vector.
Definition: b2_math.h:41
ok
ROSCPP_DECL bool ok()
xml_utils.h
create_wall_segment
static Block::Ptr create_wall_segment(World *parent, const mrpt::math::TPoint3D &rawEnd1, const mrpt::math::TPoint3D &rawEnd2, const WallProperties &wp, mrpt::maps::CSimplePointsMap &allPts)
Definition: World_walls.cpp:31
rapidxml::xml_node::first_node
xml_node< Ch > * first_node(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
Definition: rapidxml.hpp:936
mvsim::TParameterDefinitions
std::map< std::string, TParamEntry > TParameterDefinitions
Definition: TParameterDefinitions.h:64
mvsim::World::getBox2DWorld
std::unique_ptr< b2World > & getBox2DWorld()
Definition: World.h:307
rapidxml_utils.hpp
mvsim::World
Definition: World.h:82
rapidxml::xml_node< char >
std
mvsim::Block::Ptr
std::shared_ptr< Block > Ptr
Definition: Block.h:53
mvsim::parse_xmlnode_shape
void parse_xmlnode_shape(const rapidxml::xml_node< char > &xml_node, mrpt::math::TPolygon2D &out_poly, const char *functionNameContext="")
Definition: xml_utils.cpp:258
tf
rapidxml.hpp
t
geometry_msgs::TransformStamped t
rapidxml_print.hpp


mvsim
Author(s):
autogenerated on Wed May 28 2025 02:13:08