picea/constraints/
point.rs1use picea_macro_tools::Fields;
2
3use crate::{
4 element::ID,
5 math::{point::Point, vector::Vector, FloatNum},
6 scene::context::ConstraintParameters,
7};
8
9use super::{compute_soft_constraints_params, ConstraintObject, JoinConstraintConfig};
10
11#[derive(Fields)]
12pub struct PointConstraint<Obj: ConstraintObject> {
13 #[r]
14 id: u32,
15 #[r]
16 obj_id: ID,
17 #[r]
18 #[w]
19 fixed_point: Point,
20 #[r]
21 move_point: Point, #[r]
23 total_lambda: FloatNum,
24 position_bias: FloatNum,
28 soft_part: FloatNum,
29 mass_effective: FloatNum,
30 obj: *mut Obj,
31 #[r]
32 #[w]
33 config: JoinConstraintConfig,
34}
35
36impl<Obj: ConstraintObject> PointConstraint<Obj> {
37 pub fn new(
38 id: u32,
39 obj_id: ID,
40 fixed_point: Point,
41 move_point: Point,
42 config: JoinConstraintConfig,
43 ) -> Self {
44 assert!(
45 config.distance >= 0.,
46 "distance must large than or equal to zero"
47 );
48
49 Self {
50 id,
51 obj_id,
52 fixed_point,
53 move_point,
54 total_lambda: 0.,
55 position_bias: 0.,
56 soft_part: 0.,
57 mass_effective: 0.,
58 obj: std::ptr::null_mut(),
59 config,
60 }
61 }
62
63 pub fn stretch_length(&self) -> Vector {
64 (self.move_point, self.fixed_point).into()
65 }
66
67 pub(crate) unsafe fn reset_params(
68 &mut self,
69 move_point: Point,
70 obj: *mut Obj,
71 delta_time: FloatNum,
72 ) {
73 self.move_point = move_point;
74 self.total_lambda = 0.;
75
76 let meta = (*obj).meta();
77 let mass = meta.mass();
78 let inv_mass = meta.inv_mass();
79 let inv_moment_of_inertia = meta.inv_moment_of_inertia();
80
81 let (force_soft_factor, position_fix_factor) = if self.config.hard {
82 (0., 1.)
83 } else {
84 compute_soft_constraints_params(
85 mass,
86 self.config.damping_ratio,
87 self.config.frequency,
88 delta_time,
89 )
90 };
91
92 let strength_length = self.stretch_length();
93 let n = -strength_length.normalize();
94
95 let position_bias = position_fix_factor
96 * (strength_length.abs() - self.config.distance)
97 * delta_time.recip();
98
99 let soft_part = force_soft_factor * delta_time.recip();
100
101 let r_t: Vector = ((*obj).center_point(), self.move_point).into();
102
103 let mass_effective = inv_mass + (r_t ^ n).powf(2.) * inv_moment_of_inertia;
104
105 self.position_bias = position_bias;
108 self.soft_part = soft_part;
109 self.mass_effective = mass_effective;
110 self.obj = obj;
111 }
112
113 pub(crate) unsafe fn solve(&mut self, parameters: &ConstraintParameters) {
114 let strength_length = self.stretch_length();
115 if strength_length.abs() < parameters.max_allow_permeate {
116 return;
118 }
119
120 let obj = &mut *self.obj;
121
122 let &mut Self {
123 position_bias,
124 mass_effective,
125 soft_part,
126 ..
127 } = self;
128
129 let r_t: Vector = (obj.center_point(), self.move_point).into();
130
131 let n = -strength_length.normalize();
132
133 let v: Vector = obj.compute_point_velocity(&self.move_point);
134
135 let jv_b: f32 = -(v * n + position_bias);
136
137 let lambda = jv_b * (soft_part + mass_effective).recip();
138
139 let impulse = n * lambda;
140
141 obj.meta_mut().apply_impulse(impulse, r_t);
144 }
145}