use na::{DVector, Point2, RealField};
use std::iter;
use crate::bounding_volume::AABB;
use crate::math::Vector;
use crate::query::{Contact, ContactKinematic, ContactPreprocessor};
use crate::shape::Segment;
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug)]
pub struct HeightField<N: RealField + Copy> {
heights: DVector<N>,
scale: Vector<N>,
removed: Vec<bool>,
aabb: AABB<N>,
}
impl<N: RealField + Copy> HeightField<N> {
pub fn new(heights: DVector<N>, scale: Vector<N>) -> Self {
assert!(
heights.len() > 1,
"A heightfield heights must have at least 2 elements."
);
let max = heights.max();
let min = heights.min();
let hscale = scale * na::convert::<_, N>(0.5);
let aabb = AABB::new(
Point2::new(-hscale.x, min * scale.y),
Point2::new(hscale.x, max * scale.y),
);
HeightField {
heights,
scale,
aabb,
removed: Vec::new(),
}
}
pub fn num_cells(&self) -> usize {
self.heights.len() - 1
}
pub fn heights(&self) -> &DVector<N> {
&self.heights
}
pub fn scale(&self) -> &Vector<N> {
&self.scale
}
pub fn aabb(&self) -> &AABB<N> {
&self.aabb
}
pub fn cell_width(&self) -> N {
self.unit_cell_width() * self.scale.x
}
pub fn unit_cell_width(&self) -> N {
N::one() / na::convert(self.heights.len() as f64 - 1.0)
}
pub fn start_x(&self) -> N {
self.scale.x * na::convert(-0.5)
}
fn quantize_floor(&self, val: N, seg_length: N) -> usize {
let _0_5: N = na::convert(0.5);
let i = na::clamp(
((val + _0_5) / seg_length).floor(),
N::zero(),
na::convert((self.num_cells() - 1) as f64),
);
na::convert_unchecked::<N, f64>(i) as usize
}
fn quantize_ceil(&self, val: N, seg_length: N) -> usize {
let _0_5: N = na::convert(0.5);
let i = na::clamp(
((val + _0_5) / seg_length).ceil(),
N::zero(),
na::convert(self.num_cells() as f64),
);
na::convert_unchecked::<N, f64>(i) as usize
}
pub fn cell_at_point(&self, pt: &Point2<N>) -> Option<usize> {
let _0_5: N = na::convert(0.5);
let scaled_pt = pt.coords.component_div(&self.scale);
let seg_length = self.unit_cell_width();
if scaled_pt.x < -_0_5 || scaled_pt.x > _0_5 {
None
} else {
Some(self.quantize_floor(scaled_pt.x, seg_length))
}
}
pub fn segments<'a>(&'a self) -> impl Iterator<Item = Segment<N>> + 'a {
(0..self.num_cells()).filter_map(move |i| self.segment_at(i))
}
pub fn segment_at(&self, i: usize) -> Option<Segment<N>> {
if i >= self.num_cells() || self.is_segment_removed(i) {
return None;
}
let _0_5: N = na::convert(0.5);
let seg_length = N::one() / na::convert(self.heights.len() as f64 - 1.0);
let x0 = -_0_5 + seg_length * na::convert(i as f64);
let x1 = x0 + seg_length;
let y0 = self.heights[i + 0];
let y1 = self.heights[i + 1];
let mut p0 = Point2::new(x0, y0);
let mut p1 = Point2::new(x1, y1);
p0.coords.component_mul_assign(&self.scale);
p1.coords.component_mul_assign(&self.scale);
Some(Segment::new(p0, p1))
}
pub fn set_segment_removed(&mut self, i: usize, removed: bool) {
if self.removed.len() == 0 {
self.removed = iter::repeat(false).take(self.num_cells()).collect()
}
self.removed[i] = removed
}
pub fn is_segment_removed(&self, i: usize) -> bool {
self.removed.len() != 0 && self.removed[i]
}
pub fn map_elements_in_local_aabb(
&self,
aabb: &AABB<N>,
f: &mut impl FnMut(usize, &Segment<N>, &dyn ContactPreprocessor<N>),
) {
let _0_5: N = na::convert(0.5);
let ref_mins = aabb.mins.coords.component_div(&self.scale);
let ref_maxs = aabb.maxs.coords.component_div(&self.scale);
let seg_length = N::one() / na::convert(self.heights.len() as f64 - 1.0);
if ref_maxs.x < -_0_5 || ref_mins.x > _0_5 {
return;
}
let min_x = self.quantize_floor(ref_mins.x, seg_length);
let max_x = self.quantize_ceil(ref_maxs.x, seg_length);
for i in min_x..max_x {
if self.is_segment_removed(i) {
continue;
}
let x0 = -_0_5 + seg_length * na::convert(i as f64);
let x1 = x0 + seg_length;
let y0 = self.heights[i + 0];
let y1 = self.heights[i + 1];
if (y0 > ref_maxs.y && y1 > ref_maxs.y) || (y0 < ref_mins.y && y1 < ref_mins.y) {
continue;
}
let mut p0 = Point2::new(x0, y0);
let mut p1 = Point2::new(x1, y1);
p0.coords.component_mul_assign(&self.scale);
p1.coords.component_mul_assign(&self.scale);
let seg = Segment::new(p0, p1);
let seg_id = i;
let proc = HeightFieldTriangleContactPreprocessor::new(self, seg_id);
f(seg_id, &seg, &proc);
}
}
}
#[allow(dead_code)]
pub struct HeightFieldTriangleContactPreprocessor<'a, N: RealField + Copy> {
heightfield: &'a HeightField<N>,
triangle: usize,
}
impl<'a, N: RealField + Copy> HeightFieldTriangleContactPreprocessor<'a, N> {
pub fn new(heightfield: &'a HeightField<N>, triangle: usize) -> Self {
HeightFieldTriangleContactPreprocessor {
heightfield,
triangle,
}
}
}
impl<'a, N: RealField + Copy> ContactPreprocessor<N>
for HeightFieldTriangleContactPreprocessor<'a, N>
{
fn process_contact(
&self,
_c: &mut Contact<N>,
_kinematic: &mut ContactKinematic<N>,
_is_first: bool,
) -> bool {
true
}
}