oxiphysics_geometry/heightfield/
heightfield_traits.rs1use crate::shape::{RayHit, Shape};
12use oxiphysics_core::Aabb;
13use oxiphysics_core::math::{Mat3, Real, Vec3};
14
15use super::functions::ray_triangle;
16#[allow(unused_imports)]
17use super::functions::*;
18use super::types::HeightField;
19
20impl Shape for HeightField {
21 fn bounding_box(&self) -> Aabb {
22 let (min_h, max_h) = self.height_bounds();
23 Aabb::new(
24 Vec3::new(0.0, min_h, 0.0),
25 Vec3::new(
26 self.scale_x * (self.cols - 1) as Real,
27 max_h,
28 self.scale_z * (self.rows - 1) as Real,
29 ),
30 )
31 }
32 fn support_point(&self, direction: &Vec3) -> Vec3 {
33 let mut best_dot = Real::NEG_INFINITY;
34 let mut best_point = Vec3::zeros();
35 for row in 0..self.rows {
36 for col in 0..self.cols {
37 let p = Vec3::new(
38 col as Real * self.scale_x,
39 self.height_at(row, col),
40 row as Real * self.scale_z,
41 );
42 let d = p.dot(direction);
43 if d > best_dot {
44 best_dot = d;
45 best_point = p;
46 }
47 }
48 }
49 best_point
50 }
51 fn volume(&self) -> Real {
52 if self.rows < 2 || self.cols < 2 {
53 return 0.0;
54 }
55 let cell_area = self.scale_x * self.scale_z;
56 let mut total = 0.0;
57 for row in 0..(self.rows - 1) {
58 for col in 0..(self.cols - 1) {
59 let h00 = self.height_at(row, col);
60 let h10 = self.height_at(row + 1, col);
61 let h01 = self.height_at(row, col + 1);
62 let h11 = self.height_at(row + 1, col + 1);
63 let avg_h = (h00 + h10 + h01 + h11) / 4.0;
64 total += avg_h * cell_area;
65 }
66 }
67 total
68 }
69 fn center_of_mass(&self) -> Vec3 {
70 Vec3::zeros()
71 }
72 fn inertia_tensor(&self, _mass: Real) -> Mat3 {
73 Mat3::zeros()
74 }
75 fn ray_cast(&self, ray_origin: &Vec3, ray_direction: &Vec3, max_toi: Real) -> Option<RayHit> {
76 let mut best: Option<RayHit> = None;
77 for row in 0..(self.rows.saturating_sub(1)) {
78 for col in 0..(self.cols.saturating_sub(1)) {
79 let x0 = col as Real * self.scale_x;
80 let x1 = (col + 1) as Real * self.scale_x;
81 let z0 = row as Real * self.scale_z;
82 let z1 = (row + 1) as Real * self.scale_z;
83 let v00 = Vec3::new(x0, self.height_at(row, col), z0);
84 let v10 = Vec3::new(x0, self.height_at(row + 1, col), z1);
85 let v01 = Vec3::new(x1, self.height_at(row, col + 1), z0);
86 let v11 = Vec3::new(x1, self.height_at(row + 1, col + 1), z1);
87 for tri in [&[v00, v01, v11], &[v00, v11, v10]] {
88 if let Some(hit) = ray_triangle(
89 ray_origin,
90 ray_direction,
91 max_toi,
92 &tri[0],
93 &tri[1],
94 &tri[2],
95 ) && best.as_ref().is_none_or(|b| hit.toi < b.toi)
96 {
97 best = Some(hit);
98 }
99 }
100 }
101 }
102 best
103 }
104}