1use super::*;
16use crate::body::BodyState;
17use crate::distance_joint::{
18 get_distance_joint_force, prepare_distance_joint, solve_distance_joint,
19 warm_start_distance_joint,
20};
21use crate::math_functions::{abs_float, add, length, min_float, Vec2, VEC2_ZERO};
22use crate::motor_joint::{
23 get_motor_joint_force, get_motor_joint_torque, prepare_motor_joint, solve_motor_joint,
24 warm_start_motor_joint,
25};
26use crate::prismatic_joint::{
27 get_prismatic_joint_force, get_prismatic_joint_torque, prepare_prismatic_joint,
28 solve_prismatic_joint, warm_start_prismatic_joint,
29};
30use crate::revolute_joint::{
31 get_revolute_joint_force, get_revolute_joint_torque, prepare_revolute_joint,
32 solve_revolute_joint, warm_start_revolute_joint,
33};
34use crate::solver::{make_soft, StepContext};
35use crate::weld_joint::{
36 get_weld_joint_force, get_weld_joint_torque, prepare_weld_joint, solve_weld_joint,
37 warm_start_weld_joint,
38};
39use crate::wheel_joint::{
40 get_wheel_joint_force, get_wheel_joint_torque, prepare_wheel_joint, solve_wheel_joint,
41 warm_start_wheel_joint,
42};
43use crate::world::World;
44
45pub fn prepare_joint(world: &World, joint: &mut JointSim, context: &StepContext) {
47 let hertz = min_float(joint.constraint_hertz, 0.25 * context.inv_h);
49 joint.constraint_softness = make_soft(hertz, joint.constraint_damping_ratio, context.h);
50
51 match joint.joint_type() {
52 JointType::Distance => prepare_distance_joint(world, joint, context),
53 JointType::Motor => prepare_motor_joint(world, joint, context),
54 JointType::Filter => {}
55 JointType::Prismatic => prepare_prismatic_joint(world, joint, context),
56 JointType::Revolute => prepare_revolute_joint(world, joint, context),
57 JointType::Weld => prepare_weld_joint(world, joint, context),
58 JointType::Wheel => prepare_wheel_joint(world, joint, context),
59 }
60}
61
62pub fn warm_start_joint(joint: &mut JointSim, states: &mut [BodyState]) {
64 match joint.joint_type() {
65 JointType::Distance => warm_start_distance_joint(joint, states),
66 JointType::Motor => warm_start_motor_joint(joint, states),
67 JointType::Filter => {}
68 JointType::Prismatic => warm_start_prismatic_joint(joint, states),
69 JointType::Revolute => warm_start_revolute_joint(joint, states),
70 JointType::Weld => warm_start_weld_joint(joint, states),
71 JointType::Wheel => warm_start_wheel_joint(joint, states),
72 }
73}
74
75pub fn solve_joint(
77 joint: &mut JointSim,
78 context: &StepContext,
79 states: &mut [BodyState],
80 use_bias: bool,
81) {
82 match joint.joint_type() {
83 JointType::Distance => solve_distance_joint(joint, context, states, use_bias),
84 JointType::Motor => solve_motor_joint(joint, context, states),
85 JointType::Filter => {}
86 JointType::Prismatic => solve_prismatic_joint(joint, context, states, use_bias),
87 JointType::Revolute => solve_revolute_joint(joint, context, states, use_bias),
88 JointType::Weld => solve_weld_joint(joint, context, states, use_bias),
89 JointType::Wheel => solve_wheel_joint(joint, context, states, use_bias),
90 }
91}
92
93pub fn get_joint_reaction(sim: &JointSim, inv_time_step: f32) -> (f32, f32) {
96 let mut linear_impulse = 0.0;
97 let mut angular_impulse = 0.0;
98
99 match &sim.payload {
100 JointPayload::Distance(joint) => {
101 linear_impulse = abs_float(
102 joint.impulse + joint.lower_impulse - joint.upper_impulse + joint.motor_impulse,
103 );
104 }
105
106 JointPayload::Motor(joint) => {
107 linear_impulse = length(add(
108 joint.linear_velocity_impulse,
109 joint.linear_spring_impulse,
110 ));
111 angular_impulse =
112 abs_float(joint.angular_velocity_impulse + joint.angular_spring_impulse);
113 }
114
115 JointPayload::Prismatic(joint) => {
116 let perp_impulse = joint.impulse.x;
117 let axial_impulse = joint.motor_impulse + joint.lower_impulse - joint.upper_impulse;
118 linear_impulse = (perp_impulse * perp_impulse + axial_impulse * axial_impulse).sqrt();
119 angular_impulse = abs_float(joint.impulse.y);
120 }
121
122 JointPayload::Revolute(joint) => {
123 linear_impulse = length(joint.linear_impulse);
124 angular_impulse =
125 abs_float(joint.motor_impulse + joint.lower_impulse - joint.upper_impulse);
126 }
127
128 JointPayload::Weld(joint) => {
129 linear_impulse = length(joint.linear_impulse);
130 angular_impulse = abs_float(joint.angular_impulse);
131 }
132
133 JointPayload::Wheel(joint) => {
134 let perp_impulse = joint.perp_impulse;
135 let axial_impulse = joint.spring_impulse + joint.lower_impulse - joint.upper_impulse;
136 linear_impulse = (perp_impulse * perp_impulse + axial_impulse * axial_impulse).sqrt();
137 angular_impulse = abs_float(joint.motor_impulse);
138 }
139
140 JointPayload::Filter => {}
141 }
142
143 (
144 linear_impulse * inv_time_step,
145 angular_impulse * inv_time_step,
146 )
147}
148
149pub(crate) fn get_joint_constraint_force(world: &World, joint_index: i32) -> Vec2 {
151 let base = get_joint_sim_ref(world, joint_index);
152
153 match world.joints[joint_index as usize].type_ {
154 JointType::Distance => get_distance_joint_force(world, base),
155 JointType::Motor => get_motor_joint_force(world, base),
156 JointType::Filter => VEC2_ZERO,
157 JointType::Prismatic => get_prismatic_joint_force(world, base),
158 JointType::Revolute => get_revolute_joint_force(world, base),
159 JointType::Weld => get_weld_joint_force(world, base),
160 JointType::Wheel => get_wheel_joint_force(world, base),
161 }
162}
163
164pub(crate) fn get_joint_constraint_torque(world: &World, joint_index: i32) -> f32 {
166 let base = get_joint_sim_ref(world, joint_index);
167
168 match world.joints[joint_index as usize].type_ {
169 JointType::Distance => 0.0,
170 JointType::Motor => get_motor_joint_torque(world, base),
171 JointType::Filter => 0.0,
172 JointType::Prismatic => get_prismatic_joint_torque(world, base),
173 JointType::Revolute => get_revolute_joint_torque(world, base),
174 JointType::Weld => get_weld_joint_torque(world, base),
175 JointType::Wheel => get_wheel_joint_torque(world, base),
176 }
177}