Block.cpp
Go to the documentation of this file.
1 /*+-------------------------------------------------------------------------+
2  | MultiVehicle simulator (libmvsim) |
3  | |
4  | Copyright (C) 2014-2023 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/bits_math.h>
11 #include <mrpt/core/format.h>
12 #include <mrpt/core/lock_helper.h>
13 #include <mrpt/math/TPose2D.h>
14 #include <mrpt/opengl/CBox.h>
15 #include <mrpt/opengl/CCylinder.h>
16 #include <mrpt/opengl/CPolyhedron.h>
17 #include <mrpt/opengl/CSphere.h>
18 #include <mrpt/poses/CPose2D.h>
19 #include <mrpt/version.h>
20 #include <mvsim/Block.h>
21 #include <mvsim/World.h>
22 
23 #include <map>
24 #include <rapidxml.hpp>
25 #include <rapidxml_print.hpp>
26 #include <rapidxml_utils.hpp>
27 #include <sstream> // std::stringstream
28 #include <string>
29 
30 #include "JointXMLnode.h"
31 #include "XMLClassesRegistry.h"
32 #include "xml_utils.h"
33 
34 using namespace mvsim;
35 using namespace std;
36 
37 static XmlClassesRegistry block_classes_registry("block:class");
38 
39 // Protected ctor:
40 Block::Block(World* parent) : VisualObject(parent), Simulable(parent)
41 {
42  // Default shape:
43  block_poly_.emplace_back(-0.5, -0.5);
44  block_poly_.emplace_back(-0.5, 0.5);
45  block_poly_.emplace_back(0.5, 0.5);
46  block_poly_.emplace_back(0.5, -0.5);
48 }
49 
53 {
54  // Sanity checks:
55  if (!xml_node)
56  throw runtime_error(
57  "[Block::register_vehicle_class] XML node is nullptr");
58  if (0 != strcmp(xml_node->name(), "block:class"))
59  throw runtime_error(mrpt::format(
60  "[Block::register_block_class] XML element is '%s' "
61  "('block:class' expected)",
62  xml_node->name()));
63 
64  // rapidxml doesn't allow making copied of objects.
65  // So: convert to txt; then re-parse.
66  std::stringstream ss;
67  ss << *xml_node;
68 
69  block_classes_registry.add(ss.str());
70 }
71 
73 {
74  using namespace std;
75  using namespace rapidxml;
76 
77  if (!root) throw runtime_error("[Block::factory] XML node is nullptr");
78  if (0 != strcmp(root->name(), "block"))
79  throw runtime_error(mrpt::format(
80  "[Block::factory] XML root element is '%s' ('block' expected)",
81  root->name()));
82 
83  // "class": When there is a 'class="XXX"' attribute, look for each parameter
84  // in the set of "root" + "class_root" XML nodes:
85  // --------------------------------------------------------------------------------
86  JointXMLnode<> nodes;
87  const rapidxml::xml_node<char>* class_root = nullptr;
88  {
89  // Always search in root. Also in the class root, if any:
90  nodes.add(root);
91  if (const xml_attribute<>* block_class = root->first_attribute("class");
92  block_class)
93  {
94  const string sClassName = block_class->value();
95  if (class_root = block_classes_registry.get(sClassName);
96  !class_root)
97  THROW_EXCEPTION_FMT(
98  "[Block::factory] Block class '%s' undefined",
99  sClassName.c_str());
100 
101  nodes.add(class_root);
102  }
103  }
104 
105  // Build object (we don't use class factory for blocks)
106  // ----------------------------------------------------
107  Block::Ptr block = std::make_shared<Block>(parent);
108 
109  // Init params
110  // -------------------------------------------------
111  // attrib: name
112  {
113  const xml_attribute<>* attrib_name = root->first_attribute("name");
114  if (attrib_name && attrib_name->value())
115  {
116  block->name_ = attrib_name->value();
117  }
118  else
119  {
120  // Default name:
121  static int cnt = 0;
122  block->name_ = mrpt::format("block%03i", ++cnt);
123  }
124  }
125 
126  // Common setup for simulable objects:
127  // -----------------------------------------------------------
128  block->parseSimulable(nodes);
129 
130  // Params:
131  // -----------------------------------------------------------
133  *root, block->params_, parent->user_defined_variables(),
134  "[Block::factory]");
135  if (class_root)
137  *class_root, block->params_, parent->user_defined_variables(),
138  "[Block::factory]");
139 
140  // Custom visualization 3D model:
141  // -----------------------------------------------------------
142  block->parseVisual(nodes);
143 
144  // Shape node (optional, fallback to default shape if none found)
145  if (const auto* xml_shape = nodes.first_node("shape"); xml_shape)
146  {
148  *xml_shape, block->block_poly_, "[Block::factory]");
149  block->updateMaxRadiusFromPoly();
150  }
151  else if (const auto* xml_geom = nodes.first_node("geometry"); xml_geom)
152  {
153  block->internal_parseGeometry(*xml_geom);
154  }
155 
156  // Auto shape node from visual?
157  if (const rapidxml::xml_node<char>* xml_shape_viz =
158  nodes.first_node("shape_from_visual");
159  xml_shape_viz)
160  {
161  const auto& bbVis = block->collisionShape();
162  if (!bbVis.has_value())
163  {
164  THROW_EXCEPTION(
165  "Error: Tag <shape_from_visual/> found but neither <visual> "
166  "nor <geometry> entries, while parsing <block>");
167  }
168  const auto& bb = bbVis.value();
169 
170  if (bb.volume() == 0)
171  {
172  THROW_EXCEPTION(
173  "Error: Tag <shape_from_visual/> found but bounding box of "
174  "visual object seems incorrect, while parsing <block>");
175  }
176 
177  // Set contour polygon:
178  block->block_poly_ = bb.getContour();
179  block->block_z_min(bb.zMin());
180  block->block_z_max(bb.zMax());
181  }
182  else
183  {
184  // set zmin/zmax to defaults, if not set explicitly by the user in the
185  // XML file, and we didn't have a "shaped_from_visual" tag:
186  if (block->default_block_z_min_max())
187  {
188  block->block_z_min(0.0);
189  block->block_z_max(1.0);
190  }
191  }
192 
193  block->updateMaxRadiusFromPoly();
194 
195  // Register bodies, fixtures, etc. in Box2D simulator:
196  // ----------------------------------------------------
197  block->create_multibody_system(*parent->getBox2DWorld());
198 
199  if (block->b2dBody_)
200  {
201  // Init pos:
202  const auto q = block->getPose();
203  const auto dq = block->getTwist();
204 
205  block->b2dBody_->SetTransform(b2Vec2(q.x, q.y), q.yaw);
206  // Init vel:
207  block->b2dBody_->SetLinearVelocity(b2Vec2(dq.vx, dq.vy));
208  block->b2dBody_->SetAngularVelocity(dq.omega);
209  }
210 
211  return block;
212 }
213 
214 Block::Ptr Block::factory(World* parent, const std::string& xml_text)
215 {
216  // Parse the string as if it was an XML file:
217  std::stringstream s;
218  s.str(xml_text);
219 
220  char* input_str = const_cast<char*>(xml_text.c_str());
222  try
223  {
224  xml.parse<0>(input_str);
225  }
226  catch (rapidxml::parse_error& e)
227  {
228  unsigned int line =
229  static_cast<long>(std::count(input_str, e.where<char>(), '\n') + 1);
230  throw std::runtime_error(mrpt::format(
231  "[Block::factory] XML parse error (Line %u): %s",
232  static_cast<unsigned>(line), e.what()));
233  }
234  return Block::factory(parent, xml.first_node());
235 }
236 
238 {
240 }
241 
245 {
247 }
248 
250  const mrpt::optional_ref<mrpt::opengl::COpenGLScene>& viz,
251  const mrpt::optional_ref<mrpt::opengl::COpenGLScene>& physical,
252  bool childrenOnly)
253 {
254  // 1st time call?? -> Create objects
255  // ----------------------------------
256  if (!childrenOnly)
257  {
258  if (!gl_block_ && viz && physical)
259  {
260  gl_block_ = mrpt::opengl::CSetOfObjects::Create();
261  gl_block_->setName(name_);
262 
263  // Block shape:
264  auto gl_poly = mrpt::opengl::CPolyhedron::CreateCustomPrism(
266  gl_poly->setLocation(0, 0, block_z_min_);
267  gl_poly->setColor_u8(block_color_);
268 
269 // Hide back faces:
270 #if MRPT_VERSION >= 0x240
271  // gl_poly->cullFaces(mrpt::opengl::TCullFace::FRONT);
272 #endif
273 
274  gl_block_->insert(gl_poly);
275 
276  viz->get().insert(gl_block_);
277  physical->get().insert(gl_block_);
278  }
279 
280  // Update them:
281  // If "viz" does not have a value, it's because we are already
282  // inside a setPose() change event, so my caller already holds the
283  // mutex and we don't need/can't acquire it again:
284  const auto objectPose = viz.has_value() ? getPose() : getPoseNoLock();
285 
286  if (gl_block_) gl_block_->setPose(objectPose);
287  }
288 
289  if (!gl_forces_ && viz)
290  {
291  // Visualization of forces:
292  gl_forces_ = mrpt::opengl::CSetOfLines::Create();
293  gl_forces_->setLineWidth(3.0);
294  gl_forces_->setColor_u8(0xff, 0xff, 0xff);
295 
296  viz->get().insert(gl_forces_); // forces are in global coords
297  }
298 
299  // Other common stuff:
300  if (viz) internal_internalGuiUpdate_forces(viz->get());
301 }
302 
304  [[maybe_unused]] mrpt::opengl::COpenGLScene& scene)
305 {
307  {
308  std::lock_guard<std::mutex> csl(force_segments_for_rendering_cs_);
309  gl_forces_->clear();
311  gl_forces_->setVisibility(true);
312  }
313  else
314  {
315  gl_forces_->setVisibility(false);
316  }
317 }
318 
320 {
321  using namespace mrpt::math;
322 
323  maxRadius_ = 0.001f;
324  for (const auto& segment : block_poly_)
325  {
326  const float n = segment.norm();
327  mrpt::keep_max(maxRadius_, n);
328  }
329 }
330 
333 {
334  if (intangible_) return;
335 
336  // Update collision shape from shape loaded from XML or set manually:
337  {
338  Shape2p5 cs;
340  setCollisionShape(cs);
341  }
342 
343  // Define the dynamic body. We set its position and call the body
344  // factory.
345  b2BodyDef bodyDef;
346  bodyDef.type = b2_dynamicBody;
347 
348  b2dBody_ = world.CreateBody(&bodyDef);
349 
350  // Define shape of block:
351  // ------------------------------
352  {
353  // Convert shape into Box2D format:
354  const size_t nPts = block_poly_.size();
355  ASSERT_(nPts >= 3);
356  ASSERT_LE_(nPts, (size_t)b2_maxPolygonVertices);
357  std::vector<b2Vec2> pts(nPts);
358  for (size_t i = 0; i < nPts; i++)
359  pts[i] = b2Vec2(block_poly_[i].x, block_poly_[i].y);
360 
361  b2PolygonShape blockPoly;
362  blockPoly.Set(&pts[0], nPts);
363 
364  // FIXED value by design in b2Box: The "skin" depth of the body
365  blockPoly.m_radius = 2.5e-3; // b2_polygonRadius;
366 
367  // Define the dynamic body fixture.
368  b2FixtureDef fixtureDef;
369  fixtureDef.shape = &blockPoly;
370  fixtureDef.restitution = restitution_;
371 
372  // Set the box density to be non-zero, so it will be dynamic.
374  blockPoly.ComputeMass(&mass, 1); // Mass with density=1 => compute area
375  fixtureDef.density = mass_ / mass.mass;
376 
377  // Override the default friction.
378  fixtureDef.friction = lateral_friction_; // 0.3f;
379 
380  // Add the shape to the body.
381  fixture_block_ = b2dBody_->CreateFixture(&fixtureDef);
382 
383  // Static (does not move at all) vs dynamic object:
384  b2dBody_->SetType(isStatic_ ? b2_staticBody : b2_dynamicBody);
385 
386  // Compute center of mass:
387  b2MassData vehMass;
388  fixture_block_->GetMassData(&vehMass);
389  block_com_.x = vehMass.center.x;
390  block_com_.y = vehMass.center.y;
391  }
392 
393  // Create "archor points" to simulate friction with the ground:
394  // -----------------------------------------------------------------
395  const size_t nContactPoints = 2;
396  const double weight_per_contact_point =
397  mass_ * parent()->get_gravity() / nContactPoints;
398  const double mu = groundFriction_;
399  const double max_friction = mu * weight_per_contact_point;
400 
401  // Location (local coords) of each contact-point:
402  const mrpt::math::TPoint2D pt_loc[nContactPoints] = {
403  mrpt::math::TPoint2D(maxRadius_, 0),
404  mrpt::math::TPoint2D(-maxRadius_, 0)};
405 
406  b2FrictionJointDef fjd;
407 
409  fjd.bodyB = b2dBody_;
410 
411  for (size_t i = 0; i < nContactPoints; i++)
412  {
413  const b2Vec2 local_pt = b2Vec2(pt_loc[i].x, pt_loc[i].y);
414 
415  fjd.localAnchorA = b2dBody_->GetWorldPoint(local_pt);
416  fjd.localAnchorB = local_pt;
417  fjd.maxForce = max_friction;
418  fjd.maxTorque = 0;
419 
420  b2FrictionJoint* b2_friction = dynamic_cast<b2FrictionJoint*>(
421  world_->getBox2DWorld()->CreateJoint(&fjd));
422  friction_joints_.push_back(b2_friction);
423  }
424 }
425 
427  const mrpt::math::TVector2D& force, const mrpt::math::TPoint2D& applyPoint)
428 {
429  if (intangible_) return;
430  ASSERT_(b2dBody_);
431  // Application point -> world coords
432  const b2Vec2 wPt =
433  b2dBody_->GetWorldPoint(b2Vec2(applyPoint.x, applyPoint.y));
434  b2dBody_->ApplyForce(b2Vec2(force.x, force.y), wPt, true /*wake up*/);
435 }
436 
437 bool Block::isStatic() const
438 {
439  if (intangible_) return true;
440  ASSERT_(b2dBody_);
441  return b2dBody_->GetType() == b2_staticBody;
442 }
443 
444 void Block::setIsStatic(bool b)
445 {
446  if (intangible_) return;
447  ASSERT_(b2dBody_);
448  b2dBody_->SetType(b ? b2_staticBody : b2_dynamicBody);
449 }
450 
451 // Protected ctor:
453  : VisualObject(parent), Simulable(parent)
454 {
455 }
456 
458  const mrpt::optional_ref<mrpt::opengl::COpenGLScene>& viz,
459  const mrpt::optional_ref<mrpt::opengl::COpenGLScene>& physical,
460  [[maybe_unused]] bool childrenOnly)
461 {
462  if (!viz || !physical) return;
463 
464  for (auto& s : sensors_) s->guiUpdate(viz, physical);
465 }
466 
468  const rapidxml::xml_node<char>& xml_geom_node)
469 {
470  std::string type; // cylinder, sphere, etc.
471  float radius = 0;
472  float length = 0, lx = 0, ly = 0, lz = 0;
473  int vertex_count = 0;
474 
475  const TParameterDefinitions params = {
476  {"type", {"%s", &type}},
477  {"radius", {"%f", &radius}},
478  {"length", {"%f", &length}},
479  {"lx", {"%f", &lx}},
480  {"ly", {"%f", &ly}},
481  {"lz", {"%f", &lz}},
482  {"vertex_count", {"%i", &vertex_count}},
483  };
484 
486  xml_geom_node, params, world_->user_defined_variables(),
487  "[Block::internal_parseGeometry]");
488 
489  if (type.empty())
490  {
491  THROW_EXCEPTION(
492  "Geometry type attribute is missing, i.e. <geometry type='...' ... "
493  "/>");
494  }
495 
496  if (type == "cylinder")
497  {
498  ASSERTMSG_(
499  radius > 0, "Missing 'radius' attribute for cylinder geometry");
500  ASSERTMSG_(
501  length > 0, "Missing 'length' attribute for cylinder geometry");
502 
503  if (vertex_count == 0) vertex_count = 10; // default
504 
505  auto glCyl = mrpt::opengl::CCylinder::Create();
506  glCyl->setHeight(length);
507  glCyl->setRadius(radius);
508  glCyl->setSlicesCount(vertex_count);
509  glCyl->setColor_u8(block_color_);
510  addCustomVisualization(glCyl);
511  }
512  else if (type == "sphere")
513  {
514  ASSERTMSG_(
515  radius > 0, "Missing 'radius' attribute for cylinder geometry");
516 
517  if (vertex_count == 0) vertex_count = 10; // default
518 
519  auto glSph = mrpt::opengl::CSphere::Create(radius, vertex_count);
520  glSph->setColor_u8(block_color_);
521  addCustomVisualization(glSph);
522  }
523  else if (type == "box")
524  {
525  ASSERTMSG_(lx > 0, "Missing 'lx' attribute for box geometry");
526  ASSERTMSG_(ly > 0, "Missing 'ly' attribute for box geometry");
527  ASSERTMSG_(lz > 0, "Missing 'lz' attribute for box geometry");
528 
529  auto glBox = mrpt::opengl::CBox::Create();
530  glBox->setBoxCorners({0, 0, 0}, {lx, ly, lz});
531  glBox->setColor_u8(block_color_);
532  addCustomVisualization(glBox);
533  }
534  else
535  {
536  THROW_EXCEPTION_FMT(
537  "Unknown type in <geometry type='%s'...>", type.c_str());
538  }
539 }
540 
542 {
543  // true if any of the limits is a nan:
544  return block_z_max_ != block_z_max_ || block_z_min_ != block_z_min_;
545 }
const b2Shape * shape
Definition: b2_fixture.h:76
This file contains rapidxml parser and DOM implementation.
float mass
The mass of the shape, usually in kilograms.
Definition: b2_shape.h:36
float maxForce
The maximum friction force in N.
mrpt::math::TPoint2D block_com_
In local coordinates.
Definition: Block.h:150
std::vector< b2FrictionJoint * > friction_joints_
Definition: Block.h:135
mrpt::opengl::CSetOfLines::Ptr gl_forces_
Definition: Block.h:184
bool intangible_
Definition: Block.h:158
b2Fixture * fixture_block_
Definition: Block.h:176
b2Vec2 localAnchorA
The local anchor point relative to bodyA&#39;s origin.
float density
The density, usually in kg/m^2.
Definition: b2_fixture.h:92
mrpt::opengl::CSetOfObjects::Ptr gl_block_
Definition: Block.h:183
std::map< std::string, TParamEntry > TParameterDefinitions
virtual const char * what() const
Definition: rapidxml.hpp:85
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:224
mrpt::math::TPose3D getPose() const
Definition: Simulable.cpp:438
void updateMaxRadiusFromPoly()
Definition: Block.cpp:319
bool default_block_z_min_max() const
Definition: Block.cpp:541
float maxTorque
The maximum friction torque in N-m.
mrpt::img::TColor block_color_
Definition: Block.h:149
float x
Definition: b2_math.h:128
b2Vec2 localAnchorB
The local anchor point relative to bodyB&#39;s origin.
float y
Definition: b2_math.h:128
mrpt::math::TPose3D getPoseNoLock() const
No thread-safe version. Used internally only.
Definition: Simulable.cpp:446
double mass_
Definition: Block.h:138
double restitution_
Default: 0.01.
Definition: Block.h:154
XmlRpcServer s
std::vector< mrpt::math::TSegment3D > force_segments_for_rendering_
Definition: Block.h:186
const rapidxml::xml_node< Ch > * first_node(const char *name) const
Definition: JointXMLnode.h:30
virtual void apply_force(const mrpt::math::TVector2D &force, const mrpt::math::TPoint2D &applyPoint=mrpt::math::TPoint2D(0, 0)) override
Definition: Block.cpp:426
static Ptr factory(World *parent, const rapidxml::xml_node< char > *xml_node)
Definition: Block.cpp:72
GLenum GLuint GLenum GLsizei length
Definition: gl.h:1033
static void register_block_class(const rapidxml::xml_node< char > *xml_node)
Definition: Block.cpp:52
bool isStatic_
Definition: Block.h:139
void parse(Ch *text)
Definition: rapidxml.hpp:1381
std::unique_ptr< b2World > & getBox2DWorld()
Definition: World.h:297
void setIsStatic(bool b)
Definition: Block.cpp:444
double lateral_friction_
Default: 0.5.
Definition: Block.h:152
double mass() const
Definition: Block.h:93
void parse_xmlnode_attribs(const rapidxml::xml_node< char > &xml_node, const TParameterDefinitions &params, const std::map< std::string, std::string > &variableNamesValues={}, const char *functionNameContext="")
Definition: xml_utils.cpp:184
b2Vec2 center
The position of the shape&#39;s centroid relative to the shape&#39;s origin.
Definition: b2_shape.h:39
Ch * name() const
Definition: rapidxml.hpp:673
A 2D column vector.
Definition: b2_math.h:41
std::shared_ptr< Block > Ptr
Definition: Block.h:37
xml_node< Ch > * first_node(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
Definition: rapidxml.hpp:936
void ComputeMass(b2MassData *massData, float density) const override
Friction joint definition.
void setShapeManual(const mrpt::math::TPolygon2D &contour, const float zMin, const float zMax)
Definition: Shape2p5.cpp:219
b2BodyType type
Definition: b2_body.h:74
mrpt::math::TPolygon2D block_poly_
Definition: Block.h:140
float m_radius
Definition: b2_shape.h:102
void GetMassData(b2MassData *massData) const
Definition: b2_fixture.h:354
double block_z_max_
Definition: Block.h:147
virtual void create_multibody_system(b2World &world)
Definition: Block.cpp:332
DummyInvisibleBlock(World *parent)
Definition: Block.cpp:452
std::string name_
Definition: Simulable.h:120
const std::map< std::string, std::string > & user_defined_variables() const
Definition: World.h:391
TListSensors sensors_
Sensors aboard.
Definition: Block.h:248
void internal_parseGeometry(const rapidxml::xml_node< char > &xml_geom_node)
Definition: Block.cpp:467
void setCollisionShape(const Shape2p5 &cs)
Definition: VisualObject.h:94
virtual void simul_post_timestep(const TSimulContext &context)
Definition: Simulable.cpp:59
bool isStatic() const
Definition: Block.cpp:437
virtual void simul_pre_timestep(const TSimulContext &context) override
Definition: Block.cpp:237
virtual void simul_pre_timestep(const TSimulContext &context)
Definition: Simulable.cpp:30
Ch * value() const
Definition: rapidxml.hpp:692
void internal_internalGuiUpdate_forces(mrpt::opengl::COpenGLScene &scene)
Definition: Block.cpp:303
void Set(const b2Vec2 *points, int32 count)
void internalGuiUpdate(const mrpt::optional_ref< mrpt::opengl::COpenGLScene > &viz, const mrpt::optional_ref< mrpt::opengl::COpenGLScene > &physical, [[maybe_unused]] bool childrenOnly) override
Definition: Block.cpp:457
double maxRadius_
Definition: Block.h:144
double groundFriction_
Default: 0.5.
Definition: Block.h:153
b2Body * getBox2DGroundBody()
Definition: World.h:302
Ch * where() const
Definition: rapidxml.hpp:94
TGUI_Options guiOptions_
Definition: World.h:495
virtual void simul_post_timestep(const TSimulContext &context) override
Definition: Block.cpp:244
double block_z_min_
Definition: Block.h:146
void addCustomVisualization(const mrpt::opengl::CRenderizable::Ptr &glModel, const mrpt::poses::CPose3D &modelPose={}, const float modelScale=1.0f, const std::string &modelName="group", const std::optional< std::string > &modelURI=std::nullopt, const bool initialShowBoundingBox=false)
#define b2_maxPolygonVertices
Definition: b2_settings.h:53
void parse_xmlnode_shape(const rapidxml::xml_node< char > &xml_node, mrpt::math::TPolygon2D &out_poly, const char *functionNameContext="")
Definition: xml_utils.cpp:271
This file contains rapidxml printer implementation.
const rapidxml::xml_node< char > * get(const std::string &xml_node_class) const
void add(const std::string &input_xml_node_class)
Block(World *parent)
Definition: Block.cpp:40
b2Body * bodyA
The first attached body.
Definition: b2_joint.h:89
float restitution
The restitution (elasticity) usually in the range [0,1].
Definition: b2_fixture.h:85
This holds the mass data computed for a shape.
Definition: b2_shape.h:33
virtual void internalGuiUpdate(const mrpt::optional_ref< mrpt::opengl::COpenGLScene > &viz, const mrpt::optional_ref< mrpt::opengl::COpenGLScene > &physical, bool childrenOnly) override
Definition: Block.cpp:249
void add(const rapidxml::xml_node< Ch > *node)
Definition: JointXMLnode.h:28
static XmlClassesRegistry block_classes_registry("block:class")
xml_attribute< Ch > * first_attribute(const Ch *name=0, std::size_t name_size=0, bool case_sensitive=true) const
Definition: rapidxml.hpp:1025
b2Body * CreateBody(const b2BodyDef *def)
Definition: b2_world.cpp:115
b2Body * bodyB
The second attached body.
Definition: b2_joint.h:92
float friction
The friction coefficient, usually in the range [0,1].
Definition: b2_fixture.h:82
std::mutex force_segments_for_rendering_cs_
Definition: Block.h:185
double get_gravity() const
Definition: World.h:136
GLenum type
Definition: gl.h:1033


mvsim
Author(s):
autogenerated on Tue Jul 4 2023 03:08:19