1use na::{DVector, RealField, Unit};
2
3use crate::math::{Point, Vector};
4use crate::object::{Body, BodyHandle, BodyPart, BodyPartHandle};
5use crate::solver::{
6 helper, BilateralConstraint, BilateralGroundConstraint, ForceDirection,
7 GenericNonlinearConstraint, ImpulseLimits, IntegrationParameters, LinearConstraints,
8};
9
10pub fn build_linear_limits_velocity_constraint<N: RealField + Copy, B: ?Sized + Body<N>, H: BodyHandle>(
11 body1: &B,
12 part1: &dyn BodyPart<N>,
13 handle1: BodyPartHandle<H>,
14 body2: &B,
15 part2: &dyn BodyPart<N>,
16 handle2: BodyPartHandle<H>,
17 assembly_id1: usize,
18 assembly_id2: usize,
19 anchor1: &Point<N>,
20 anchor2: &Point<N>,
21 axis: &Unit<Vector<N>>,
22 min: Option<N>,
23 max: Option<N>,
24 ext_vels: &DVector<N>,
25 impulse: N,
26 impulse_id: usize,
27 ground_j_id: &mut usize,
28 j_id: &mut usize,
29 jacobians: &mut [N],
30 constraints: &mut LinearConstraints<N, usize>,
31) {
32 let offset = axis.dot(&(anchor2 - anchor1));
33
34 let (unilateral, dir) = match (min, max) {
35 (None, None) => {
36 return;
37 }
38 (Some(min), Some(max)) => {
39 if relative_eq!(min, max) {
40 (false, *axis)
41 } else {
42 if offset <= min {
43 (true, -*axis)
44 } else if offset >= max {
45 (true, *axis)
46 } else {
47 return;
48 }
49 }
50 }
51 (Some(min), None) => {
52 if offset <= min {
53 (true, -*axis)
54 } else {
55 return;
56 }
57 }
58 (None, Some(max)) => {
59 if offset >= max {
60 (true, *axis)
61 } else {
62 return;
63 }
64 }
65 };
66
67 let (ext_vels1, ext_vels2) =
68 helper::split_ext_vels(body1, body2, assembly_id1, assembly_id2, ext_vels);
69 let force = ForceDirection::Linear(dir);
70 let mut rhs = N::zero();
71 let geom = helper::constraint_pair_geometry(
72 body1,
73 part1,
74 handle1,
75 body2,
76 part2,
77 handle2,
78 anchor1,
79 anchor2,
80 &force,
81 ground_j_id,
82 j_id,
83 jacobians,
84 Some(&ext_vels1),
85 Some(&ext_vels2),
86 Some(&mut rhs),
87 );
88
89 let limits = if unilateral {
91 ImpulseLimits::Independent {
92 min: N::zero(),
93 max: N::max_value(),
94 }
95 } else {
96 ImpulseLimits::Independent {
97 min: -N::max_value(),
98 max: N::max_value(),
99 }
100 };
101
102 if geom.ndofs1 == 0 || geom.ndofs2 == 0 {
103 constraints
104 .bilateral_ground
105 .push(BilateralGroundConstraint::new(
106 geom,
107 assembly_id1,
108 assembly_id2,
109 limits,
110 rhs,
111 impulse,
112 impulse_id,
113 ));
114 } else {
115 constraints.bilateral.push(BilateralConstraint::new(
116 geom,
117 assembly_id1,
118 assembly_id2,
119 limits,
120 rhs,
121 impulse,
122 impulse_id,
123 ));
124 }
125}
126
127pub fn build_linear_limits_position_constraint<N: RealField + Copy, B: ?Sized + Body<N>, H: BodyHandle>(
128 parameters: &IntegrationParameters<N>,
129 body1: &B,
130 part1: &dyn BodyPart<N>,
131 handle1: BodyPartHandle<H>,
132 body2: &B,
133 part2: &dyn BodyPart<N>,
134 handle2: BodyPartHandle<H>,
135 anchor1: &Point<N>,
136 anchor2: &Point<N>,
137 axis: &Unit<Vector<N>>,
138 min: Option<N>,
139 max: Option<N>,
140 jacobians: &mut [N],
141) -> Option<GenericNonlinearConstraint<N, H>> {
142 let offset = axis.dot(&(anchor2 - anchor1));
143 let mut error = N::zero();
144 let mut dir = *axis;
145
146 if let Some(min) = min {
147 error = min - offset;
148 dir = -*axis;
149 }
150
151 if error < N::zero() {
152 if let Some(max) = max {
153 error = offset - max;
154 dir = *axis;
155 }
156 }
157
158 if error > parameters.allowed_linear_error {
159 let mut j_id = 0;
160 let mut ground_j_id = 0;
161
162 let geom = helper::constraint_pair_geometry(
163 body1,
164 part1,
165 handle1,
166 body2,
167 part2,
168 handle2,
169 anchor1,
170 anchor2,
171 &ForceDirection::Linear(dir),
172 &mut ground_j_id,
173 &mut j_id,
174 jacobians,
175 None,
176 None,
177 None,
178 );
179
180 let rhs = -error;
181 let constraint = GenericNonlinearConstraint::new(
182 handle1,
183 Some(handle2),
184 false,
185 geom.ndofs1,
186 geom.ndofs2,
187 geom.wj_id1,
188 geom.wj_id2,
189 rhs,
190 geom.r,
191 );
192
193 Some(constraint)
194 } else {
195 None
196 }
197}
198
199