Oregami
Repositories/oxedyne/fe2o3

oxedyne/fe2o3/fe2o3_geom/src/dim.rs

13.2 KiB, 3 runs

created by r1870400018:331, which is this file's identity for as long as the history lasts, whatever it is later renamed to

download · who wrote it · its history

1use oxedyne_fe2o3_core::prelude::*;
2
3use std::{
4 fmt,
5 iter::Sum,
6};
7
8
9new_type!(Dim, usize, Clone, Copy, Debug, Default, Eq, Hash, Ord);
10
11impl fmt::Display for Dim {
12 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
13 write!(f, "{}", self.0)
14 }
15}
16
17impl<T> From<T> for Dim
18where
19 usize: From<T>,
20{
21 fn from(value: T) -> Self {
22 Dim(usize::from(value))
23 }
24}
25
26impl std::ops::Add for Dim {
27 type Output = Self;
28
29 fn add(self, other: Self) -> Self {
30 Self(self.0.saturating_add(other.0))
31 }
32}
33
34impl std::ops::Add<usize> for Dim {
35 type Output = Self;
36
37 fn add(self, other: usize) -> Self {
38 Self(self.0.saturating_add(other))
39 }
40}
41
42impl std::ops::Add<Dim> for usize {
43 type Output = Dim;
44
45 fn add(self, other: Dim) -> Dim {
46 Dim(self.saturating_add(other.0))
47 }
48}
49
50impl std::ops::Sub for Dim {
51 type Output = Self;
52
53 fn sub(self, other: Self) -> Self {
54 Self(self.0.saturating_sub(other.0))
55 }
56}
57
58impl std::ops::Sub<usize> for Dim {
59 type Output = Self;
60
61 fn sub(self, other: usize) -> Self {
62 Self(self.0.saturating_sub(other))
63 }
64}
65
66impl std::ops::Sub<Dim> for usize {
67 type Output = Dim;
68
69 fn sub(self, other: Dim) -> Dim {
70 Dim(self.saturating_sub(other.0))
71 }
72}
73
74impl std::ops::Mul for Dim {
75 type Output = Self;
76
77 fn mul(self, other: Self) -> Self {
78 Self(self.0.saturating_mul(other.0))
79 }
80}
81
82impl std::ops::Mul<usize> for Dim {
83 type Output = Self;
84
85 fn mul(self, other: usize) -> Self {
86 Self(self.0.saturating_mul(other))
87 }
88}
89
90impl std::ops::Mul<Dim> for usize {
91 type Output = Dim;
92
93 fn mul(self, other: Dim) -> Dim {
94 Dim(self.saturating_mul(other.0))
95 }
96}
97
98impl std::ops::Div for Dim {
99 type Output = Self;
100
101 fn div(self, other: Self) -> Self {
102 Self(self.0.saturating_div(other.0))
103 }
104}
105
106impl std::ops::Div<usize> for Dim {
107 type Output = Self;
108
109 fn div(self, other: usize) -> Self {
110 Self(self.0.saturating_div(other))
111 }
112}
113
114impl std::ops::Div<Dim> for usize {
115 type Output = Dim;
116
117 fn div(self, other: Dim) -> Dim {
118 Dim(self.saturating_div(other.0))
119 }
120}
121
122impl std::ops::Rem for Dim {
123 type Output = Self;
124
125 fn rem(self, other: Self) -> Self {
126 Self(self.0.rem(other.0))
127 }
128}
129
130impl std::ops::Rem<usize> for Dim {
131 type Output = Self;
132
133 fn rem(self, other: usize) -> Self {
134 Self(self.0.rem(other))
135 }
136}
137
138impl std::ops::Rem<Dim> for usize {
139 type Output = Dim;
140
141 fn rem(self, other: Dim) -> Dim {
142 Dim(self.rem(other.0))
143 }
144}
145
146impl<T: Copy> PartialEq<T> for Dim
147where
148 usize: From<T>,
149{
150 fn eq(&self, other: &T) -> bool {
151 self.0 == usize::from(*other)
152 }
153}
154
155impl PartialEq<Dim> for Dim {
156 fn eq(&self, other: &Dim) -> bool {
157 self.0 == other.0
158 }
159}
160
161impl PartialEq<Dim> for usize {
162 fn eq(&self, other: &Dim) -> bool {
163 *self == other.0
164 }
165}
166
167impl<T: Copy> PartialOrd<T> for Dim
168where
169 usize: From<T>,
170{
171 fn partial_cmp(&self, other: &T) -> Option<std::cmp::Ordering> {
172 self.0.partial_cmp(&usize::from(*other))
173 }
174}
175
176impl PartialOrd<Dim> for Dim {
177 fn partial_cmp(&self, other: &Dim) -> Option<std::cmp::Ordering> {
178 self.0.partial_cmp(&other.0)
179 }
180}
181
182impl PartialOrd<Dim> for usize {
183 fn partial_cmp(&self, other: &Dim) -> Option<std::cmp::Ordering> {
184 self.partial_cmp(&other.0)
185 }
186}
187
188impl std::ops::AddAssign for Dim {
189 fn add_assign(&mut self, other: Self) {
190 self.0 = self.0.saturating_add(other.0);
191 }
192}
193
194impl std::ops::AddAssign<usize> for Dim {
195 fn add_assign(&mut self, other: usize) {
196 self.0 = self.0.saturating_add(other);
197 }
198}
199
200impl std::ops::SubAssign for Dim {
201 fn sub_assign(&mut self, other: Self) {
202 self.0 = self.0.saturating_sub(other.0);
203 }
204}
205
206impl std::ops::SubAssign<usize> for Dim {
207 fn sub_assign(&mut self, other: usize) {
208 self.0 = self.0.saturating_sub(other);
209 }
210}
211
212impl Sum for Dim {
213 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
214 iter.fold(Dim(0), |acc, x| acc + x)
215 }
216}
217
218impl Dim {
219
220 pub fn new<N: Into<usize>>(n: N) -> Self {
221 Self(n.into())
222 }
223
224 pub fn as_usize(&self) -> usize {
225 self.0
226 }
227
228 pub fn as_index(&self) -> usize {
229 self.0
230 }
231
232 pub fn checked_div(&self, other: Self) -> Option<Self> {
233 if other.0 == 0 {
234 None
235 } else {
236 Some(*self / other)
237 }
238 }
239}
240
241new_type!(Span, (Dim, Dim), Clone, Debug, Default, Eq, Ord, PartialEq, PartialOrd);
242
243impl From<(Dim, Dim)> for Span {
244 fn from((x, y): (Dim, Dim)) -> Self { Self((x, y)) }
245}
246
247impl Span {
248
249 pub fn new<
250 X: Into<Dim>,
251 Y: Into<Dim>,
252 >(
253 (x, y): (X, Y),
254 )
255 -> Self
256 {
257 Self((
258 x.into(),
259 y.into(),
260 ))
261 }
262
263 pub fn tup(&self) -> (Dim, Dim) { (self.0.0, self.0.1) }
264 pub fn start(&self) -> Dim { self.0.0 }
265 pub fn len(&self) -> Dim { self.0.1 }
266
267 /// Clip `x2` and `len2` by `x1` and `len1` so that that latter stays within the former bounds.
268 /// ```ignore
269 ///
270 ///
271 /// Case A:
272 /// x1 x1+len1
273 /// |--------------------+----------------------------+
274 /// |---------+--------+
275 /// x2 x2+len2
276 /// Result: Clipped completely.
277 /// |--------------------+
278 /// x2=x1 len2=0
279 ///
280 /// Case B:
281 /// x1 x1+len1
282 /// |--------------------+----------------------------+
283 /// |----------------+----------------------+
284 /// x2 x2+len2
285 /// Result:
286 /// |--------------------+------------------+ Clipped at start.
287 /// x2=x1 | x2+len2
288 /// |
289 /// len2=x2+len2-x1
290 ///
291 /// Case C:
292 /// x1 x1+len1
293 /// |--------------------+----------------------------+
294 /// |---------------------------+------------+
295 /// x2 x2+len2
296 /// Result:
297 /// |---------------------------+------------+ No clipping.
298 /// x2 x2+len2
299 ///
300 /// Case D:
301 /// x1 x1+len1
302 /// |--------------------+----------------------------+
303 /// |--------------------------------------------+----------------------+
304 /// x2 x2+len2
305 /// Result:
306 /// |--------------------------------------------+----+ Clipped at end.
307 /// x2 | x2+len2
308 /// |
309 /// len2=x1+len1-x2
310 /// Case E:
311 /// x1 x1+len1
312 /// |--------------------+----------------------------+ x2 x2+len2
313 /// |--------------------------------------------------------+------+
314 ///
315 /// Result: Clipped completely.
316 /// |-------------------------------------------------+
317 /// x2=x1+len1 len2=0
318 ///
319 /// ```
320 pub fn clip(
321 &self,
322 clipped: Self,
323 )
324 -> Option<Self>
325 {
326 let (x1, len1) = self.tup();
327 let (x2, len2) = clipped.tup();
328
329 return if x2 + len2 < x1 {
330 None // A
331 } else if x2 + len2 < x1 + len1 {
332 if x2 < x1 {
333 Some(Span((x1, x2 + len2 - x1))) // B
334 } else {
335 Some(Span((x2, len2))) // C
336 }
337 } else {
338 if x2 < x1 + len1 {
339 Some(Span((x2, x1 + len1 - x2))) // D
340 } else {
341 None // E
342 }
343 };
344 }
345}
346
347/// Specify start and end points along a dimension in terms of a possible static pad and/or fixed
348/// distance, using a flexible fill that occupies the remaining distance to the unspecified edge.
349/// ```ignore
350/// x1 (near) x2 x2+len2 x1+len1 (far)
351/// PadFixedFill(Dim, Dim) |<----pad---|----fixed-----|---fill---->|
352/// FillFixedPad(Dim, Dim) |<---fill----|---fixed---|-----pad----->|
353/// PadFillPad(Dim, Dim) |<---pad----|-----fill------|---pad---->|
354/// PadFill(Dim) |<------pad-------|---------fill------->|
355/// FillPad(Dim) |<------------fill------------|---pad-->|
356/// Fill |<--------------fill------------------->|
357///
358/// ```
359#[derive(Clone, Debug)]
360pub enum FlexDim {
361 PadFixedFill(Dim, Dim),
362 FillFixedPad(Dim, Dim),
363 PadFillPad(Dim, Dim),
364 PadFill(Dim),
365 FillPad(Dim),
366 Fill,
367}
368
369impl FlexDim {
370
371 pub fn end(&self, outer: Dim) -> Dim {
372 match *self {
373 Self::PadFixedFill(pad, fixed) => pad + fixed,
374 Self::FillFixedPad(_fixed, pad) => outer - pad,
375 Self::PadFillPad(_pad1, pad2) => outer - pad2,
376 Self::PadFill(pad) => pad,
377 Self::FillPad(pad) => outer - pad,
378 Self::Fill => outer,
379 }
380 }
381
382 pub fn relative_to(
383 &self,
384 outer: Span,
385 )
386 -> Span // (x2, len2)
387 {
388 let (x1, len1) = outer.tup();
389 Span(match self {
390 Self::PadFixedFill(pad, len2) => {
391 let pad = *pad;
392 let len2 = *len2;
393 if (pad > len1) || (pad + len2 > len1) {
394 (x1 + len1, Dim(0)) // Inner pushed right/bottom to zero length.
395 } else {
396 (x1 + pad, len2)
397 }
398 }
399 Self::FillFixedPad(len2, pad) => {
400 let pad = *pad;
401 let len2 = *len2;
402 if (pad > len1) || (pad + len2 > len1) {
403 (x1, Dim(0)) // Inner pushed left/top to zero length.
404 } else {
405 (x1 + len1 - pad - len2, len2)
406 }
407 }
408 Self::PadFillPad(pad1, pad2) => {
409 let pad1 = *pad1;
410 let pad2 = *pad2;
411 if pad1 + pad2 > len1 {
412 (x1 + (len1 / Dim(2)), Dim(0)) // Inner pushed centrally to zero length.
413 } else {
414 (x1 + pad1, len1 - pad1 - pad2)
415 }
416 }
417 Self::PadFill(pad) => {
418 let pad = *pad;
419 if pad > len1 {
420 (x1 + len1, Dim(0)) // Inner pushed right/bottom to zero length.
421 } else {
422 (x1 + pad, len1 - pad)
423 }
424 }
425 Self::FillPad(pad) => {
426 let pad = *pad;
427 if pad > len1 {
428 (x1, Dim(0)) // Inner pushed left/top to zero length.
429 } else {
430 (x1 + len1 - pad, len1 - pad)
431 }
432 }
433 Self::Fill => (x1, len1),
434 })
435 }
436}
437
438#[derive(Clone, Copy, Debug)]
439pub struct Offset {
440 pub x: isize,
441 pub y: isize,
442}
443
444impl Offset {
445 pub fn new((x, y): (isize, isize)) -> Self { Self { x, y } }
446 pub fn tup(&self) -> (isize, isize) { (self.x, self.y) }
447}
448
449#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
450pub struct Coord {
451 pub x: Dim,
452 pub y: Dim,
453}
454
455impl From<(Dim, Dim)> for Coord {
456 fn from((x, y): (Dim, Dim)) -> Self { Self { x, y } }
457}
458
459impl From<(usize, usize)> for Coord {
460 fn from((x, y): (usize, usize)) -> Self { Self { x: Dim(x), y: Dim(y) } }
461}
462
463impl std::ops::Add for Coord {
464 type Output = Self;
465
466 fn add(self, other: Self) -> Self {
467 Self {
468 x: self.x + other.x,
469 y: self.y + other.y,
470 }
471 }
472}
473
474impl std::ops::Sub for Coord {
475 type Output = Self;
476
477 fn sub(self, other: Self) -> Self {
478 Self {
479 x: self.x - other.x,
480 y: self.y - other.y,
481 }
482 }
483}
484
485impl std::ops::AddAssign for Coord {
486 fn add_assign(&mut self, other: Self) {
487 self.x = self.x + *other.x;
488 self.y = self.y + *other.y;
489 }
490}
491
492impl std::ops::SubAssign for Coord {
493 fn sub_assign(&mut self, other: Self) {
494 self.x = self.x - *other.x;
495 self.y = self.y - *other.y;
496 }
497}
498
499impl Coord {
500
501 pub fn new<
502 X: Into<Dim>,
503 Y: Into<Dim>,
504 >(
505 (x, y): (X, Y),
506 )
507 -> Self
508 {
509 Self {
510 x: x.into(),
511 y: y.into(),
512 }
513 }
514
515 pub fn zero() -> Self { Self { x: Dim(0), y: Dim(0) } }
516 pub fn tup(&self) -> (Dim, Dim) { (self.x, self.y) }
517
518 pub fn inc_x<D: Into<Dim>>(&mut self, by: D) { self.x = self.x + by.into(); }
519 pub fn dec_x<D: Into<Dim>>(&mut self, by: D) { self.x = self.x - by.into(); }
520 pub fn inc_y<D: Into<Dim>>(&mut self, by: D) { self.y = self.y + by.into(); }
521 pub fn dec_y<D: Into<Dim>>(&mut self, by: D) { self.y = self.y - by.into(); }
522}