1use core::ops::Range;
2#[cfg(feature = "alloc")]
4use crate::utils::Array2;
5
6use crate::bounding_volume::Aabb;
7use crate::math::{Real, Vector};
8use crate::shape::{FeatureId, Triangle, TrianglePseudoNormals};
9
10#[cfg(not(feature = "std"))]
11use crate::math::ComplexField;
12
13#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
14#[cfg_attr(
15 feature = "rkyv",
16 derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize)
17)]
18#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
19pub struct HeightFieldCellStatus(u8);
21
22bitflags::bitflags! {
23 impl HeightFieldCellStatus: u8 {
24 const ZIGZAG_SUBDIVISION = 0b00000001;
26 const LEFT_TRIANGLE_REMOVED = 0b00000010;
28 const RIGHT_TRIANGLE_REMOVED = 0b00000100;
30 const CELL_REMOVED = Self::LEFT_TRIANGLE_REMOVED.bits() | Self::RIGHT_TRIANGLE_REMOVED.bits();
32 }
33}
34
35#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
36#[cfg_attr(
37 feature = "rkyv",
38 derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize)
39)]
40#[repr(C)]
41#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
42pub struct HeightFieldFlags(u8);
44
45bitflags::bitflags! {
46 impl HeightFieldFlags: u8 {
47 const FIX_INTERNAL_EDGES = 1 << 0;
54 }
55}
56
57#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
58#[derive(Debug, Clone)]
65#[repr(C)]
66pub struct HeightField {
68 heights: Array2<Real>,
69 status: Array2<HeightFieldCellStatus>,
70
71 scale: Vector,
72 aabb: Aabb,
73 num_triangles: usize,
74 flags: HeightFieldFlags,
75}
76
77#[cfg(feature = "alloc")]
78impl HeightField {
79 pub fn new(heights_zx: Array2<Real>, scale: Vector) -> Self {
85 Self::with_flags(heights_zx, scale, HeightFieldFlags::empty())
86 }
87
88 pub fn with_flags(heights_zx: Array2<Real>, scale: Vector, flags: HeightFieldFlags) -> Self {
90 assert!(
91 heights_zx.nrows() > 1 && heights_zx.ncols() > 1,
92 "A heightfield heights must have at least 2 rows and columns."
93 );
94 let max = heights_zx.max();
95 let min = heights_zx.min();
96 let hscale = scale * 0.5;
97 let aabb = Aabb::new(
98 Vector::new(-hscale.x, min * scale.y, -hscale.z),
99 Vector::new(hscale.x, max * scale.y, hscale.z),
100 );
101 let num_triangles = (heights_zx.nrows() - 1) * (heights_zx.ncols() - 1) * 2;
102 let status = Array2::repeat(
103 heights_zx.nrows() - 1,
104 heights_zx.ncols() - 1,
105 HeightFieldCellStatus::default(),
106 );
107
108 HeightField {
109 heights: heights_zx,
110 scale,
111 aabb,
112 num_triangles,
113 status,
114 flags,
115 }
116 }
117}
118
119impl HeightField {
120 pub fn nrows(&self) -> usize {
122 self.heights.nrows() - 1
123 }
124
125 pub fn ncols(&self) -> usize {
127 self.heights.ncols() - 1
128 }
129
130 fn triangle_id(&self, i: usize, j: usize, left: bool) -> u32 {
131 let tid = j * (self.heights.nrows() - 1) + i;
132 if left {
133 tid as u32
134 } else {
135 (tid + self.num_triangles / 2) as u32
136 }
137 }
138
139 fn split_triangle_id(&self, id: u32) -> (usize, usize, bool) {
140 let left = id < self.num_triangles as u32 / 2;
141 let tri_id = if left {
142 id as usize
143 } else {
144 id as usize - self.num_triangles / 2
145 };
146 let j = tri_id / (self.heights.nrows() - 1);
147 let i = tri_id - j * (self.heights.nrows() - 1);
148 (i, j, left)
149 }
150
151 fn face_id(&self, i: usize, j: usize, left: bool, front: bool) -> u32 {
152 let tid = self.triangle_id(i, j, left);
153 if front {
154 tid
155 } else {
156 tid + self.num_triangles as u32
157 }
158 }
159
160 fn quantize_floor_unclamped(&self, val: Real, cell_size: Real) -> isize {
161 ((val + 0.5) / cell_size).floor() as isize
162 }
163
164 fn quantize_ceil_unclamped(&self, val: Real, cell_size: Real) -> isize {
165 ((val + 0.5) / cell_size).ceil() as isize
166 }
167
168 fn quantize_floor(&self, val: Real, cell_size: Real, num_cells: usize) -> usize {
169 ((val + 0.5) / cell_size)
170 .floor()
171 .clamp(0.0, (num_cells - 1) as Real) as usize
172 }
173
174 fn quantize_ceil(&self, val: Real, cell_size: Real, num_cells: usize) -> usize {
175 ((val + 0.5) / cell_size)
176 .ceil()
177 .clamp(0.0, num_cells as Real) as usize
178 }
179
180 pub fn closest_cell_at_point(&self, pt: Vector) -> (usize, usize) {
182 let scaled_pt = pt / self.scale;
183 let cell_width = self.unit_cell_width();
184 let cell_height = self.unit_cell_height();
185 let ncells_x = self.ncols();
186 let ncells_z = self.nrows();
187
188 let j = self.quantize_floor(scaled_pt.x, cell_width, ncells_x);
189 let i = self.quantize_floor(scaled_pt.z, cell_height, ncells_z);
190 (i, j)
191 }
192
193 pub fn cell_at_point(&self, pt: Vector) -> Option<(usize, usize)> {
195 let scaled_pt = pt / self.scale;
196 let cell_width = self.unit_cell_width();
197 let cell_height = self.unit_cell_height();
198 let ncells_x = self.ncols();
199 let ncells_z = self.nrows();
200
201 if scaled_pt.x < -0.5 || scaled_pt.x > 0.5 || scaled_pt.z < -0.5 || scaled_pt.z > 0.5 {
202 None
204 } else {
205 let j = self.quantize_floor(scaled_pt.x, cell_width, ncells_x);
206 let i = self.quantize_floor(scaled_pt.z, cell_height, ncells_z);
207 Some((i, j))
208 }
209 }
210
211 pub fn unclamped_cell_at_point(&self, pt: Vector) -> (isize, isize) {
213 let scaled_pt = pt / self.scale;
214 let cell_width = self.unit_cell_width();
215 let cell_height = self.unit_cell_height();
216
217 let j = self.quantize_floor_unclamped(scaled_pt.x, cell_width);
218 let i = self.quantize_floor_unclamped(scaled_pt.z, cell_height);
219 (i, j)
220 }
221
222 pub fn x_at(&self, j: usize) -> Real {
224 (-0.5 + self.unit_cell_width() * (j as Real)) * self.scale.x
225 }
226
227 pub fn z_at(&self, i: usize) -> Real {
229 (-0.5 + self.unit_cell_height() * (i as Real)) * self.scale.z
230 }
231
232 pub fn signed_x_at(&self, j: isize) -> Real {
234 (-0.5 + self.unit_cell_width() * (j as Real)) * self.scale.x
235 }
236
237 pub fn signed_z_at(&self, i: isize) -> Real {
239 (-0.5 + self.unit_cell_height() * (i as Real)) * self.scale.z
240 }
241
242 pub fn triangles(&self) -> impl Iterator<Item = Triangle> + '_ {
244 HeightFieldTriangles {
245 heightfield: self,
246 curr: (0, 0),
247 tris: self.triangles_at(0, 0),
248 }
249 }
250
251 pub fn triangles_around_point(&self, point: Vector) -> HeightFieldRadialTriangles<'_> {
253 let center = self.closest_cell_at_point(point);
254 HeightFieldRadialTriangles {
255 heightfield: self,
256 center,
257 curr_radius: 0,
258 curr_element: 0,
259 tris: self.triangles_at(center.0, center.1),
260 }
261 }
262
263 pub fn triangle_at_id(&self, id: u32) -> Option<Triangle> {
265 let (i, j, left) = self.split_triangle_id(id);
266 if left {
267 self.triangles_at(i, j).0
268 } else {
269 self.triangles_at(i, j).1
270 }
271 }
272
273 pub fn triangle_vids_at_id(&self, id: u32) -> Option<[u32; 3]> {
275 let (i, j, left) = self.split_triangle_id(id);
276 if left {
277 self.triangles_vids_at(i, j).0
278 } else {
279 self.triangles_vids_at(i, j).1
280 }
281 }
282
283 pub fn triangles_vids_at(&self, i: usize, j: usize) -> (Option<[u32; 3]>, Option<[u32; 3]>) {
285 if i >= self.heights.nrows() - 1 || j >= self.heights.ncols() - 1 {
286 return (None, None);
287 }
288
289 let status = self.status[(i, j)];
290
291 if status.contains(
292 HeightFieldCellStatus::LEFT_TRIANGLE_REMOVED
293 | HeightFieldCellStatus::RIGHT_TRIANGLE_REMOVED,
294 ) {
295 return (None, None);
296 }
297
298 let p00 = (i + j * self.heights.nrows()) as u32;
299 let p10 = ((i + 1) + j * self.heights.nrows()) as u32;
300 let p01 = (i + (j + 1) * self.heights.nrows()) as u32;
301 let p11 = ((i + 1) + (j + 1) * self.heights.nrows()) as u32;
302
303 if status.contains(HeightFieldCellStatus::ZIGZAG_SUBDIVISION) {
304 let tri1 = if status.contains(HeightFieldCellStatus::LEFT_TRIANGLE_REMOVED) {
305 None
306 } else {
307 Some([p00, p10, p11])
308 };
309
310 let tri2 = if status.contains(HeightFieldCellStatus::RIGHT_TRIANGLE_REMOVED) {
311 None
312 } else {
313 Some([p00, p11, p01])
314 };
315
316 (tri1, tri2)
317 } else {
318 let tri1 = if status.contains(HeightFieldCellStatus::LEFT_TRIANGLE_REMOVED) {
319 None
320 } else {
321 Some([p00, p10, p01])
322 };
323
324 let tri2 = if status.contains(HeightFieldCellStatus::RIGHT_TRIANGLE_REMOVED) {
325 None
326 } else {
327 Some([p10, p11, p01])
328 };
329
330 (tri1, tri2)
331 }
332 }
333
334 pub fn triangles_at(&self, i: usize, j: usize) -> (Option<Triangle>, Option<Triangle>) {
339 if i >= self.heights.nrows() - 1 || j >= self.heights.ncols() - 1 {
340 return (None, None);
341 }
342
343 let status = self.status[(i, j)];
344
345 if status.contains(
346 HeightFieldCellStatus::LEFT_TRIANGLE_REMOVED
347 | HeightFieldCellStatus::RIGHT_TRIANGLE_REMOVED,
348 ) {
349 return (None, None);
350 }
351
352 let cell_width = self.unit_cell_width();
353 let cell_height = self.unit_cell_height();
354
355 let z0 = -0.5 + cell_height * (i as Real);
356 let z1 = -0.5 + cell_height * ((i + 1) as Real);
357
358 let x0 = -0.5 + cell_width * (j as Real);
359 let x1 = -0.5 + cell_width * ((j + 1) as Real);
360
361 let y00 = self.heights[(i, j)];
362 let y10 = self.heights[(i + 1, j)];
363 let y01 = self.heights[(i, j + 1)];
364 let y11 = self.heights[(i + 1, j + 1)];
365
366 let mut p00 = Vector::new(x0, y00, z0);
367 let mut p10 = Vector::new(x0, y10, z1);
368 let mut p01 = Vector::new(x1, y01, z0);
369 let mut p11 = Vector::new(x1, y11, z1);
370
371 p00 *= self.scale;
373 p10 *= self.scale;
374 p01 *= self.scale;
375 p11 *= self.scale;
376
377 if status.contains(HeightFieldCellStatus::ZIGZAG_SUBDIVISION) {
378 let tri1 = if status.contains(HeightFieldCellStatus::LEFT_TRIANGLE_REMOVED) {
379 None
380 } else {
381 Some(Triangle::new(p00, p10, p11))
382 };
383
384 let tri2 = if status.contains(HeightFieldCellStatus::RIGHT_TRIANGLE_REMOVED) {
385 None
386 } else {
387 Some(Triangle::new(p00, p11, p01))
388 };
389
390 (tri1, tri2)
391 } else {
392 let tri1 = if status.contains(HeightFieldCellStatus::LEFT_TRIANGLE_REMOVED) {
393 None
394 } else {
395 Some(Triangle::new(p00, p10, p01))
396 };
397
398 let tri2 = if status.contains(HeightFieldCellStatus::RIGHT_TRIANGLE_REMOVED) {
399 None
400 } else {
401 Some(Triangle::new(p10, p11, p01))
402 };
403
404 (tri1, tri2)
405 }
406 }
407
408 pub fn triangle_normal_constraints(&self, id: u32) -> Option<TrianglePseudoNormals> {
415 if self.flags.contains(HeightFieldFlags::FIX_INTERNAL_EDGES) {
416 let (i, j, left) = self.split_triangle_id(id);
417 let status = self.status[(i, j)];
418
419 let (tri_left, tri_right) = self.triangles_at(i, j);
420 let tri_normal = if left {
421 tri_left?.normal()?
422 } else {
423 tri_right?.normal()?
424 };
425
426 let bivector = |v: Vector| tri_normal.cross(v).cross(tri_normal).normalize();
431 let adj_pseudo_normal =
433 |adj: Option<Triangle>| adj.map(|adj| adj.normal().unwrap_or(tri_normal));
434
435 let diag_dir = if status.contains(HeightFieldCellStatus::ZIGZAG_SUBDIVISION) {
436 Vector::new(-1.0, 0.0, 1.0)
437 } else {
438 Vector::new(1.0, 0.0, 1.0)
439 };
440
441 let (left_pseudo_normal, right_pseudo_normal) = if left {
442 let adj_left = adj_pseudo_normal(self.triangles_at(i.overflowing_sub(1).0, j).1)
443 .unwrap_or_else(|| bivector(-Vector::Z));
444 let adj_right = adj_pseudo_normal(tri_right).unwrap_or_else(|| bivector(diag_dir));
445 (adj_left, adj_right)
446 } else {
447 let adj_left = adj_pseudo_normal(tri_left).unwrap_or_else(|| bivector(-diag_dir));
448 let adj_right = adj_pseudo_normal(self.triangles_at(i + 1, j).0)
449 .unwrap_or_else(|| bivector(Vector::Z));
450 (adj_left, adj_right)
451 };
452
453 let top_or_bottom_pseudo_normal = if left
456 != status.contains(HeightFieldCellStatus::ZIGZAG_SUBDIVISION)
457 {
458 let ((bot_left, bot_right), bot_status) = if j > 0 {
460 (self.triangles_at(i, j - 1), self.status[(i, j - 1)])
461 } else {
462 ((None, None), HeightFieldCellStatus::empty())
463 };
464
465 let bot_tri = if bot_status.contains(HeightFieldCellStatus::ZIGZAG_SUBDIVISION) {
466 bot_left
467 } else {
468 bot_right
469 };
470
471 adj_pseudo_normal(bot_tri).unwrap_or_else(|| bivector(-Vector::X))
472 } else {
473 let ((top_left, top_right), top_status) = if j < self.heights.ncols() - 2 {
475 (self.triangles_at(i, j + 1), self.status[(i, j + 1)])
476 } else {
477 ((None, None), HeightFieldCellStatus::empty())
478 };
479
480 let top_tri = if top_status.contains(HeightFieldCellStatus::ZIGZAG_SUBDIVISION) {
481 top_right
482 } else {
483 top_left
484 };
485
486 adj_pseudo_normal(top_tri).unwrap_or_else(|| bivector(Vector::X))
487 };
488
489 let pseudo_normal1 = (tri_normal + left_pseudo_normal).normalize();
491 let pseudo_normal2 = (tri_normal + right_pseudo_normal).normalize();
492 let pseudo_normal3 = (tri_normal + top_or_bottom_pseudo_normal).normalize();
493
494 Some(TrianglePseudoNormals {
495 face: tri_normal, edges: [pseudo_normal1, pseudo_normal2, pseudo_normal3],
499 })
500 } else {
501 None
502 }
503 }
504
505 pub fn num_cells_ij(&self) -> (usize, usize) {
507 (self.nrows(), self.ncols())
508 }
509
510 pub fn cell_status(&self, i: usize, j: usize) -> HeightFieldCellStatus {
512 self.status[(i, j)]
513 }
514
515 pub fn set_cell_status(&mut self, i: usize, j: usize, status: HeightFieldCellStatus) {
517 self.status[(i, j)] = status;
518 }
519
520 pub fn cells_statuses(&self) -> &Array2<HeightFieldCellStatus> {
522 &self.status
523 }
524
525 pub fn cells_statuses_mut(&mut self) -> &mut Array2<HeightFieldCellStatus> {
527 &mut self.status
528 }
529
530 pub fn flags(&self) -> HeightFieldFlags {
532 self.flags
533 }
534
535 pub fn set_flags(&mut self, flags: HeightFieldFlags) {
537 self.flags = flags;
538 }
539
540 pub fn heights(&self) -> &Array2<Real> {
542 &self.heights
543 }
544
545 pub fn scale(&self) -> Vector {
547 self.scale
548 }
549
550 pub fn set_scale(&mut self, new_scale: Vector) {
552 let ratio = new_scale / self.scale;
553 self.aabb.mins *= ratio;
554 self.aabb.maxs *= ratio;
555 self.scale = new_scale;
556 }
557
558 pub fn scaled(mut self, scale: Vector) -> Self {
560 self.set_scale(self.scale * scale);
561 self
562 }
563
564 pub fn cell_width(&self) -> Real {
566 self.unit_cell_width() * self.scale.x
567 }
568
569 pub fn cell_height(&self) -> Real {
571 self.unit_cell_height() * self.scale.z
572 }
573
574 pub fn unit_cell_width(&self) -> Real {
576 1.0 / (self.heights.ncols() as Real - 1.0)
577 }
578
579 pub fn unit_cell_height(&self) -> Real {
581 1.0 / (self.heights.nrows() as Real - 1.0)
582 }
583
584 pub fn root_aabb(&self) -> &Aabb {
586 &self.aabb
587 }
588
589 pub fn convert_triangle_feature_id(
592 &self,
593 i: usize,
594 j: usize,
595 left: bool,
596 fid: FeatureId,
597 ) -> FeatureId {
598 match fid {
599 FeatureId::Vertex(ivertex) => {
600 let nrows = self.heights.nrows();
601 let ij = i + j * nrows;
602
603 if self.status[(i, j)].contains(HeightFieldCellStatus::ZIGZAG_SUBDIVISION) {
604 if left {
605 FeatureId::Vertex([ij, ij + 1, ij + 1 + nrows][ivertex as usize] as u32)
606 } else {
607 FeatureId::Vertex([ij, ij + 1 + nrows, ij + nrows][ivertex as usize] as u32)
608 }
609 } else if left {
610 FeatureId::Vertex([ij, ij + 1, ij + nrows][ivertex as usize] as u32)
611 } else {
612 FeatureId::Vertex([ij + 1, ij + 1 + nrows, ij + nrows][ivertex as usize] as u32)
613 }
614 }
615 FeatureId::Edge(iedge) => {
616 let (nrows, ncols) = (self.heights.nrows(), self.heights.ncols());
617 let vshift = 0; let hshift = (nrows - 1) * ncols; let dshift = hshift + nrows * (ncols - 1); let idiag = dshift + i + j * (nrows - 1);
621 let itop = hshift + i + j * nrows;
622 let ibottom = itop + 1;
623 let ileft = vshift + i + j * (nrows - 1);
624 let iright = ileft + nrows - 1;
625
626 if self.status[(i, j)].contains(HeightFieldCellStatus::ZIGZAG_SUBDIVISION) {
627 if left {
628 FeatureId::Edge([ileft, ibottom, idiag][iedge as usize] as u32)
634 } else {
635 FeatureId::Edge([idiag, iright, itop][iedge as usize] as u32)
641 }
642 } else if left {
643 FeatureId::Edge([ileft, idiag, itop][iedge as usize] as u32)
649 } else {
650 FeatureId::Edge([ibottom, iright, idiag][iedge as usize] as u32)
656 }
657 }
658 FeatureId::Face(iface) => {
659 if iface == 0 {
660 FeatureId::Face(self.face_id(i, j, left, true))
661 } else {
662 FeatureId::Face(self.face_id(i, j, left, false))
663 }
664 }
665 FeatureId::Unknown => FeatureId::Unknown,
666 }
667 }
668
669 pub fn unclamped_elements_range_in_local_aabb(
671 &self,
672 aabb: &Aabb,
673 ) -> (Range<isize>, Range<isize>) {
674 let ref_mins = aabb.mins / self.scale;
675 let ref_maxs = aabb.maxs / self.scale;
676 let cell_width = self.unit_cell_width();
677 let cell_height = self.unit_cell_height();
678
679 let min_x = self.quantize_floor_unclamped(ref_mins.x, cell_width);
680 let min_z = self.quantize_floor_unclamped(ref_mins.z, cell_height);
681
682 let max_x = self.quantize_ceil_unclamped(ref_maxs.x, cell_width);
683 let max_z = self.quantize_ceil_unclamped(ref_maxs.z, cell_height);
684 (min_z..max_z, min_x..max_x)
685 }
686
687 pub fn map_elements_in_local_aabb(&self, aabb: &Aabb, f: &mut impl FnMut(u32, &Triangle)) {
689 let ncells_x = self.ncols();
690 let ncells_z = self.nrows();
691
692 let ref_mins = aabb.mins / self.scale;
693 let ref_maxs = aabb.maxs / self.scale;
694 let cell_width = self.unit_cell_width();
695 let cell_height = self.unit_cell_height();
696
697 if ref_maxs.x <= -0.5 || ref_maxs.z <= -0.5 || ref_mins.x >= 0.5 || ref_mins.z >= 0.5 {
698 return;
700 }
701
702 let min_x = self.quantize_floor(ref_mins.x, cell_width, ncells_x);
703 let min_z = self.quantize_floor(ref_mins.z, cell_height, ncells_z);
704
705 let max_x = self.quantize_ceil(ref_maxs.x, cell_width, ncells_x);
706 let max_z = self.quantize_ceil(ref_maxs.z, cell_height, ncells_z);
707
708 for j in min_x..max_x {
711 for i in min_z..max_z {
712 let status = self.status[(i, j)];
713
714 if status.contains(HeightFieldCellStatus::CELL_REMOVED) {
715 continue;
716 }
717
718 let z0 = -0.5 + cell_height * (i as Real);
719 let z1 = z0 + cell_height;
720
721 let x0 = -0.5 + cell_width * (j as Real);
722 let x1 = x0 + cell_width;
723
724 let y00 = self.heights[(i, j)];
725 let y10 = self.heights[(i + 1, j)];
726 let y01 = self.heights[(i, j + 1)];
727 let y11 = self.heights[(i + 1, j + 1)];
728
729 if (y00 > ref_maxs.y && y10 > ref_maxs.y && y01 > ref_maxs.y && y11 > ref_maxs.y)
730 || (y00 < ref_mins.y
731 && y10 < ref_mins.y
732 && y01 < ref_mins.y
733 && y11 < ref_mins.y)
734 {
735 continue;
736 }
737
738 let mut p00 = Vector::new(x0, y00, z0);
739 let mut p10 = Vector::new(x0, y10, z1);
740 let mut p01 = Vector::new(x1, y01, z0);
741 let mut p11 = Vector::new(x1, y11, z1);
742
743 p00 *= self.scale;
745 p10 *= self.scale;
746 p01 *= self.scale;
747 p11 *= self.scale;
748
749 if !status.contains(HeightFieldCellStatus::LEFT_TRIANGLE_REMOVED) {
751 let tri1 = if status.contains(HeightFieldCellStatus::ZIGZAG_SUBDIVISION) {
752 Triangle::new(p00, p10, p11)
753 } else {
754 Triangle::new(p00, p10, p01)
755 };
756
757 let tid = self.triangle_id(i, j, true);
758 f(tid, &tri1);
759 }
760
761 if !status.contains(HeightFieldCellStatus::RIGHT_TRIANGLE_REMOVED) {
762 let tri2 = if status.contains(HeightFieldCellStatus::ZIGZAG_SUBDIVISION) {
763 Triangle::new(p00, p11, p01)
764 } else {
765 Triangle::new(p10, p11, p01)
766 };
767 let tid = self.triangle_id(i, j, false);
768 f(tid, &tri2);
769 }
770 }
771 }
772 }
773}
774
775struct HeightFieldTriangles<'a> {
776 heightfield: &'a HeightField,
777 curr: (usize, usize),
778 tris: (Option<Triangle>, Option<Triangle>),
779}
780
781impl Iterator for HeightFieldTriangles<'_> {
782 type Item = Triangle;
783
784 fn next(&mut self) -> Option<Triangle> {
785 loop {
786 if let Some(tri1) = self.tris.0.take() {
787 return Some(tri1);
788 } else if let Some(tri2) = self.tris.1.take() {
789 return Some(tri2);
790 } else {
791 self.curr.0 += 1;
792
793 if self.curr.0 >= self.heightfield.nrows() {
794 if self.curr.1 >= self.heightfield.ncols() - 1 {
795 return None;
796 }
797
798 self.curr.0 = 0;
799 self.curr.1 += 1;
800 }
801
802 self.tris = self.heightfield.triangles_at(self.curr.0, self.curr.1);
804 }
805 }
806 }
807}
808
809pub struct HeightFieldRadialTriangles<'a> {
811 heightfield: &'a HeightField,
812 center: (usize, usize),
813 curr_radius: usize,
814 curr_element: usize,
815 tris: (Option<Triangle>, Option<Triangle>),
816}
817
818impl HeightFieldRadialTriangles<'_> {
819 pub fn next(&mut self, max_dist: Real) -> Option<Triangle> {
825 let max_rad = if max_dist == Real::MAX {
826 usize::MAX
827 } else {
828 (max_dist / self.heightfield.cell_width())
829 .ceil()
830 .max((max_dist / self.heightfield.cell_height()).ceil()) as usize
831 };
832
833 loop {
834 if let Some(tri1) = self.tris.0.take() {
835 return Some(tri1);
836 } else if let Some(tri2) = self.tris.1.take() {
837 return Some(tri2);
838 } else {
839 let mut curr_cell = (0, 0);
840
841 loop {
842 self.curr_element += 1;
843
844 if self.curr_element >= 8 * self.curr_radius {
845 if self.curr_radius >= max_rad {
846 return None;
847 }
848
849 self.curr_element = 0;
850 self.curr_radius += 1;
851 }
852
853 let side_max_index = self.curr_radius + self.curr_radius;
854 let curr_index_in_side = self.curr_element % side_max_index;
855 let curr_side = self.curr_element / side_max_index;
856
857 let mins = (
858 self.center.0 as isize - self.curr_radius as isize,
859 self.center.1 as isize - self.curr_radius as isize,
860 );
861 let maxs = (
862 self.center.0 as isize + self.curr_radius as isize,
863 self.center.1 as isize + self.curr_radius as isize,
864 );
865
866 if curr_cell.0 < 0
867 && curr_cell.1 < 0
868 && (curr_cell.0 as usize) >= self.heightfield.nrows()
869 && (curr_cell.1 as usize) >= self.heightfield.ncols()
870 {
871 return None;
873 }
874
875 let side_origins = [
876 (mins.0, mins.1),
877 (maxs.0, mins.1),
878 (maxs.0, maxs.1),
879 (mins.0, maxs.1),
880 ];
881 let side_directions = [(1, 0), (0, 1), (-1, 0), (0, -1)];
882
883 curr_cell = (
884 side_origins[curr_side].0
885 + side_directions[curr_side].0 * (curr_index_in_side as isize),
886 side_origins[curr_side].1
887 + side_directions[curr_side].1 * (curr_index_in_side as isize),
888 );
889
890 if curr_cell.0 >= 0
891 && curr_cell.1 >= 0
892 && (curr_cell.0 as usize) < self.heightfield.nrows()
893 && (curr_cell.1 as usize) < self.heightfield.ncols()
894 {
895 break;
896 }
897 }
898
899 self.tris = self
900 .heightfield
901 .triangles_at(curr_cell.0 as usize, curr_cell.1 as usize);
902 }
903 }
904 }
905}