MVSim
Lightweight simulator for 2.5D vehicles and robots
HumanActor.h
1 /*+-------------------------------------------------------------------------+
2  | MultiVehicle simulator (libmvsim) |
3  | |
4  | Copyright (C) 2014-2026 Jose Luis Blanco Claraco |
5  | Distributed under 3-clause BSD License |
6  | See COPYING |
7  +-------------------------------------------------------------------------+ */
8 
9 #pragma once
10 
11 #include <mrpt/opengl/CCylinder.h>
12 #include <mrpt/opengl/CSetOfObjects.h>
13 #include <mrpt/opengl/CSphere.h>
14 #include <mrpt/poses/CPose3DInterpolator.h>
15 #include <mrpt/version.h>
16 #include <mvsim/ClassFactory.h>
17 #include <mvsim/Simulable.h>
18 #include <mvsim/TParameterDefinitions.h>
19 #include <mvsim/VisualObject.h>
20 
21 #define MIN_MRPT_VERSION_ANIMATED_ASSIMP 0x020f08
22 
23 #if MRPT_VERSION >= MIN_MRPT_VERSION_ANIMATED_ASSIMP
24 #include <mrpt/opengl/CAnimatedAssimpModel.h>
25 #else
26 #include <mrpt/opengl/CAssimpModel.h>
27 #endif
28 
29 #include <memory>
30 #include <string>
31 #include <vector>
32 
33 namespace mvsim
34 {
35 class World;
36 
66 class HumanActor : public VisualObject, public Simulable
67 {
68  public:
69  using Ptr = std::shared_ptr<HumanActor>;
70 
71  HumanActor(World* parent);
72  virtual ~HumanActor() = default;
73 
74  // Delete copy/move
75  HumanActor(const HumanActor&) = delete;
76  HumanActor& operator=(const HumanActor&) = delete;
77  HumanActor(HumanActor&&) = delete;
78  HumanActor& operator=(HumanActor&&) = delete;
79 
80  // ==================== Factory ====================
81 
83  static Ptr factory(World* parent, const rapidxml::xml_node<char>* xml_node);
84 
87  static void register_actor_class(const World& parent, const rapidxml::xml_node<char>* xml_node);
88 
89  // ==================== Simulable interface ====================
90 
91  void simul_pre_timestep(const TSimulContext& context) override;
92  void simul_post_timestep(const TSimulContext& context) override;
93 
95  const mrpt::math::TVector2D& force,
96  const mrpt::math::TPoint2D& applyPoint = mrpt::math::TPoint2D(0, 0)) override
97  {
98  // Actors are kinematic, they do not respond to external forces.
99  (void)force;
100  (void)applyPoint;
101  }
102 
103  // ==================== Path & Animation Control ====================
104 
106  struct Waypoint
107  {
108  mrpt::math::TPose3D pose;
109  double pauseDuration = 0.0;
110  std::string animationHint;
111  };
112 
114  enum class AnimationState
115  {
116  Idle,
117  Walking,
118  Running,
119  Turning,
120  Custom
121  };
122 
124  void setPath(const std::vector<Waypoint>& waypoints, bool loop = true);
125 
127  void clearPath();
128 
130  AnimationState getAnimationState() const { return animState_; }
131 
133  void setAnimation(const std::string& animationName);
134 
137 
138  // ==================== Configuration ====================
139 
140  double getWalkingSpeed() const { return walkingSpeed_; }
141  void setWalkingSpeed(double speed) { walkingSpeed_ = speed; }
142 
143  double getRunningSpeed() const { return runningSpeed_; }
144  void setRunningSpeed(double speed) { runningSpeed_ = speed; }
145 
146  double getHeight() const { return height_; }
147  void setHeight(double h) { height_ = h; }
148 
149  // ==================== Collision ====================
150 
151  double getCollisionRadius() const { return collisionRadius_; }
152  double getCollisionHeight() const { return collisionHeight_; }
153 
154  protected:
155  void internalGuiUpdate(
156  const mrpt::optional_ref<mrpt::opengl::COpenGLScene>& viz,
157  const mrpt::optional_ref<mrpt::opengl::COpenGLScene>& physical, bool childrenOnly) override;
158 
159  // ==================== Configuration Parameters ====================
160 
161  double walkingSpeed_ = 1.4;
162  double runningSpeed_ = 3.5;
163  double height_ = 1.75;
164 
165  // Collision shape (capsule approximation)
166  double collisionRadius_ = 0.3;
167  double collisionHeight_ = 1.7;
168 
169  // Animation names (mapped to animations in the 3D model)
170  std::string animNameIdle_ = "idle";
171  std::string animNameWalk_ = "walk";
172  std::string animNameRun_ = "run";
173 
176  const TParameterDefinitions params_ = {
177  {"walking_speed", {"%lf", &walkingSpeed_}},
178  {"running_speed", {"%lf", &runningSpeed_}},
179  {"height", {"%lf", &height_}},
180  {"collision_radius", {"%lf", &collisionRadius_}},
181  {"collision_height", {"%lf", &collisionHeight_}},
182  {"animation_idle", {"%s", &animNameIdle_}},
183  {"animation_walk", {"%s", &animNameWalk_}},
184  {"animation_run", {"%s", &animNameRun_}},
185  };
186 
187  private:
188  // ==================== Path Following ====================
189 
190  std::vector<Waypoint> path_;
191  bool pathLoop_ = true;
192  size_t currentWaypointIdx_ = 0;
193  double waypointPauseTimer_ = 0.0;
194  bool isAtWaypoint_ = false;
195 
196  // Smooth interpolation between waypoints
197  mrpt::math::TPose3D pathStartPose_;
198  mrpt::math::TPose3D pathTargetPose_;
199  double pathSegmentProgress_ = 0.0;
200  double pathSegmentLength_ = 0.0;
201 
202  void initializePathFromCurrentPose();
203 
204  // ==================== Animation ====================
205 
206  AnimationState animState_ = AnimationState::Idle;
207  bool manualAnimationOverride_ = false;
208  std::string manualAnimationName_;
209 
210  double currentAnimTime_ = 0.0;
211  double currentMovementSpeed_ = 0.0;
212 
213  // ==================== Rendering ====================
214 #if MRPT_VERSION >= MIN_MRPT_VERSION_ANIMATED_ASSIMP
215  mrpt::opengl::CAnimatedAssimpModel::Ptr glModel_;
216 #else
217  mrpt::opengl::CAssimpModel::Ptr glModel_;
218 #endif
219  bool glInitialized_ = false;
220 
223  std::string modelFilePath_;
224 
225  // ==================== Internal Methods ====================
226 
228  void parseConfig(const rapidxml::xml_node<char>* root);
229 
231  void parsePath(const rapidxml::xml_node<char>* pathNode);
232 
234  void updatePathFollowing(const TSimulContext& context);
235 
237  void updateAnimationState(double dt);
238 
240  void updateSkeletalAnimation(double dt);
241 
243  double computeDesiredSpeed() const;
244 
246  void advanceToNextWaypoint();
247 
249  mrpt::math::TPose3D interpolatePathPose(double progress) const;
250 
254  void upgradeToAnimatedModel();
255 };
256 
257 } // namespace mvsim
Definition: HumanActor.h:67
void simul_post_timestep(const TSimulContext &context) override
AnimationState
Definition: HumanActor.h:115
double runningSpeed_
m/s
Definition: HumanActor.h:162
void apply_force(const mrpt::math::TVector2D &force, const mrpt::math::TPoint2D &applyPoint=mrpt::math::TPoint2D(0, 0)) override
Definition: HumanActor.h:94
static Ptr factory(World *parent, const rapidxml::xml_node< char > *xml_node)
void simul_pre_timestep(const TSimulContext &context) override
double walkingSpeed_
m/s (typical human walking speed)
Definition: HumanActor.h:161
void setPath(const std::vector< Waypoint > &waypoints, bool loop=true)
const TParameterDefinitions params_
Definition: HumanActor.h:176
void setAnimation(const std::string &animationName)
static void register_actor_class(const World &parent, const rapidxml::xml_node< char > *xml_node)
double height_
meters
Definition: HumanActor.h:163
void setAutomaticAnimation()
AnimationState getAnimationState() const
Definition: HumanActor.h:130
Definition: Simulable.h:40
Definition: VisualObject.h:36
Definition: World.h:132
Definition: HumanActor.h:107
std::string animationHint
"walk", "run", "idle", or empty
Definition: HumanActor.h:110
double pauseDuration
seconds to pause at this waypoint
Definition: HumanActor.h:109
Definition: basic_types.h:58