1use na::{DMatrix, Point3, RealField};
2
3use crate::bounding_volume::AABB;
4use crate::math::Vector;
5use crate::query::{Contact, ContactKinematic, ContactPreprocessor};
6use crate::shape::{FeatureId, Triangle};
7
8bitflags! {
9 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
10 #[derive(Default)]
11 pub struct HeightFieldCellStatus: u8 {
13 const ZIGZAG_SUBDIVISION = 0b00000001;
15 const LEFT_TRIANGLE_REMOVED = 0b00000010;
17 const RIGHT_TRIANGLE_REMOVED = 0b00000100;
19 const CELL_REMOVED = Self::LEFT_TRIANGLE_REMOVED.bits | Self::RIGHT_TRIANGLE_REMOVED.bits;
21 }
22}
23
24#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
25#[derive(Clone, Debug)]
26pub struct HeightField<N: RealField + Copy> {
28 heights: DMatrix<N>,
29 scale: Vector<N>,
30 aabb: AABB<N>,
31 num_triangles: usize,
32 status: DMatrix<HeightFieldCellStatus>,
33}
34
35impl<N: RealField + Copy> HeightField<N> {
36 pub fn new(heights: DMatrix<N>, scale: Vector<N>) -> Self {
38 assert!(
39 heights.nrows() > 1 && heights.ncols() > 1,
40 "A heightfield heights must have at least 2 rows and columns."
41 );
42 let max = heights.max();
43 let min = heights.min();
44 let hscale = scale * na::convert::<_, N>(0.5);
45 let aabb = AABB::new(
46 Point3::new(-hscale.x, min * scale.y, -hscale.z),
47 Point3::new(hscale.x, max * scale.y, hscale.z),
48 );
49 let num_triangles = (heights.nrows() - 1) * (heights.ncols() - 1) * 2;
50 let status = DMatrix::repeat(
51 heights.nrows() - 1,
52 heights.ncols() - 1,
53 HeightFieldCellStatus::default(),
54 );
55
56 HeightField {
57 heights,
58 scale,
59 aabb,
60 num_triangles,
61 status,
62 }
63 }
64
65 pub fn nrows(&self) -> usize {
67 self.heights.nrows() - 1
68 }
69
70 pub fn ncols(&self) -> usize {
72 self.heights.ncols() - 1
73 }
74
75 fn triangle_id(&self, i: usize, j: usize, left: bool) -> usize {
76 let tid = j * (self.heights.nrows() - 1) + i;
77 if left {
78 tid
79 } else {
80 tid + self.num_triangles / 2
81 }
82 }
83
84 fn face_id(&self, i: usize, j: usize, left: bool, front: bool) -> usize {
85 let tid = self.triangle_id(i, j, left);
86 if front {
87 tid
88 } else {
89 tid + self.num_triangles
90 }
91 }
92
93 fn quantize_floor(&self, val: N, cell_size: N, num_cells: usize) -> usize {
94 let _0_5: N = na::convert(0.5);
95 let i = na::clamp(
96 ((val + _0_5) / cell_size).floor(),
97 N::zero(),
98 na::convert((num_cells - 1) as f64),
99 );
100 na::convert_unchecked::<N, f64>(i) as usize
101 }
102
103 fn quantize_ceil(&self, val: N, cell_size: N, num_cells: usize) -> usize {
104 let _0_5: N = na::convert(0.5);
105 let i = na::clamp(
106 ((val + _0_5) / cell_size).ceil(),
107 N::zero(),
108 na::convert(num_cells as f64),
109 );
110 na::convert_unchecked::<N, f64>(i) as usize
111 }
112
113 pub fn cell_at_point(&self, pt: &Point3<N>) -> Option<(usize, usize)> {
115 let _0_5: N = na::convert(0.5);
116 let scaled_pt = pt.coords.component_div(&self.scale);
117 let cell_width = self.unit_cell_width();
118 let cell_height = self.unit_cell_height();
119 let ncells_x = self.ncols();
120 let ncells_z = self.nrows();
121
122 if scaled_pt.x < -_0_5 || scaled_pt.x > _0_5 || scaled_pt.z < -_0_5 || scaled_pt.z > _0_5 {
123 None
125 } else {
126 let j = self.quantize_floor(scaled_pt.x, cell_width, ncells_x);
127 let i = self.quantize_floor(scaled_pt.z, cell_height, ncells_z);
128 Some((i, j))
129 }
130 }
131
132 pub fn x_at(&self, j: usize) -> N {
134 let _0_5: N = na::convert(0.5);
135 (-_0_5 + self.unit_cell_width() * na::convert(j as f64)) * self.scale.x
136 }
137
138 pub fn z_at(&self, i: usize) -> N {
140 let _0_5: N = na::convert(0.5);
141 (-_0_5 + self.unit_cell_height() * na::convert(i as f64)) * self.scale.z
142 }
143
144 pub fn triangles<'a>(&'a self) -> impl Iterator<Item = Triangle<N>> + 'a {
146 HeightfieldTriangles {
147 heightfield: self,
148 curr: (0, 0),
149 tris: self.triangles_at(0, 0),
150 }
151 }
152
153 pub fn triangles_at(&self, i: usize, j: usize) -> (Option<Triangle<N>>, Option<Triangle<N>>) {
158 let status = self.status[(i, j)];
159
160 if status.contains(
161 HeightFieldCellStatus::LEFT_TRIANGLE_REMOVED
162 | HeightFieldCellStatus::RIGHT_TRIANGLE_REMOVED,
163 ) {
164 return (None, None);
165 }
166
167 let cell_width = self.unit_cell_width();
168 let cell_height = self.unit_cell_height();
169
170 let _0_5: N = na::convert(0.5);
171 let z0 = -_0_5 + cell_height * na::convert(i as f64);
172 let z1 = z0 + cell_height;
173
174 let x0 = -_0_5 + cell_width * na::convert(j as f64);
175 let x1 = x0 + cell_width;
176
177 let y00 = self.heights[(i + 0, j + 0)];
178 let y10 = self.heights[(i + 1, j + 0)];
179 let y01 = self.heights[(i + 0, j + 1)];
180 let y11 = self.heights[(i + 1, j + 1)];
181
182 let mut p00 = Point3::new(x0, y00, z0);
183 let mut p10 = Point3::new(x0, y10, z1);
184 let mut p01 = Point3::new(x1, y01, z0);
185 let mut p11 = Point3::new(x1, y11, z1);
186
187 p00.coords.component_mul_assign(&self.scale);
189 p10.coords.component_mul_assign(&self.scale);
190 p01.coords.component_mul_assign(&self.scale);
191 p11.coords.component_mul_assign(&self.scale);
192
193 if status.contains(HeightFieldCellStatus::ZIGZAG_SUBDIVISION) {
194 let tri1 = if status.contains(HeightFieldCellStatus::LEFT_TRIANGLE_REMOVED) {
195 None
196 } else {
197 Some(Triangle::new(p00, p10, p11))
198 };
199
200 let tri2 = if status.contains(HeightFieldCellStatus::RIGHT_TRIANGLE_REMOVED) {
201 None
202 } else {
203 Some(Triangle::new(p00, p11, p01))
204 };
205
206 (tri1, tri2)
207 } else {
208 let tri1 = if status.contains(HeightFieldCellStatus::LEFT_TRIANGLE_REMOVED) {
209 None
210 } else {
211 Some(Triangle::new(p00, p10, p01))
212 };
213
214 let tri2 = if status.contains(HeightFieldCellStatus::RIGHT_TRIANGLE_REMOVED) {
215 None
216 } else {
217 Some(Triangle::new(p10, p11, p01))
218 };
219
220 (tri1, tri2)
221 }
222 }
223
224 pub fn cell_status(&self, i: usize, j: usize) -> HeightFieldCellStatus {
226 self.status[(i, j)]
227 }
228
229 pub fn set_cell_status(&mut self, i: usize, j: usize, status: HeightFieldCellStatus) {
231 self.status[(i, j)] = status
232 }
233
234 pub fn cells_statuses(&self) -> &DMatrix<HeightFieldCellStatus> {
236 &self.status
237 }
238
239 pub fn cells_statuses_mut(&mut self) -> &mut DMatrix<HeightFieldCellStatus> {
241 &mut self.status
242 }
243
244 pub fn heights(&self) -> &DMatrix<N> {
246 &self.heights
247 }
248
249 pub fn scale(&self) -> &Vector<N> {
251 &self.scale
252 }
253
254 pub fn cell_width(&self) -> N {
256 self.unit_cell_width() * self.scale.x
257 }
258
259 pub fn cell_height(&self) -> N {
261 self.unit_cell_height() * self.scale.z
262 }
263
264 pub fn unit_cell_width(&self) -> N {
266 N::one() / na::convert(self.heights.ncols() as f64 - 1.0)
267 }
268
269 pub fn unit_cell_height(&self) -> N {
271 N::one() / na::convert(self.heights.nrows() as f64 - 1.0)
272 }
273
274 pub fn aabb(&self) -> &AABB<N> {
276 &self.aabb
277 }
278
279 pub fn convert_triangle_feature_id(
282 &self,
283 i: usize,
284 j: usize,
285 left: bool,
286 fid: FeatureId,
287 ) -> FeatureId {
288 match fid {
289 FeatureId::Vertex(ivertex) => {
290 let nrows = self.heights.nrows();
291 let ij = i + j * nrows;
292
293 if self.status[(i, j)].contains(HeightFieldCellStatus::ZIGZAG_SUBDIVISION) {
294 if left {
295 FeatureId::Vertex([ij, ij + 1, ij + 1 + nrows][ivertex])
296 } else {
297 FeatureId::Vertex([ij, ij + 1 + nrows, ij + nrows][ivertex])
298 }
299 } else {
300 if left {
301 FeatureId::Vertex([ij, ij + 1, ij + nrows][ivertex])
302 } else {
303 FeatureId::Vertex([ij + 1, ij + 1 + nrows, ij + nrows][ivertex])
304 }
305 }
306 }
307 FeatureId::Edge(iedge) => {
308 let (nrows, ncols) = self.heights.shape();
309 let vshift = 0; let hshift = (nrows - 1) * ncols; let dshift = hshift + nrows * (ncols - 1); let idiag = dshift + i + j * (nrows - 1);
313 let itop = hshift + i + j * nrows;
314 let ibottom = itop + 1;
315 let ileft = vshift + i + j * (nrows - 1);
316 let iright = ileft + nrows - 1;
317
318 if self.status[(i, j)].contains(HeightFieldCellStatus::ZIGZAG_SUBDIVISION) {
319 if left {
320 FeatureId::Edge([ileft, ibottom, idiag][iedge])
326 } else {
327 FeatureId::Edge([idiag, iright, itop][iedge])
333 }
334 } else {
335 if left {
336 FeatureId::Edge([ileft, idiag, itop][iedge])
342 } else {
343 FeatureId::Edge([ibottom, iright, idiag][iedge])
349 }
350 }
351 }
352 FeatureId::Face(iface) => {
353 if iface == 0 {
354 FeatureId::Face(self.face_id(i, j, left, true))
355 } else {
356 FeatureId::Face(self.face_id(i, j, left, false))
357 }
358 }
359 FeatureId::Unknown => FeatureId::Unknown,
360 }
361 }
362
363 pub fn map_elements_in_local_aabb(
365 &self,
366 aabb: &AABB<N>,
367 f: &mut impl FnMut(usize, &Triangle<N>, &dyn ContactPreprocessor<N>),
368 ) {
369 let _0_5: N = na::convert(0.5);
370 let ncells_x = self.ncols();
371 let ncells_z = self.nrows();
372
373 let ref_mins = aabb.mins.coords.component_div(&self.scale);
374 let ref_maxs = aabb.maxs.coords.component_div(&self.scale);
375 let cell_width = self.unit_cell_width();
376 let cell_height = self.unit_cell_height();
377
378 if ref_maxs.x <= -_0_5 || ref_maxs.z <= -_0_5 || ref_mins.x >= _0_5 || ref_mins.z >= _0_5 {
379 return;
381 }
382
383 let min_x = self.quantize_floor(ref_mins.x, cell_width, ncells_x);
384 let min_z = self.quantize_floor(ref_mins.z, cell_height, ncells_z);
385
386 let max_x = self.quantize_ceil(ref_maxs.x, cell_width, ncells_x);
387 let max_z = self.quantize_ceil(ref_maxs.z, cell_height, ncells_z);
388
389 for j in min_x..max_x {
392 for i in min_z..max_z {
393 let status = self.status[(i, j)];
394
395 if status.contains(HeightFieldCellStatus::CELL_REMOVED) {
396 continue;
397 }
398
399 let z0 = -_0_5 + cell_height * na::convert(i as f64);
400 let z1 = z0 + cell_height;
401
402 let x0 = -_0_5 + cell_width * na::convert(j as f64);
403 let x1 = x0 + cell_width;
404
405 let y00 = self.heights[(i + 0, j + 0)];
406 let y10 = self.heights[(i + 1, j + 0)];
407 let y01 = self.heights[(i + 0, j + 1)];
408 let y11 = self.heights[(i + 1, j + 1)];
409
410 if (y00 > ref_maxs.y && y10 > ref_maxs.y && y01 > ref_maxs.y && y11 > ref_maxs.y)
411 || (y00 < ref_mins.y
412 && y10 < ref_mins.y
413 && y01 < ref_mins.y
414 && y11 < ref_mins.y)
415 {
416 continue;
417 }
418
419 let mut p00 = Point3::new(x0, y00, z0);
420 let mut p10 = Point3::new(x0, y10, z1);
421 let mut p01 = Point3::new(x1, y01, z0);
422 let mut p11 = Point3::new(x1, y11, z1);
423
424 p00.coords.component_mul_assign(&self.scale);
426 p10.coords.component_mul_assign(&self.scale);
427 p01.coords.component_mul_assign(&self.scale);
428 p11.coords.component_mul_assign(&self.scale);
429
430 if !status.contains(HeightFieldCellStatus::LEFT_TRIANGLE_REMOVED) {
432 let tri1 = if status.contains(HeightFieldCellStatus::ZIGZAG_SUBDIVISION) {
433 Triangle::new(p00, p10, p11)
434 } else {
435 Triangle::new(p00, p10, p01)
436 };
437
438 let tid = self.triangle_id(i, j, true);
439 let proc1 = HeightFieldTriangleContactPreprocessor::new(self, tid);
440 f(tid, &tri1, &proc1);
441 }
442
443 if !status.contains(HeightFieldCellStatus::RIGHT_TRIANGLE_REMOVED) {
444 let tri2 = if status.contains(HeightFieldCellStatus::ZIGZAG_SUBDIVISION) {
445 Triangle::new(p00, p11, p01)
446 } else {
447 Triangle::new(p10, p11, p01)
448 };
449 let tid = self.triangle_id(i, j, false);
450 let proc2 = HeightFieldTriangleContactPreprocessor::new(self, tid);
451 f(tid, &tri2, &proc2);
452 }
453 }
454 }
455 }
456}
457
458#[allow(dead_code)]
459pub struct HeightFieldTriangleContactPreprocessor<'a, N: RealField + Copy> {
460 heightfield: &'a HeightField<N>,
461 triangle: usize,
462}
463
464impl<'a, N: RealField + Copy> HeightFieldTriangleContactPreprocessor<'a, N> {
465 pub fn new(heightfield: &'a HeightField<N>, triangle: usize) -> Self {
466 HeightFieldTriangleContactPreprocessor {
467 heightfield,
468 triangle,
469 }
470 }
471}
472
473impl<'a, N: RealField + Copy> ContactPreprocessor<N>
474 for HeightFieldTriangleContactPreprocessor<'a, N>
475{
476 fn process_contact(
477 &self,
478 _c: &mut Contact<N>,
479 _kinematic: &mut ContactKinematic<N>,
480 _is_first: bool,
481 ) -> bool {
482 true
519 }
520}
521
522struct HeightfieldTriangles<'a, N: RealField + Copy> {
523 heightfield: &'a HeightField<N>,
524 curr: (usize, usize),
525 tris: (Option<Triangle<N>>, Option<Triangle<N>>),
526}
527
528impl<'a, N: RealField + Copy> Iterator for HeightfieldTriangles<'a, N> {
529 type Item = Triangle<N>;
530
531 fn next(&mut self) -> Option<Triangle<N>> {
532 loop {
533 if let Some(tri1) = self.tris.0.take() {
534 return Some(tri1);
535 } else if let Some(tri2) = self.tris.1.take() {
536 return Some(tri2);
537 } else {
538 self.curr.0 += 1;
539
540 if self.curr.0 >= self.heightfield.nrows() {
541 if self.curr.1 >= self.heightfield.ncols() - 1 {
542 return None;
543 }
544
545 self.curr.0 = 0;
546 self.curr.1 += 1;
547 }
548
549 self.tris = self.heightfield.triangles_at(self.curr.0, self.curr.1);
551 }
552 }
553 }
554}