Skip to main content

oxiphysics_geometry/heightfield/
heightfield_traits.rs

1//! # HeightField - Trait Implementations
2//!
3//! This module contains trait implementations for `HeightField`.
4//!
5//! ## Implemented Traits
6//!
7//! - `Shape`
8//!
9//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
10
11use 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}