8#include <box3d/box3d.h>
16 for (
int i = 0; i <
count; ++i) {
17 if (!std::isfinite(
values[i]))
22void requireDistinctBodies(World3D *
world, Body3D *bodyA, Body3D *bodyB,
const char *
operation) {
23 if (!
world || !
world->
isValid() || !bodyA || !bodyB || !bodyA->isValid() || !bodyB->isValid() ||
24 bodyA->getWorld() !=
world || bodyB->getWorld() !=
world || bodyA == bodyB)
28b3Vec3 normalizedAxis(
float x,
float y,
float z,
const char *
operation) {
37 float anchorZ,
bool collideConnected) {
38 requireDistinctBodies(
this, bodyA, bodyB,
"World3D.newWeldJoint");
39 const float values[] = {anchorX, anchorY, anchorZ};
40 requireFiniteJointParams(
values, 3,
"World3D.newWeldJoint");
41 const b3Pos
anchor{anchorX, anchorY, anchorZ};
42 const b3WorldTransform xfA = b3Body_GetTransform(bodyA->
raw());
43 const b3WorldTransform xfB = b3Body_GetTransform(bodyB->
raw());
44 b3WeldJointDef def = b3DefaultWeldJointDef();
45 def.base.bodyIdA = bodyA->
raw();
46 def.base.bodyIdB = bodyB->
raw();
47 def.base.localFrameA.p = b3Body_GetLocalPoint(bodyA->
raw(),
anchor);
48 def.base.localFrameB.p = b3Body_GetLocalPoint(bodyB->
raw(),
anchor);
49 def.base.localFrameA.q = b3InvMulQuat(xfA.q, b3Quat_identity);
50 def.base.localFrameB.q = b3InvMulQuat(xfB.q, b3Quat_identity);
51 def.base.collideConnected = collideConnected;
53 const b3JointId
id = b3CreateWeldJoint(worldId_, &def);
55 b3Joint_SetUserData(
id, joint);
56 joints_.insert(joint);
62 requireDistinctBodies(
this, bodyA, bodyB,
"World3D.newMotorJoint");
63 b3MotorJointDef def = b3DefaultMotorJointDef();
64 def.base.bodyIdA = bodyA->
raw();
65 def.base.bodyIdB = bodyB->
raw();
66 def.base.collideConnected = collideConnected;
68 const b3JointId
id = b3CreateMotorJoint(worldId_, &def);
70 b3Joint_SetUserData(
id, joint);
71 joints_.insert(joint);
77 float axisZ,
bool collideConnected) {
78 requireDistinctBodies(
this, bodyA, bodyB,
"World3D.newParallelJoint");
80 requireFiniteJointParams(
values, 3,
"World3D.newParallelJoint");
81 const b3Vec3 worldAxis = normalizedAxis(
axisX,
axisY,
axisZ,
"World3D.newParallelJoint");
82 b3ParallelJointDef def = b3DefaultParallelJointDef();
83 def.base.bodyIdA = bodyA->
raw();
84 def.base.bodyIdB = bodyB->
raw();
85 def.base.localFrameA.q = b3ComputeQuatBetweenUnitVectors(
86 b3Vec3_axisZ, b3Body_GetLocalVector(bodyA->
raw(), worldAxis));
87 def.base.localFrameB.q = b3ComputeQuatBetweenUnitVectors(
88 b3Vec3_axisZ, b3Body_GetLocalVector(bodyB->
raw(), worldAxis));
89 def.base.collideConnected = collideConnected;
91 const b3JointId
id = b3CreateParallelJoint(worldId_, &def);
94 b3Joint_SetUserData(
id, joint);
95 joints_.insert(joint);
101 requireDistinctBodies(
this, bodyA, bodyB,
"World3D.newFilterJoint");
102 b3FilterJointDef def = b3DefaultFilterJointDef();
103 def.base.bodyIdA = bodyA->
raw();
104 def.base.bodyIdB = bodyB->
raw();
106 const b3JointId
id = b3CreateFilterJoint(worldId_, &def);
109 b3Joint_SetUserData(
id, joint);
110 joints_.insert(joint);
116 if (!mechanism)
return;
117 mechanisms_.erase(mechanism);
124 bool collideConnected) {
125 requireDistinctBodies(
this, support, rotor,
"World3D.newShaft");
126 const b3Vec3 axis = normalizedAxis(
axisX,
axisY,
axisZ,
"World3D.newShaft");
128 newRevoluteJoint(support, rotor, anchorX, anchorY, anchorZ, axis.x, axis.y, axis.z,
131 nullptr,
nullptr,
nullptr, axis.x, axis.y, axis.z, 1, 0.f);
132 mechanisms_.insert(mechanism);
138 int direction,
float engagementTorque,
bool collideConnected) {
139 requireDistinctBodies(
this, frame, wheel,
"World3D.newRatchet");
141 throw eve::Exception(
"World3D.newRatchet: direction must be +1 or -1");
142 if (!std::isfinite(engagementTorque) || engagementTorque < 0.f)
143 throw eve::Exception(
"World3D.newRatchet: engagementTorque must be finite and >= 0");
144 const b3Vec3 axis = normalizedAxis(
axisX,
axisY,
axisZ,
"World3D.newRatchet");
146 newRevoluteJoint(frame, wheel, anchorX, anchorY, anchorZ, axis.x, axis.y, axis.z,
150 nullptr,
nullptr, axis.x, axis.y, axis.z,
direction, engagementTorque);
151 mechanisms_.insert(mechanism);
156 float crankAnchorX,
float crankAnchorY,
float crankAnchorZ,
158 float crankPinY,
float crankPinZ,
float sliderPinX,
159 float sliderPinY,
float sliderPinZ,
float slideAxisX,
160 float slideAxisY,
float slideAxisZ,
bool collideConnected) {
161 requireDistinctBodies(
this, frame, crank,
"World3D.newCrankSlider");
162 requireDistinctBodies(
this, crank, rod,
"World3D.newCrankSlider");
163 requireDistinctBodies(
this, rod, slider,
"World3D.newCrankSlider");
164 requireDistinctBodies(
this, frame, slider,
"World3D.newCrankSlider");
165 if (frame == rod || crank == slider)
166 throw eve::Exception(
"World3D.newCrankSlider: bodies must form a four-bar chain");
167 const float values[] = {crankAnchorX, crankAnchorY, crankAnchorZ,
axisX,
axisY,
168 axisZ, crankPinX, crankPinY, crankPinZ, sliderPinX,
169 sliderPinY, sliderPinZ, slideAxisX, slideAxisY, slideAxisZ};
170 requireFiniteJointParams(
values, 15,
"World3D.newCrankSlider");
171 const b3Vec3 hingeAxis = normalizedAxis(
axisX,
axisY,
axisZ,
"World3D.newCrankSlider");
172 const b3Vec3 slideAxis =
173 normalizedAxis(slideAxisX, slideAxisY, slideAxisZ,
"World3D.newCrankSlider");
174 if (std::fabs(b3Dot(hingeAxis, slideAxis)) > 0.999f)
175 throw eve::Exception(
"World3D.newCrankSlider: hinge and slide axes must not be parallel");
178 newRevoluteJoint(frame, crank, crankAnchorX, crankAnchorY, crankAnchorZ, hingeAxis.x,
179 hingeAxis.y, hingeAxis.z, collideConnected);
181 newRevoluteJoint(crank, rod, crankPinX, crankPinY, crankPinZ, hingeAxis.x, hingeAxis.y,
182 hingeAxis.z, collideConnected);
184 newRevoluteJoint(rod, slider, sliderPinX, sliderPinY, sliderPinZ, hingeAxis.x, hingeAxis.y,
185 hingeAxis.z, collideConnected);
187 newPrismaticJoint(frame, slider, sliderPinX, sliderPinY, sliderPinZ, slideAxis.x,
188 slideAxis.y, slideAxis.z, collideConnected);
191 sliderPin, prismatic, hingeAxis.x, hingeAxis.y, hingeAxis.z, 1, 0.f);
192 mechanisms_.insert(mechanism);
ActionParameterOperation operation
std::map< std::string, Var > values
RoadLaneDirection direction
EVENGINE_API_FOUNDATION public API.
3D rigid body (Box3D) in meter-space coordinates (+Y up by convention). Owned by a World3D; create pr...
Script-facing Box3D joint owned by a World3D.
Composed mechanical assembly owned by a World3D.
PhysicsJointHandle nextJointRuntimeHandle()
Internal: next generation-qualified joint handle.
Joint3D * newMotorJoint(Body3D *bodyA, Body3D *bodyB, bool collideConnected=false)
Creates a motor joint that drives relative linear/angular velocity between bodies.
PhysicsWorldHandle runtimeHandle() const noexcept
Process-local identity used by PhysicsLink; invalid after destruction.
Joint3D * newWeldJoint(Body3D *bodyA, Body3D *bodyB, float anchorX, float anchorY, float anchorZ, bool collideConnected=false)
Welds two bodies at a shared world-space anchor, preserving current relative pose.
Joint3D * newParallelJoint(Body3D *bodyA, Body3D *bodyB, float axisX, float axisY, float axisZ, bool collideConnected=false)
Creates a parallel joint that spring-aligns body local Z axes to a world axis.
Joint3D * newRevoluteJoint(Body3D *bodyA, Body3D *bodyB, float anchorX, float anchorY, float anchorZ, float axisX, float axisY, float axisZ, bool collideConnected=false)
Creates a hinge around a normalized world-space axis at a shared anchor.
int nextJointId()
Internal: next stable joint id.
Mechanism3D * newCrankSlider(Body3D *frame, Body3D *crank, Body3D *rod, Body3D *slider, float crankAnchorX, float crankAnchorY, float crankAnchorZ, float axisX, float axisY, float axisZ, float crankPinX, float crankPinY, float crankPinZ, float sliderPinX, float sliderPinY, float sliderPinZ, float slideAxisX, float slideAxisY, float slideAxisZ, bool collideConnected=false)
Builds a planar crank-slider from frame, crank, connecting rod and slider bodies.
bool isValid() const
True while the underlying Box3D world is alive.
Mechanism3D * newRatchet(Body3D *frame, Body3D *wheel, float anchorX, float anchorY, float anchorZ, float axisX, float axisY, float axisZ, int direction, float engagementTorque, bool collideConnected=false)
Builds a one-way ratchet around a revolute axis.
Joint3D * newFilterJoint(Body3D *bodyA, Body3D *bodyB)
Disables collision between two specific bodies (filter joint).
Joint3D * newPrismaticJoint(Body3D *bodyA, Body3D *bodyB, float anchorX, float anchorY, float anchorZ, float axisX, float axisY, float axisZ, bool collideConnected=false)
Creates a slider whose permitted world-space translation follows axis.
Mechanism3D * newShaft(Body3D *support, Body3D *rotor, float anchorX, float anchorY, float anchorZ, float axisX, float axisY, float axisZ, bool collideConnected=false)
Builds a shaft (support↔rotor revolute) with optional drive motor helpers.
void forgetMechanism(Mechanism3D *mechanism)
Internal: removes a mechanism wrapper from ownership bookkeeping.
int nextMechanismId()
Internal: next stable mechanism id.
Optional physics backend for vehicle mobility and body attach.