parry2d/shape/
heightfield2.rs1#[cfg(not(feature = "std"))]
2use crate::math::ComplexField;
3#[cfg(feature = "alloc")]
4use alloc::{vec, vec::Vec};
5use core::ops::Range;
6
7use crate::math::Vector2;
8
9use crate::bounding_volume::Aabb;
10use crate::math::{Real, Vector};
11
12use crate::shape::Segment;
13
14pub type HeightFieldCellStatus = bool;
17
18#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
19#[derive(Debug, Clone)]
26#[repr(C)]
27pub struct HeightField {
29 heights: Vec<Real>,
30 status: Vec<HeightFieldCellStatus>,
31
32 scale: Vector,
33 aabb: Aabb,
34}
35
36#[cfg(feature = "alloc")]
37impl HeightField {
38 pub fn new(heights: Vec<Real>, scale: Vector) -> Self {
40 assert!(
41 heights.len() > 1,
42 "A heightfield heights must have at least 2 elements."
43 );
44
45 let max = heights.iter().fold(Real::MIN, |a, b| a.max(*b));
46 let min = heights.iter().fold(Real::MAX, |a, b| a.min(*b));
47 let hscale = scale * 0.5;
48 let aabb = Aabb::new(
49 Vector2::new(-hscale.x, min * scale.y),
50 Vector2::new(hscale.x, max * scale.y),
51 );
52 let num_segments = heights.len() - 1;
53
54 HeightField {
55 heights,
56 status: vec![true; num_segments],
57 scale,
58 aabb,
59 }
60 }
61}
62
63impl HeightField {
64 pub fn num_cells(&self) -> usize {
66 self.heights.len() - 1
67 }
68
69 pub fn heights(&self) -> &Vec<Real> {
71 &self.heights
72 }
73
74 pub fn scale(&self) -> Vector {
76 self.scale
77 }
78
79 pub fn set_scale(&mut self, new_scale: Vector) {
81 let ratio = new_scale / self.scale;
82 self.aabb.mins *= ratio;
83 self.aabb.maxs *= ratio;
84 self.scale = new_scale;
85 }
86
87 pub fn scaled(mut self, scale: Vector) -> Self {
89 self.set_scale(self.scale * scale);
90 self
91 }
92
93 pub fn root_aabb(&self) -> &Aabb {
95 &self.aabb
96 }
97
98 pub fn cell_width(&self) -> Real {
100 self.unit_cell_width() * self.scale.x
101 }
102
103 pub fn unit_cell_width(&self) -> Real {
105 1.0 / (self.heights.len() as Real - 1.0)
106 }
107
108 pub fn start_x(&self) -> Real {
110 self.scale.x * -0.5
111 }
112
113 fn quantize_floor_unclamped(&self, val: Real, seg_length: Real) -> isize {
114 ((val + 0.5) / seg_length).floor() as isize
115 }
116
117 fn quantize_ceil_unclamped(&self, val: Real, seg_length: Real) -> isize {
118 ((val + 0.5) / seg_length).ceil() as isize
119 }
120
121 fn quantize_floor(&self, val: Real, seg_length: Real) -> usize {
122 ((val + 0.5) / seg_length)
123 .floor()
124 .clamp(0.0, (self.num_cells() - 1) as Real) as usize
125 }
126
127 fn quantize_ceil(&self, val: Real, seg_length: Real) -> usize {
128 ((val + 0.5) / seg_length)
129 .ceil()
130 .clamp(0.0, self.num_cells() as Real) as usize
131 }
132
133 pub fn cell_at_point(&self, pt: Vector2) -> Option<usize> {
135 let scaled_pt = pt / self.scale;
136 let seg_length = self.unit_cell_width();
137
138 if scaled_pt.x < -0.5 || scaled_pt.x > 0.5 {
139 None
141 } else {
142 Some(self.quantize_floor(scaled_pt.x, seg_length))
143 }
144 }
145
146 pub fn height_at_point(&self, pt: Vector2) -> Option<Real> {
148 let cell = self.cell_at_point(pt)?;
149 let seg = self.segment_at(cell)?;
150 let inter = crate::query::details::closest_points_line_line_parameters(
151 seg.a,
152 seg.scaled_direction(),
153 pt,
154 Vector::Y,
155 );
156 Some(seg.a.y + inter.1)
157 }
158
159 pub fn segments(&self) -> impl Iterator<Item = Segment> + '_ {
161 (0..self.num_cells()).filter_map(move |i| self.segment_at(i))
164 }
165
166 pub fn segment_at(&self, i: usize) -> Option<Segment> {
168 if i >= self.num_cells() || self.is_segment_removed(i) {
169 return None;
170 }
171
172 let seg_length = 1.0 / (self.heights.len() as Real - 1.0);
173
174 let x0 = -0.5 + seg_length * (i as Real);
175 let x1 = x0 + seg_length;
176
177 let y0 = self.heights[i];
178 let y1 = self.heights[i + 1];
179
180 let mut p0 = Vector2::new(x0, y0);
181 let mut p1 = Vector2::new(x1, y1);
182
183 p0 *= self.scale;
185 p1 *= self.scale;
186
187 Some(Segment::new(p0, p1))
188 }
189
190 pub fn set_segment_removed(&mut self, i: usize, removed: bool) {
192 self.status[i] = !removed
193 }
194
195 pub fn is_segment_removed(&self, i: usize) -> bool {
197 !self.status[i]
198 }
199
200 pub fn unclamped_elements_range_in_local_aabb(&self, aabb: &Aabb) -> Range<isize> {
202 let ref_mins = aabb.mins / self.scale;
203 let ref_maxs = aabb.maxs / self.scale;
204 let seg_length = 1.0 / (self.heights.len() as Real - 1.0);
205
206 let min_x = self.quantize_floor_unclamped(ref_mins.x, seg_length);
207 let max_x = self.quantize_ceil_unclamped(ref_maxs.x, seg_length);
208 min_x..max_x
209 }
210
211 pub fn map_elements_in_local_aabb(&self, aabb: &Aabb, f: &mut impl FnMut(u32, &Segment)) {
213 let ref_mins = aabb.mins / self.scale;
214 let ref_maxs = aabb.maxs / self.scale;
215 let seg_length = 1.0 / (self.heights.len() as Real - 1.0);
216
217 if ref_maxs.x < -0.5 || ref_mins.x > 0.5 {
218 return;
220 }
221
222 let min_x = self.quantize_floor(ref_mins.x, seg_length);
223 let max_x = self.quantize_ceil(ref_maxs.x, seg_length);
224
225 for i in min_x..max_x {
228 if self.is_segment_removed(i) {
229 continue;
230 }
231
232 let x0 = -0.5 + seg_length * (i as Real);
233 let x1 = x0 + seg_length;
234
235 let y0 = self.heights[i];
236 let y1 = self.heights[i + 1];
237
238 if (y0 > ref_maxs.y && y1 > ref_maxs.y) || (y0 < ref_mins.y && y1 < ref_mins.y) {
239 continue;
240 }
241
242 let mut p0 = Vector2::new(x0, y0);
243 let mut p1 = Vector2::new(x1, y1);
244
245 p0 *= self.scale;
247 p1 *= self.scale;
248
249 let seg = Segment::new(p0, p1);
251
252 f(i as u32, &seg);
254 }
255 }
256}