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