parry2d/shape/
heightfield2.rs1use core::ops::Range;
2#[cfg(not(feature = "std"))]
3use na::ComplexField;
4#[cfg(feature = "alloc")]
5use na::DVector;
6
7use na::Point2;
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: DVector<Real>,
30 status: DVector<HeightFieldCellStatus>,
31
32 scale: Vector<Real>,
33 aabb: Aabb,
34}
35
36#[cfg(feature = "alloc")]
37impl HeightField {
38 pub fn new(heights: DVector<Real>, scale: Vector<Real>) -> Self {
40 assert!(
41 heights.len() > 1,
42 "A heightfield heights must have at least 2 elements."
43 );
44
45 let max = heights.max();
46 let min = heights.min();
47 let hscale = scale * 0.5;
48 let aabb = Aabb::new(
49 Point2::new(-hscale.x, min * scale.y),
50 Point2::new(hscale.x, max * scale.y),
51 );
52 let num_segments = heights.len() - 1;
53
54 HeightField {
55 heights,
56 status: DVector::repeat(num_segments, true),
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) -> &DVector<Real> {
71 &self.heights
72 }
73
74 pub fn scale(&self) -> &Vector<Real> {
76 &self.scale
77 }
78
79 pub fn set_scale(&mut self, new_scale: Vector<Real>) {
81 let ratio = new_scale.component_div(&self.scale);
82 self.aabb.mins.coords.component_mul_assign(&ratio);
83 self.aabb.maxs.coords.component_mul_assign(&ratio);
84 self.scale = new_scale;
85 }
86
87 pub fn scaled(mut self, scale: &Vector<Real>) -> Self {
89 self.set_scale(self.scale.component_mul(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 na::clamp(
123 ((val + 0.5) / seg_length).floor(),
124 0.0,
125 (self.num_cells() - 1) as Real,
126 ) as usize
127 }
128
129 fn quantize_ceil(&self, val: Real, seg_length: Real) -> usize {
130 na::clamp(
131 ((val + 0.5) / seg_length).ceil(),
132 0.0,
133 self.num_cells() as Real,
134 ) as usize
135 }
136
137 pub fn cell_at_point(&self, pt: &Point2<Real>) -> Option<usize> {
139 let scaled_pt = pt.coords.component_div(&self.scale);
140 let seg_length = self.unit_cell_width();
141
142 if scaled_pt.x < -0.5 || scaled_pt.x > 0.5 {
143 None
145 } else {
146 Some(self.quantize_floor(scaled_pt.x, seg_length))
147 }
148 }
149
150 pub fn height_at_point(&self, pt: &Point2<Real>) -> Option<Real> {
152 let cell = self.cell_at_point(pt)?;
153 let seg = self.segment_at(cell)?;
154 let inter = crate::query::details::closest_points_line_line_parameters(
155 &seg.a,
156 &seg.scaled_direction(),
157 pt,
158 &Vector::y(),
159 );
160 Some(seg.a.y + inter.1)
161 }
162
163 pub fn segments(&self) -> impl Iterator<Item = Segment> + '_ {
165 (0..self.num_cells()).filter_map(move |i| self.segment_at(i))
168 }
169
170 pub fn segment_at(&self, i: usize) -> Option<Segment> {
172 if i >= self.num_cells() || self.is_segment_removed(i) {
173 return None;
174 }
175
176 let seg_length = 1.0 / (self.heights.len() as Real - 1.0);
177
178 let x0 = -0.5 + seg_length * (i as Real);
179 let x1 = x0 + seg_length;
180
181 let y0 = self.heights[i];
182 let y1 = self.heights[i + 1];
183
184 let mut p0 = Point2::new(x0, y0);
185 let mut p1 = Point2::new(x1, y1);
186
187 p0.coords.component_mul_assign(&self.scale);
189 p1.coords.component_mul_assign(&self.scale);
190
191 Some(Segment::new(p0, p1))
192 }
193
194 pub fn set_segment_removed(&mut self, i: usize, removed: bool) {
196 self.status[i] = !removed
197 }
198
199 pub fn is_segment_removed(&self, i: usize) -> bool {
201 !self.status[i]
202 }
203
204 pub fn unclamped_elements_range_in_local_aabb(&self, aabb: &Aabb) -> Range<isize> {
206 let ref_mins = aabb.mins.coords.component_div(&self.scale);
207 let ref_maxs = aabb.maxs.coords.component_div(&self.scale);
208 let seg_length = 1.0 / (self.heights.len() as Real - 1.0);
209
210 let min_x = self.quantize_floor_unclamped(ref_mins.x, seg_length);
211 let max_x = self.quantize_ceil_unclamped(ref_maxs.x, seg_length);
212 min_x..max_x
213 }
214
215 pub fn map_elements_in_local_aabb(&self, aabb: &Aabb, f: &mut impl FnMut(u32, &Segment)) {
217 let ref_mins = aabb.mins.coords.component_div(&self.scale);
218 let ref_maxs = aabb.maxs.coords.component_div(&self.scale);
219 let seg_length = 1.0 / (self.heights.len() as Real - 1.0);
220
221 if ref_maxs.x < -0.5 || ref_mins.x > 0.5 {
222 return;
224 }
225
226 let min_x = self.quantize_floor(ref_mins.x, seg_length);
227 let max_x = self.quantize_ceil(ref_maxs.x, seg_length);
228
229 for i in min_x..max_x {
232 if self.is_segment_removed(i) {
233 continue;
234 }
235
236 let x0 = -0.5 + seg_length * (i as Real);
237 let x1 = x0 + seg_length;
238
239 let y0 = self.heights[i];
240 let y1 = self.heights[i + 1];
241
242 if (y0 > ref_maxs.y && y1 > ref_maxs.y) || (y0 < ref_mins.y && y1 < ref_mins.y) {
243 continue;
244 }
245
246 let mut p0 = Point2::new(x0, y0);
247 let mut p1 = Point2::new(x1, y1);
248
249 p0.coords.component_mul_assign(&self.scale);
251 p1.coords.component_mul_assign(&self.scale);
252
253 let seg = Segment::new(p0, p1);
255
256 f(i as u32, &seg);
258 }
259 }
260}