7#include <box3d/box3d.h>
31 runtimeHandle_(runtimeHandle),
49 if (
isValid()) b3DestroyJoint(jointId_,
true);
73 if (
isValid()) b3Joint_SetCollideConnected(jointId_, collide);
77 return isValid() ? b3Joint_GetCollideConnected(jointId_) :
false;
82 nonNegative(threshold,
"Joint3D.setForceThreshold",
"threshold");
83 b3Joint_SetForceThreshold(jointId_, threshold);
86 return isValid() ? b3Joint_GetForceThreshold(jointId_) : 0.f;
90 nonNegative(threshold,
"Joint3D.setTorqueThreshold",
"threshold");
91 b3Joint_SetTorqueThreshold(jointId_, threshold);
94 return isValid() ? b3Joint_GetTorqueThreshold(jointId_) : 0.f;
97#define EV_JOINT_VEC_GETTER(name, expression, member) \
98 float Joint3D::name() const { return isValid() ? expression(jointId_).member : 0.f; }
105#undef EV_JOINT_VEC_GETTER
108 return isValid() ? b3Joint_GetLinearSeparation(jointId_) : 0.f;
111 return isValid() ? b3Joint_GetAngularSeparation(jointId_) : 0.f;
114void Joint3D::requireKind(Kind expected,
const char *
operation)
const {
121 nonNegative(
length,
"Joint3D.setDistanceLength",
"length");
122 b3DistanceJoint_SetLength(jointId_,
length);
126 return b3DistanceJoint_GetLength(jointId_);
130 return b3DistanceJoint_GetCurrentLength(jointId_);
134 nonNegative(hertz,
"Joint3D.setDistanceSpring",
"hertz");
135 nonNegative(dampingRatio,
"Joint3D.setDistanceSpring",
"dampingRatio");
136 b3DistanceJoint_SetSpringHertz(jointId_, hertz);
137 b3DistanceJoint_SetSpringDampingRatio(jointId_, dampingRatio);
138 b3DistanceJoint_EnableSpring(jointId_,
enabled);
142 nonNegative(
minimum,
"Joint3D.setDistanceLimits",
"minimum");
143 nonNegative(
maximum,
"Joint3D.setDistanceLimits",
"maximum");
145 throw eve::Exception(
"Joint3D.setDistanceLimits: minimum must be <= maximum");
147 b3DistanceJoint_EnableLimit(jointId_,
enabled);
151 finite(speed,
"Joint3D.setDistanceMotor",
"speed");
152 nonNegative(maxForce,
"Joint3D.setDistanceMotor",
"maxForce");
153 b3DistanceJoint_SetMotorSpeed(jointId_, speed);
154 b3DistanceJoint_SetMaxMotorForce(jointId_, maxForce);
155 b3DistanceJoint_EnableMotor(jointId_,
enabled);
159 float dampingRatio) {
161 finite(targetAngle,
"Joint3D.setRevoluteSpring",
"targetAngle");
162 nonNegative(hertz,
"Joint3D.setRevoluteSpring",
"hertz");
163 nonNegative(dampingRatio,
"Joint3D.setRevoluteSpring",
"dampingRatio");
164 b3RevoluteJoint_SetTargetAngle(jointId_, targetAngle);
165 b3RevoluteJoint_SetSpringHertz(jointId_, hertz);
166 b3RevoluteJoint_SetSpringDampingRatio(jointId_, dampingRatio);
167 b3RevoluteJoint_EnableSpring(jointId_,
enabled);
171 finite(lower,
"Joint3D.setRevoluteLimits",
"lower");
172 finite(upper,
"Joint3D.setRevoluteLimits",
"upper");
174 throw eve::Exception(
"Joint3D.setRevoluteLimits: lower must be <= upper");
175 b3RevoluteJoint_SetLimits(jointId_, lower, upper);
176 b3RevoluteJoint_EnableLimit(jointId_,
enabled);
180 finite(speed,
"Joint3D.setRevoluteMotor",
"speed");
181 nonNegative(maxTorque,
"Joint3D.setRevoluteMotor",
"maxTorque");
182 b3RevoluteJoint_SetMotorSpeed(jointId_, speed);
183 b3RevoluteJoint_SetMaxMotorTorque(jointId_, maxTorque);
184 b3RevoluteJoint_EnableMotor(jointId_,
enabled);
188 return b3RevoluteJoint_GetAngle(jointId_);
192 return b3RevoluteJoint_GetMotorTorque(jointId_);
196 float dampingRatio) {
198 finite(targetTranslation,
"Joint3D.setPrismaticSpring",
"targetTranslation");
199 nonNegative(hertz,
"Joint3D.setPrismaticSpring",
"hertz");
200 nonNegative(dampingRatio,
"Joint3D.setPrismaticSpring",
"dampingRatio");
201 b3PrismaticJoint_SetTargetTranslation(jointId_, targetTranslation);
202 b3PrismaticJoint_SetSpringHertz(jointId_, hertz);
203 b3PrismaticJoint_SetSpringDampingRatio(jointId_, dampingRatio);
204 b3PrismaticJoint_EnableSpring(jointId_,
enabled);
208 finite(lower,
"Joint3D.setPrismaticLimits",
"lower");
209 finite(upper,
"Joint3D.setPrismaticLimits",
"upper");
211 throw eve::Exception(
"Joint3D.setPrismaticLimits: lower must be <= upper");
212 b3PrismaticJoint_SetLimits(jointId_, lower, upper);
213 b3PrismaticJoint_EnableLimit(jointId_,
enabled);
217 finite(speed,
"Joint3D.setPrismaticMotor",
"speed");
218 nonNegative(maxForce,
"Joint3D.setPrismaticMotor",
"maxForce");
219 b3PrismaticJoint_SetMotorSpeed(jointId_, speed);
220 b3PrismaticJoint_SetMaxMotorForce(jointId_, maxForce);
221 b3PrismaticJoint_EnableMotor(jointId_,
enabled);
225 return b3PrismaticJoint_GetTranslation(jointId_);
229 return b3PrismaticJoint_GetSpeed(jointId_);
233 return b3PrismaticJoint_GetMotorForce(jointId_);
238 finite(
angle,
"Joint3D.setSphericalConeLimit",
"angle");
239 if (angle < 0.f || angle > B3_PI)
240 throw eve::Exception(
"Joint3D.setSphericalConeLimit: angle must be in [0, pi]");
241 b3SphericalJoint_SetConeLimit(jointId_,
angle);
242 b3SphericalJoint_EnableConeLimit(jointId_,
enabled);
246 finite(lower,
"Joint3D.setSphericalTwistLimits",
"lower");
247 finite(upper,
"Joint3D.setSphericalTwistLimits",
"upper");
248 if (lower > upper || lower < -0.99f * B3_PI || upper > 0.99f * B3_PI)
250 "Joint3D.setSphericalTwistLimits: require -0.99*pi <= lower <= upper <= 0.99*pi");
251 b3SphericalJoint_SetTwistLimits(jointId_, lower, upper);
252 b3SphericalJoint_EnableTwistLimit(jointId_,
enabled);
255 float velocityZ,
float maxTorque) {
257 finite(velocityX,
"Joint3D.setSphericalMotor",
"velocityX");
258 finite(velocityY,
"Joint3D.setSphericalMotor",
"velocityY");
259 finite(velocityZ,
"Joint3D.setSphericalMotor",
"velocityZ");
260 nonNegative(maxTorque,
"Joint3D.setSphericalMotor",
"maxTorque");
261 b3SphericalJoint_SetMotorVelocity(jointId_, {velocityX, velocityY, velocityZ});
262 b3SphericalJoint_SetMaxMotorTorque(jointId_, maxTorque);
263 b3SphericalJoint_EnableMotor(jointId_,
enabled);
267 return b3SphericalJoint_GetConeAngle(jointId_);
271 return b3SphericalJoint_GetTwistAngle(jointId_);
275 requireKind(
Kind::Wheel,
"Joint3D.setWheelSuspension");
276 nonNegative(hertz,
"Joint3D.setWheelSuspension",
"hertz");
277 nonNegative(dampingRatio,
"Joint3D.setWheelSuspension",
"dampingRatio");
278 b3WheelJoint_SetSuspensionHertz(jointId_, hertz);
279 b3WheelJoint_SetSuspensionDampingRatio(jointId_, dampingRatio);
280 b3WheelJoint_EnableSuspension(jointId_,
enabled);
283 requireKind(
Kind::Wheel,
"Joint3D.setWheelSuspensionLimits");
284 finite(lower,
"Joint3D.setWheelSuspensionLimits",
"lower");
285 finite(upper,
"Joint3D.setWheelSuspensionLimits",
"upper");
287 throw eve::Exception(
"Joint3D.setWheelSuspensionLimits: lower must be <= upper");
288 b3WheelJoint_SetSuspensionLimits(jointId_, lower, upper);
289 b3WheelJoint_EnableSuspensionLimit(jointId_,
enabled);
292 requireKind(
Kind::Wheel,
"Joint3D.setWheelSpinMotor");
293 finite(speed,
"Joint3D.setWheelSpinMotor",
"speed");
294 nonNegative(maxTorque,
"Joint3D.setWheelSpinMotor",
"maxTorque");
295 b3WheelJoint_SetSpinMotorSpeed(jointId_, speed);
296 b3WheelJoint_SetMaxSpinTorque(jointId_, maxTorque);
297 b3WheelJoint_EnableSpinMotor(jointId_,
enabled);
300 float dampingRatio,
float maxTorque) {
301 requireKind(
Kind::Wheel,
"Joint3D.setWheelSteering");
302 finite(targetAngle,
"Joint3D.setWheelSteering",
"targetAngle");
303 nonNegative(hertz,
"Joint3D.setWheelSteering",
"hertz");
304 nonNegative(dampingRatio,
"Joint3D.setWheelSteering",
"dampingRatio");
305 nonNegative(maxTorque,
"Joint3D.setWheelSteering",
"maxTorque");
306 b3WheelJoint_SetTargetSteeringAngle(jointId_, targetAngle);
307 b3WheelJoint_SetSteeringHertz(jointId_, hertz);
308 b3WheelJoint_SetSteeringDampingRatio(jointId_, dampingRatio);
309 b3WheelJoint_SetMaxSteeringTorque(jointId_, maxTorque);
310 b3WheelJoint_EnableSteering(jointId_,
enabled);
313 requireKind(
Kind::Wheel,
"Joint3D.setWheelSteeringLimits");
314 finite(lower,
"Joint3D.setWheelSteeringLimits",
"lower");
315 finite(upper,
"Joint3D.setWheelSteeringLimits",
"upper");
317 throw eve::Exception(
"Joint3D.setWheelSteeringLimits: lower must be <= upper");
318 b3WheelJoint_SetSteeringLimits(jointId_, lower, upper);
319 b3WheelJoint_EnableSteeringLimit(jointId_,
enabled);
322 requireKind(
Kind::Wheel,
"Joint3D.getWheelSpinSpeed");
323 return b3WheelJoint_GetSpinSpeed(jointId_);
326 requireKind(
Kind::Wheel,
"Joint3D.getWheelSpinTorque");
327 return b3WheelJoint_GetSpinTorque(jointId_);
330 requireKind(
Kind::Wheel,
"Joint3D.getWheelSteeringAngle");
331 return b3WheelJoint_GetSteeringAngle(jointId_);
334 requireKind(
Kind::Wheel,
"Joint3D.getWheelSteeringTorque");
335 return b3WheelJoint_GetSteeringTorque(jointId_);
339 requireKind(
Kind::Weld,
"Joint3D.setWeldLinearSpring");
340 nonNegative(hertz,
"Joint3D.setWeldLinearSpring",
"hertz");
341 nonNegative(dampingRatio,
"Joint3D.setWeldLinearSpring",
"dampingRatio");
342 b3WeldJoint_SetLinearHertz(jointId_, hertz);
343 b3WeldJoint_SetLinearDampingRatio(jointId_, dampingRatio);
346 requireKind(
Kind::Weld,
"Joint3D.setWeldAngularSpring");
347 nonNegative(hertz,
"Joint3D.setWeldAngularSpring",
"hertz");
348 nonNegative(dampingRatio,
"Joint3D.setWeldAngularSpring",
"dampingRatio");
349 b3WeldJoint_SetAngularHertz(jointId_, hertz);
350 b3WeldJoint_SetAngularDampingRatio(jointId_, dampingRatio);
353 requireKind(
Kind::Weld,
"Joint3D.getWeldLinearHertz");
354 return b3WeldJoint_GetLinearHertz(jointId_);
357 requireKind(
Kind::Weld,
"Joint3D.getWeldLinearDampingRatio");
358 return b3WeldJoint_GetLinearDampingRatio(jointId_);
361 requireKind(
Kind::Weld,
"Joint3D.getWeldAngularHertz");
362 return b3WeldJoint_GetAngularHertz(jointId_);
365 requireKind(
Kind::Weld,
"Joint3D.getWeldAngularDampingRatio");
366 return b3WeldJoint_GetAngularDampingRatio(jointId_);
370 requireKind(
Kind::Motor,
"Joint3D.setMotorLinearVelocity");
371 finite(
vx,
"Joint3D.setMotorLinearVelocity",
"vx");
372 finite(
vy,
"Joint3D.setMotorLinearVelocity",
"vy");
373 finite(
vz,
"Joint3D.setMotorLinearVelocity",
"vz");
374 b3MotorJoint_SetLinearVelocity(jointId_, b3Vec3{
vx,
vy,
vz});
377 requireKind(
Kind::Motor,
"Joint3D.setMotorAngularVelocity");
378 finite(
wx,
"Joint3D.setMotorAngularVelocity",
"wx");
379 finite(
wy,
"Joint3D.setMotorAngularVelocity",
"wy");
380 finite(
wz,
"Joint3D.setMotorAngularVelocity",
"wz");
381 b3MotorJoint_SetAngularVelocity(jointId_, b3Vec3{
wx,
wy,
wz});
384 requireKind(
Kind::Motor,
"Joint3D.setMotorVelocityLimits");
385 nonNegative(maxForce,
"Joint3D.setMotorVelocityLimits",
"maxForce");
386 nonNegative(maxTorque,
"Joint3D.setMotorVelocityLimits",
"maxTorque");
387 b3MotorJoint_SetMaxVelocityForce(jointId_, maxForce);
388 b3MotorJoint_SetMaxVelocityTorque(jointId_, maxTorque);
391 requireKind(
Kind::Motor,
"Joint3D.setMotorLinearSpring");
392 nonNegative(hertz,
"Joint3D.setMotorLinearSpring",
"hertz");
393 nonNegative(dampingRatio,
"Joint3D.setMotorLinearSpring",
"dampingRatio");
394 nonNegative(maxForce,
"Joint3D.setMotorLinearSpring",
"maxForce");
395 b3MotorJoint_SetLinearHertz(jointId_, hertz);
396 b3MotorJoint_SetLinearDampingRatio(jointId_, dampingRatio);
397 b3MotorJoint_SetMaxSpringForce(jointId_, maxForce);
400 requireKind(
Kind::Motor,
"Joint3D.setMotorAngularSpring");
401 nonNegative(hertz,
"Joint3D.setMotorAngularSpring",
"hertz");
402 nonNegative(dampingRatio,
"Joint3D.setMotorAngularSpring",
"dampingRatio");
403 nonNegative(maxTorque,
"Joint3D.setMotorAngularSpring",
"maxTorque");
404 b3MotorJoint_SetAngularHertz(jointId_, hertz);
405 b3MotorJoint_SetAngularDampingRatio(jointId_, dampingRatio);
406 b3MotorJoint_SetMaxSpringTorque(jointId_, maxTorque);
409 requireKind(
Kind::Motor,
"Joint3D.getMotorLinearVelocityX");
410 return b3MotorJoint_GetLinearVelocity(jointId_).x;
413 requireKind(
Kind::Motor,
"Joint3D.getMotorLinearVelocityY");
414 return b3MotorJoint_GetLinearVelocity(jointId_).y;
417 requireKind(
Kind::Motor,
"Joint3D.getMotorLinearVelocityZ");
418 return b3MotorJoint_GetLinearVelocity(jointId_).z;
421 requireKind(
Kind::Motor,
"Joint3D.getMotorAngularVelocityX");
422 return b3MotorJoint_GetAngularVelocity(jointId_).x;
425 requireKind(
Kind::Motor,
"Joint3D.getMotorAngularVelocityY");
426 return b3MotorJoint_GetAngularVelocity(jointId_).y;
429 requireKind(
Kind::Motor,
"Joint3D.getMotorAngularVelocityZ");
430 return b3MotorJoint_GetAngularVelocity(jointId_).z;
435 nonNegative(hertz,
"Joint3D.setParallelSpring",
"hertz");
436 nonNegative(dampingRatio,
"Joint3D.setParallelSpring",
"dampingRatio");
437 nonNegative(maxTorque,
"Joint3D.setParallelSpring",
"maxTorque");
438 b3ParallelJoint_SetSpringHertz(jointId_, hertz);
439 b3ParallelJoint_SetSpringDampingRatio(jointId_, dampingRatio);
440 b3ParallelJoint_SetMaxTorque(jointId_, maxTorque);
444 return b3ParallelJoint_GetSpringHertz(jointId_);
448 return b3ParallelJoint_GetSpringDampingRatio(jointId_);
452 return b3ParallelJoint_GetMaxTorque(jointId_);
ActionParameterOperation operation
#define EV_JOINT_VEC_GETTER(name, expression, member)
EVENGINE_API_FOUNDATION public API.
static constexpr RuntimeHandle invalid() noexcept
Returns the canonical invalid handle.
3D rigid body (Box3D) in meter-space coordinates (+Y up by convention). Owned by a World3D; create pr...
int getId() const
Stable id used by collision events.
void setDistanceLength(float length)
Changes distance-joint rest length in metres.
float getParallelHertz() const
Parallel spring stiffness in Hertz.
void destroy()
Destroys the backend joint and invalidates this wrapper.
void setForceThreshold(float threshold)
Sets the force threshold that emits a joint-stress event, in newtons.
float getDistanceLength() const
Distance-joint rest length in metres.
void setWheelSteering(bool enabled, float targetAngle, float hertz, float dampingRatio, float maxTorque)
Configures steering target, stiffness, damping and maximum torque.
Joint3D(World3D *world, Body3D *bodyA, Body3D *bodyB, b3JointId jointId, PhysicsJointHandle runtimeHandle, Kind kind, int id)
Internal wrapper constructor; use World3D::new*Joint.
void setMotorVelocityLimits(float maxForce, float maxTorque)
Sets motor velocity force/torque limits.
Kind
Supported joint geometry.
void setWheelSpinMotor(bool enabled, float speed, float maxTorque)
Configures wheel spin motor speed and maximum torque.
void invalidate()
Internal invalidation used by body/world destruction.
void setSphericalTwistLimits(bool enabled, float lower, float upper)
Enables spherical twist limits in radians.
float getTorqueThreshold() const
Current torque event threshold in newton-metres.
float getParallelMaxTorque() const
Parallel maximum spring torque in newton-metres.
float getWheelSpinTorque() const
Current wheel spin motor torque in newton-metres.
void setRevoluteLimits(bool enabled, float lower, float upper)
Configures revolute angular limits in radians.
void setDistanceMotor(bool enabled, float speed, float maxForce)
Configures the distance motor in metres/second and newtons.
float getRevoluteMotorTorque() const
Current revolute motor torque in newton-metres.
void setMotorAngularVelocity(float wx, float wy, float wz)
Sets motor-joint relative angular velocity in radians/second.
float getForceThreshold() const
Current force event threshold in newtons.
float getParallelDampingRatio() const
Parallel spring damping ratio.
void setSphericalMotor(bool enabled, float velocityX, float velocityY, float velocityZ, float maxTorque)
Configures spherical motor velocity and maximum torque.
float getWeldAngularHertz() const
Weld angular stiffness in Hertz.
float getWeldLinearDampingRatio() const
Weld linear damping ratio.
void setTorqueThreshold(float threshold)
Sets the torque threshold that emits a joint-stress event, in newton-metres.
void setWeldLinearSpring(float hertz, float dampingRatio)
Configures weld linear spring stiffness and damping; 0 hertz is rigid.
float getDistanceCurrentLength() const
Current anchor-to-anchor distance in metres.
float getPrismaticTranslation() const
Current prismatic translation in metres.
float getRevoluteAngle() const
Current revolute angle in radians.
void setDistanceLimits(bool enabled, float minimum, float maximum)
Configures optional distance limits in metres.
float getWheelSpinSpeed() const
Current wheel spin speed in radians/second.
void setWheelSteeringLimits(bool enabled, float lower, float upper)
Configures steering angular limits in radians.
float getPrismaticMotorForce() const
Current prismatic motor force in newtons.
void setRevoluteSpring(bool enabled, float targetAngle, float hertz, float dampingRatio)
Configures a revolute angular spring in radians.
void setPrismaticLimits(bool enabled, float lower, float upper)
Configures prismatic translation limits in metres.
std::string getKind() const
Joint kind string for script/debug ("distance", "revolute", …, "filter").
float getMotorLinearVelocityX() const
Desired motor linear velocity X in metres/second.
void setParallelSpring(float hertz, float dampingRatio, float maxTorque)
Configures parallel-joint spring stiffness, damping and torque cap.
void setMotorLinearVelocity(float vx, float vy, float vz)
Sets motor-joint relative linear velocity in metres/second.
float getMotorAngularVelocityY() const
Desired motor angular velocity Y in radians/second.
float getLinearSeparation() const
Current inadmissible linear separation error in metres.
bool isValid() const
Whether the backend joint still exists.
float getMotorAngularVelocityX() const
Desired motor angular velocity X in radians/second.
float getWheelSteeringTorque() const
Current steering torque in newton-metres.
float getMotorAngularVelocityZ() const
Desired motor angular velocity Z in radians/second.
float getWeldLinearHertz() const
Weld linear stiffness in Hertz.
float getWeldAngularDampingRatio() const
Weld angular damping ratio.
float getMotorLinearVelocityY() const
Desired motor linear velocity Y in metres/second.
float getAngularSeparation() const
Current inadmissible angular separation error in radians.
float getMotorLinearVelocityZ() const
Desired motor linear velocity Z in metres/second.
float getWheelSteeringAngle() const
Current wheel steering angle in radians.
void setDistanceSpring(bool enabled, float hertz, float dampingRatio)
Configures a distance spring; hertz and damping must be non-negative.
void setRevoluteMotor(bool enabled, float speed, float maxTorque)
Configures the revolute motor in radians/second and newton-metres.
int getBodyAId() const
Stable ID of attached body A, or -1 after invalidation.
void setWheelSuspensionLimits(bool enabled, float lower, float upper)
Configures wheel suspension travel limits in metres.
float getPrismaticSpeed() const
Current prismatic translation speed in metres/second.
bool getCollideConnected() const
Whether attached bodies may collide.
void setMotorAngularSpring(float hertz, float dampingRatio, float maxTorque)
Configures motor angular position spring.
float getSphericalConeAngle() const
Current spherical cone angle in radians.
void setPrismaticMotor(bool enabled, float speed, float maxForce)
Configures a prismatic motor in metres/second and newtons.
void setSphericalConeLimit(bool enabled, float angle)
Enables a spherical cone limit in radians, within [0, pi].
void setWeldAngularSpring(float hertz, float dampingRatio)
Configures weld angular spring stiffness and damping; 0 hertz is rigid.
int getBodyBId() const
Stable ID of attached body B, or -1 after invalidation.
void setWheelSuspension(bool enabled, float hertz, float dampingRatio)
Configures wheel suspension spring stiffness and damping.
void setPrismaticSpring(bool enabled, float targetTranslation, float hertz, float dampingRatio)
Configures a prismatic linear spring and target translation.
float getSphericalTwistAngle() const
Current spherical twist angle in radians.
void setCollideConnected(bool collide)
Enables or disables collision between the attached bodies.
void setMotorLinearSpring(float hertz, float dampingRatio, float maxForce)
Configures motor linear position spring.
Box3D rigid-body world. Script coordinates are meters (Box3D native), unlike 2D World which uses pixe...
void forgetJoint(Joint3D *joint)
Internal: removes a joint wrapper from ownership bookkeeping.
Optional physics backend for vehicle mobility and body attach.