1use nalgebra::SVector;
2
3use crate::IsPoint;
4
5#[derive(Debug, Copy, Clone, PartialEq)]
7pub struct Interval {
8 pub min_max: Option<(f64, f64)>,
10}
11
12#[derive(Debug, Copy, Clone, PartialEq)]
14pub struct IInterval {
15 pub min_max: Option<(i64, i64)>,
17}
18
19#[derive(Debug, Copy, Clone, PartialEq)]
21pub struct Region<const D: usize> {
22 pub min_max: Option<(SVector<f64, D>, SVector<f64, D>)>,
24}
25
26#[derive(Debug, Copy, Clone, PartialEq)]
28pub struct IRegion<const D: usize> {
29 pub min_max: Option<(SVector<i64, D>, SVector<i64, D>)>,
31}
32
33impl<const D: usize> IRegion<D> {
34 pub fn to_region(&self) -> Region<D> {
36 if self.is_empty() {
37 return Region::empty();
38 }
39 Region::from_min_max(
41 self.min().cast() - SVector::repeat(0.5),
42 self.max().cast() + SVector::repeat(0.5),
43 )
44 }
45}
46
47pub trait IsRegion<const D: usize, P: IsPoint<D>>: core::marker::Sized {
49 fn unbounded() -> Self;
51
52 fn empty() -> Self;
54
55 fn from_min_max(min: P, max: P) -> Self;
57
58 fn from_point(point: P) -> Self {
60 Self::from_min_max(point, point)
61 }
62
63 fn is_empty(&self) -> bool;
65
66 fn is_degenerated(&self) -> bool;
70
71 fn is_proper(&self) -> bool {
75 !self.is_empty() && !self.is_degenerated()
76 }
77
78 fn is_unbounded(&self) -> bool;
80
81 fn extend(&mut self, point: &P);
83
84 fn min(&self) -> P {
88 self.try_min().unwrap()
89 }
90
91 fn max(&self) -> P {
95 self.try_max().unwrap()
96 }
97
98 fn try_min(&self) -> Option<P>;
100
101 fn try_max(&self) -> Option<P>;
103
104 fn clamp(&self, p: P) -> P;
106
107 fn intersect(self, other: Self) -> Self {
109 if other.is_empty() {
110 return other;
111 }
112 if self.is_empty() {
113 return self;
114 }
115
116 Self::from_min_max(self.clamp(other.min()), self.clamp(other.max()))
117 }
118
119 fn contains(&self, p: P) -> bool {
121 if self.is_empty() {
122 return false;
123 }
124 self.min().is_less_equal(self.min()) && p.is_less_equal(self.max())
125 }
126
127 fn range(&self) -> P;
129
130 fn mid(&self) -> P;
132}
133
134impl IsRegion<1, f64> for Interval {
135 fn unbounded() -> Self {
136 Self {
137 min_max: Option::Some((f64::NEG_INFINITY, f64::INFINITY)),
138 }
139 }
140
141 fn empty() -> Self {
142 Self {
143 min_max: Option::None,
144 }
145 }
146
147 fn from_min_max(min: f64, max: f64) -> Self {
148 Self {
149 min_max: Option::Some((min, max)),
150 }
151 }
152
153 fn is_empty(&self) -> bool {
154 self.min_max.is_none()
155 }
156
157 fn is_degenerated(&self) -> bool {
158 if self.is_empty() {
159 return false;
160 }
161 self.min() == self.max()
162 }
163
164 fn is_unbounded(&self) -> bool {
165 if self.is_empty() {
166 return false;
167 }
168 self.min() == f64::NEG_INFINITY && self.max() == f64::INFINITY
169 }
170
171 fn extend(&mut self, point: &f64) {
172 if self.is_empty() {
173 *self = Self::from_point(*point);
174 }
175 let (min, max) = (self.min().min(*point), self.max().max(*point));
176
177 *self = Self::from_min_max(min, max)
178 }
179
180 fn try_min(&self) -> Option<f64> {
181 Some(self.min_max?.0)
182 }
183
184 fn try_max(&self) -> Option<f64> {
185 Some(self.min_max?.1)
186 }
187
188 fn clamp(&self, p: f64) -> f64 {
189 p.clamp(self.min(), self.max())
190 }
191
192 fn range(&self) -> f64 {
193 if self.is_empty() {
194 return 0.0;
195 }
196 self.max() - self.min()
197 }
198
199 fn mid(&self) -> f64 {
200 self.min() + 0.5 * self.range()
201 }
202}
203
204impl<const D: usize> IsRegion<D, SVector<f64, D>> for Region<D> {
205 fn unbounded() -> Self {
206 let s: SVector<f64, D> = SVector::<f64, D>::smallest();
207 let l: SVector<f64, D> = SVector::<f64, D>::largest();
208 Self::from_min_max(s, l)
209 }
210
211 fn empty() -> Self {
212 Self {
213 min_max: Option::default(),
214 }
215 }
216
217 fn is_empty(&self) -> bool {
218 self.min_max.is_none()
219 }
220
221 fn is_degenerated(&self) -> bool {
222 if self.is_empty() {
223 return false;
224 }
225 self.min() == self.max()
226 }
227
228 fn is_unbounded(&self) -> bool {
229 if self.is_empty() {
230 return false;
231 }
232 self.min() == SVector::<f64, D>::smallest() && self.max() == SVector::<f64, D>::largest()
233 }
234
235 fn from_min_max(min: SVector<f64, D>, max: SVector<f64, D>) -> Self {
236 Self {
237 min_max: Option::Some((min, max)),
238 }
239 }
240
241 fn try_min(&self) -> Option<SVector<f64, D>> {
242 Some(self.min_max?.0)
243 }
244 fn try_max(&self) -> Option<SVector<f64, D>> {
245 Some(self.min_max?.1)
246 }
247
248 fn clamp(&self, p: SVector<f64, D>) -> SVector<f64, D> {
249 p.clamp(self.min(), self.max())
250 }
251
252 fn range(&self) -> SVector<f64, D> {
253 let p: SVector<f64, D>;
254 if self.is_empty() {
255 p = SVector::<f64, D>::zeros();
256 return p;
257 }
258 p = self.max() - self.min();
259 p
260 }
261
262 fn mid(&self) -> SVector<f64, D> {
263 self.min() + 0.5 * self.range()
264 }
265
266 fn extend(&mut self, point: &SVector<f64, D>) {
267 if self.is_empty() {
268 *self = Self::from_point(*point);
269 }
270 let (min, max) = self.min().inf_sup(point);
271
272 *self = Self::from_min_max(min, max)
273 }
274}
275
276impl IsRegion<1, i64> for IInterval {
277 fn unbounded() -> Self {
278 Self {
279 min_max: Option::Some((i64::MIN, i64::MAX)),
280 }
281 }
282
283 fn empty() -> Self {
284 Self {
285 min_max: Option::None,
286 }
287 }
288
289 fn from_min_max(min: i64, max: i64) -> Self {
290 Self {
291 min_max: Option::Some((min, max)),
292 }
293 }
294
295 fn is_empty(&self) -> bool {
296 self.min_max.is_none()
297 }
298
299 fn is_degenerated(&self) -> bool {
300 false
301 }
302
303 fn is_unbounded(&self) -> bool {
304 if self.is_empty() {
305 return false;
306 }
307 self.min() == i64::MIN && self.max() == i64::MAX
308 }
309
310 fn extend(&mut self, point: &i64) {
311 if self.is_empty() {
312 *self = Self::from_point(*point);
313 }
314 let (min, max) = (self.min().min(*point), self.max().max(*point));
315
316 *self = Self::from_min_max(min, max)
317 }
318
319 fn try_min(&self) -> Option<i64> {
320 Some(self.min_max?.0)
321 }
322
323 fn try_max(&self) -> Option<i64> {
324 Some(self.min_max?.1)
325 }
326
327 fn clamp(&self, p: i64) -> i64 {
328 p.clamp(self.min(), self.max())
329 }
330
331 fn range(&self) -> i64 {
332 if self.is_empty() {
333 return 0;
334 }
335 self.max() - self.min()
336 }
337
338 fn mid(&self) -> i64 {
339 self.min() + self.range() / 2
340 }
341}
342
343impl<const D: usize> IsRegion<D, SVector<i64, D>> for IRegion<D> {
344 fn unbounded() -> Self {
345 let s: SVector<i64, D> = SVector::<i64, D>::smallest();
346 let l: SVector<i64, D> = SVector::<i64, D>::largest();
347 Self::from_min_max(s, l)
348 }
349
350 fn empty() -> Self {
351 Self {
352 min_max: Option::default(),
353 }
354 }
355
356 fn is_empty(&self) -> bool {
357 self.min_max.is_none()
358 }
359
360 fn is_degenerated(&self) -> bool {
361 false
362 }
363
364 fn is_unbounded(&self) -> bool {
365 if self.is_empty() {
366 return false;
367 }
368 self.min() == SVector::<i64, D>::smallest() && self.max() == SVector::<i64, D>::largest()
369 }
370
371 fn from_min_max(min: SVector<i64, D>, max: SVector<i64, D>) -> Self {
372 Self {
373 min_max: Option::Some((min, max)),
374 }
375 }
376
377 fn try_min(&self) -> Option<SVector<i64, D>> {
378 Some(self.min_max?.0)
379 }
380 fn try_max(&self) -> Option<SVector<i64, D>> {
381 Some(self.min_max?.1)
382 }
383
384 fn clamp(&self, p: SVector<i64, D>) -> SVector<i64, D> {
385 p.clamp(self.min(), self.max())
386 }
387
388 fn range(&self) -> SVector<i64, D> {
389 let p: SVector<i64, D>;
390 if self.is_empty() {
391 p = SVector::<i64, D>::zeros();
392 return p;
393 }
394 p = self.max() - self.min() + SVector::<i64, D>::repeat(1);
395 p
396 }
397
398 fn mid(&self) -> SVector<i64, D> {
399 self.min() + self.range() / 2
400 }
401
402 fn extend(&mut self, point: &SVector<i64, D>) {
403 if self.is_empty() {
404 *self = Self::from_point(*point);
405 }
406 let (min, max) = self.min().inf_sup(point);
407
408 *self = Self::from_min_max(min, max)
409 }
410}
411
412#[cfg(test)]
413mod tests {
414
415 use super::*;
416
417 #[test]
418 fn region() {
419 let empty_f64 = Region::<2>::empty();
420 assert!(empty_f64.is_empty());
421 assert!(!empty_f64.is_degenerated());
422 assert!(!empty_f64.is_proper());
423 assert!(!empty_f64.is_unbounded());
424
425 let unbounded = Region::<2>::unbounded();
426 assert!(!unbounded.is_empty());
427 assert!(!unbounded.is_degenerated());
428 assert!(unbounded.is_proper());
429 assert!(unbounded.is_unbounded());
430
431 let one_i64 = IRegion::<2>::from_point(SVector::<i64, 2>::repeat(1));
432 assert!(!one_i64.is_empty());
433 assert!(!one_i64.is_degenerated());
434 assert!(one_i64.is_proper());
435 assert!(!one_i64.is_unbounded());
436
437 let two_f64 = Region::<2>::from_point(SVector::<f64, 2>::repeat(2.0));
438 assert!(!two_f64.is_empty());
439 assert!(two_f64.is_degenerated());
440 assert!(!two_f64.is_proper());
441 assert!(!two_f64.is_unbounded());
442 }
443
444 #[test]
445 fn interval() {
446 let empty_f64 = Interval::empty();
447 assert!(empty_f64.is_empty());
448 assert!(!empty_f64.is_degenerated());
449 assert!(!empty_f64.is_proper());
450 assert!(!empty_f64.is_unbounded());
451
452 let unbounded = Interval::unbounded();
453 assert!(!unbounded.is_empty());
454 assert!(!unbounded.is_degenerated());
455 assert!(unbounded.is_proper());
456 assert!(unbounded.is_unbounded());
457
458 let one_i64 = IRegion::<1>::from_point(SVector::<i64, 1>::repeat(1));
459 assert!(!one_i64.is_empty());
460 assert!(!one_i64.is_degenerated());
461 assert!(one_i64.is_proper());
462 assert!(!one_i64.is_unbounded());
463
464 let two_f64 = Interval::from_point(2.0);
465 assert!(!two_f64.is_empty());
466 assert!(two_f64.is_degenerated());
467 assert!(!two_f64.is_proper());
468 assert!(!two_f64.is_unbounded());
469 }
470}