conrod_core/position/
range.rs

1//! A type for working one-dimensional ranges.
2
3use super::Scalar;
4
5/// Some start and end position along a single axis.
6///
7/// As an example, a **Rect** is made up of two **Range**s; one along the *x* axis, and one along
8/// the *y* axis.
9#[derive(Copy, Clone, Debug, PartialEq)]
10pub struct Range {
11    /// The start of some `Range` along an axis.
12    pub start: Scalar,
13    /// The end of some `Range` along an axis.
14    pub end: Scalar,
15}
16
17/// Represents either the **Start** or **End** **Edge** of a **Range**.
18#[derive(Copy, Clone, Debug, PartialEq, Eq)]
19pub enum Edge {
20    /// The beginning of a **Range**.
21    Start,
22    /// The end of a **Range**.
23    End,
24}
25
26impl Range {
27    /// Construct a new `Range` from a given range, i.e. `Range::new(start, end)`.
28    ///
29    /// # Examples
30    ///
31    /// ```
32    /// use conrod_core::Range;
33    ///
34    /// assert_eq!(Range { start: 0.0, end: 10.0 }, Range::new(0.0, 10.0));
35    /// ```
36    pub fn new(start: Scalar, end: Scalar) -> Range {
37        Range {
38            start: start,
39            end: end,
40        }
41    }
42
43    /// Construct a new `Range` from a given length and its centered position.
44    ///
45    /// # Examples
46    ///
47    /// ```
48    /// use conrod_core::Range;
49    ///
50    /// assert_eq!(Range::new(0.0, 10.0), Range::from_pos_and_len(5.0, 10.0));
51    /// assert_eq!(Range::new(-5.0, 1.0), Range::from_pos_and_len(-2.0, 6.0));
52    /// assert_eq!(Range::new(-100.0, 200.0), Range::from_pos_and_len(50.0, 300.0));
53    /// ```
54    pub fn from_pos_and_len(pos: Scalar, len: Scalar) -> Range {
55        let half_len = len / 2.0;
56        let start = pos - half_len;
57        let end = pos + half_len;
58        Range::new(start, end)
59    }
60
61    /// The `start` value subtracted from the `end` value.
62    ///
63    /// # Examples
64    ///
65    /// ```
66    /// use conrod_core::Range;
67    ///
68    /// assert_eq!(Range::new(-5.0, 5.0).magnitude(), 10.0);
69    /// assert_eq!(Range::new(5.0, -5.0).magnitude(), -10.0);
70    /// assert_eq!(Range::new(15.0, 10.0).magnitude(), -5.0);
71    /// ```
72    pub fn magnitude(&self) -> Scalar {
73        self.end - self.start
74    }
75
76    /// The absolute length of the Range aka the absolute magnitude.
77    ///
78    /// # Examples
79    ///
80    /// ```
81    /// use conrod_core::Range;
82    ///
83    /// assert_eq!(Range::new(-5.0, 5.0).len(), 10.0);
84    /// assert_eq!(Range::new(5.0, -5.0).len(), 10.0);
85    /// assert_eq!(Range::new(15.0, 10.0).len(), 5.0);
86    /// ```
87    pub fn len(&self) -> Scalar {
88        self.magnitude().abs()
89    }
90
91    /// Return the value directly between the start and end values.
92    ///
93    /// # Examples
94    ///
95    /// ```
96    /// use conrod_core::Range;
97    ///
98    /// assert_eq!(Range::new(-5.0, 5.0).middle(), 0.0);
99    /// assert_eq!(Range::new(5.0, -5.0).middle(), 0.0);
100    /// assert_eq!(Range::new(10.0, 15.0).middle(), 12.5);
101    /// assert_eq!(Range::new(20.0, 40.0).middle(), 30.0);
102    /// assert_eq!(Range::new(20.0, -40.0).middle(), -10.0);
103    /// ```
104    pub fn middle(&self) -> Scalar {
105        (self.end + self.start) / 2.0
106    }
107
108    /// The current range with its start and end values swapped.
109    ///
110    /// # Examples
111    ///
112    /// ```
113    /// use conrod_core::Range;
114    ///
115    /// assert_eq!(Range::new(-5.0, 5.0).invert(), Range::new(5.0, -5.0));
116    /// assert_eq!(Range::new(-10.0, 10.0).invert(), Range::new(10.0, -10.0));
117    /// assert_eq!(Range::new(0.0, 7.25).invert(), Range::new(7.25, 0.0));
118    /// assert_eq!(Range::new(5.0, 1.0).invert(), Range::new(1.0, 5.0));
119    /// ```
120    pub fn invert(self) -> Range {
121        Range {
122            start: self.end,
123            end: self.start,
124        }
125    }
126
127    /// Map the given Scalar from `Self` to some other given `Range`.
128    ///
129    /// # Examples
130    ///
131    /// ```
132    /// use conrod_core::Range;
133    ///
134    /// let a = Range::new(0.0, 5.0);
135    ///
136    /// let b = Range::new(0.0, 10.0);
137    /// assert_eq!(a.map_value_to(2.5, &b), 5.0);
138    /// assert_eq!(a.map_value_to(0.0, &b), 0.0);
139    /// assert_eq!(a.map_value_to(5.0, &b), 10.0);
140    /// assert_eq!(a.map_value_to(-5.0, &b), -10.0);
141    /// assert_eq!(a.map_value_to(10.0, &b), 20.0);
142    ///
143    /// let c = Range::new(10.0, -10.0);
144    /// assert_eq!(a.map_value_to(2.5, &c), 0.0);
145    /// assert_eq!(a.map_value_to(0.0, &c), 10.0);
146    /// assert_eq!(a.map_value_to(5.0, &c), -10.0);
147    /// assert_eq!(a.map_value_to(-5.0, &c), 30.0);
148    /// assert_eq!(a.map_value_to(10.0, &c), -30.0);
149    /// ```
150    pub fn map_value_to(&self, value: Scalar, other: &Range) -> Scalar {
151        ::utils::map_range(value, self.start, self.end, other.start, other.end)
152    }
153
154    /// Shift the `Range` start and end points by a given `Scalar`.
155    ///
156    /// # Examples
157    ///
158    /// ```
159    /// use conrod_core::Range;
160    ///
161    /// assert_eq!(Range::new(0.0, 5.0).shift(5.0), Range::new(5.0, 10.0));
162    /// assert_eq!(Range::new(0.0, 5.0).shift(-5.0), Range::new(-5.0, 0.0));
163    /// assert_eq!(Range::new(5.0, -5.0).shift(-5.0), Range::new(0.0, -10.0));
164    /// ```
165    pub fn shift(self, amount: Scalar) -> Range {
166        Range {
167            start: self.start + amount,
168            end: self.end + amount,
169        }
170    }
171
172    /// The direction of the Range represented as a normalised scalar.
173    ///
174    /// # Examples
175    ///
176    /// ```
177    /// use conrod_core::Range;
178    ///
179    /// assert_eq!(Range::new(0.0, 5.0).direction(), 1.0);
180    /// assert_eq!(Range::new(0.0, 0.0).direction(), 0.0);
181    /// assert_eq!(Range::new(0.0, -5.0).direction(), -1.0);
182    /// ```
183    pub fn direction(&self) -> Scalar {
184        if self.start < self.end {
185            1.0
186        } else if self.start > self.end {
187            -1.0
188        } else {
189            0.0
190        }
191    }
192
193    /// Converts the Range to an undirected Range. By ensuring that `start` <= `end`.
194    ///
195    /// If `start` > `end`, then the start and end points will be swapped.
196    ///
197    /// # Examples
198    ///
199    /// ```
200    /// use conrod_core::Range;
201    ///
202    /// assert_eq!(Range::new(0.0, 5.0).undirected(), Range::new(0.0, 5.0));
203    /// assert_eq!(Range::new(5.0, 1.0).undirected(), Range::new(1.0, 5.0));
204    /// assert_eq!(Range::new(10.0, -10.0).undirected(), Range::new(-10.0, 10.0));
205    /// ```
206    pub fn undirected(self) -> Range {
207        if self.start > self.end {
208            self.invert()
209        } else {
210            self
211        }
212    }
213
214    /// The Range that encompasses both self and the given Range.
215    ///
216    /// The returned Range's `start` will always be <= its `end`.
217    ///
218    /// # Examples
219    ///
220    /// ```
221    /// use conrod_core::Range;
222    ///
223    /// let a = Range::new(0.0, 3.0);
224    /// let b = Range::new(7.0, 10.0);
225    /// assert_eq!(a.max(b), Range::new(0.0, 10.0));
226    ///
227    /// let c = Range::new(-20.0, -30.0);
228    /// let d = Range::new(5.0, -7.5);
229    /// assert_eq!(c.max(d), Range::new(-30.0, 5.0));
230    /// ```
231    pub fn max(self, other: Self) -> Range {
232        let start = self.start.min(self.end).min(other.start).min(other.end);
233        let end = self.start.max(self.end).max(other.start).max(other.end);
234        Range::new(start, end)
235    }
236
237    /// The Range that represents the range of the overlap between two Ranges if there is some.
238    ///
239    /// The returned `Range`'s `start` will always be < its `end`.
240    ///
241    /// # Examples
242    ///
243    /// ```
244    /// use conrod_core::Range;
245    ///
246    /// let a = Range::new(0.0, 6.0);
247    /// let b = Range::new(4.0, 10.0);
248    /// assert_eq!(a.overlap(b), Some(Range::new(4.0, 6.0)));
249    ///
250    /// let c = Range::new(10.0, -30.0);
251    /// let d = Range::new(-5.0, 20.0);
252    /// assert_eq!(c.overlap(d), Some(Range::new(-5.0, 10.0)));
253    ///
254    /// let e = Range::new(0.0, 2.5);
255    /// let f = Range::new(50.0, 100.0);
256    /// assert_eq!(e.overlap(f), None);
257    /// ```
258    pub fn overlap(mut self, mut other: Self) -> Option<Range> {
259        self = self.undirected();
260        other = other.undirected();
261        let start = ::utils::partial_max(self.start, other.start);
262        let end = ::utils::partial_min(self.end, other.end);
263        let magnitude = end - start;
264        if magnitude > 0.0 {
265            Some(Range::new(start, end))
266        } else {
267            None
268        }
269    }
270
271    /// The Range that encompasses both self and the given Range.
272    ///
273    /// The same as [**Range::max**](./struct.Range#method.max) but retains `self`'s original
274    /// direction.
275    ///
276    /// # Examples
277    ///
278    /// ```
279    /// use conrod_core::Range;
280    ///
281    /// let a = Range::new(0.0, 3.0);
282    /// let b = Range::new(7.0, 10.0);
283    /// assert_eq!(a.max_directed(b), Range::new(0.0, 10.0));
284    ///
285    /// let c = Range::new(-20.0, -30.0);
286    /// let d = Range::new(5.0, -7.5);
287    /// assert_eq!(c.max_directed(d), Range::new(5.0, -30.0));
288    /// ```
289    pub fn max_directed(self, other: Self) -> Range {
290        if self.start <= self.end {
291            self.max(other)
292        } else {
293            self.max(other).invert()
294        }
295    }
296
297    /// Is the given scalar within our range.
298    ///
299    /// # Examples
300    ///
301    /// ```
302    /// use conrod_core::Range;
303    ///
304    /// let range = Range::new(0.0, 10.0);
305    /// assert!(range.is_over(5.0));
306    /// assert!(!range.is_over(12.0));
307    /// assert!(!range.is_over(-1.0));
308    /// assert!(range.is_over(0.0));
309    /// assert!(range.is_over(10.0));
310    /// ```
311    pub fn is_over(&self, pos: Scalar) -> bool {
312        let Range { start, end } = self.undirected();
313        pos >= start && pos <= end
314    }
315
316    /// Round the values at both ends of the Range and return the result.
317    ///
318    /// # Examples
319    ///
320    /// ```
321    /// use conrod_core::Range;
322    ///
323    /// assert_eq!(Range::new(0.25, 9.5).round(), Range::new(0.0, 10.0));
324    /// assert_eq!(Range::new(4.95, -5.3).round(), Range::new(5.0, -5.0));
325    /// ```
326    pub fn round(self) -> Range {
327        Range::new(self.start.round(), self.end.round())
328    }
329
330    /// Floor the values at both ends of the Range and return the result.
331    ///
332    /// # Examples
333    ///
334    /// ```
335    /// use conrod_core::Range;
336    ///
337    /// assert_eq!(Range::new(0.25, 9.5).floor(), Range::new(0.0, 9.0));
338    /// assert_eq!(Range::new(4.95, -5.3).floor(), Range::new(4.0, -6.0));
339    /// ```
340    pub fn floor(self) -> Range {
341        Range::new(self.start.floor(), self.end.floor())
342    }
343
344    /// The Range with some padding given to the `start` value.
345    ///
346    /// # Examples
347    ///
348    /// ```
349    /// use conrod_core::Range;
350    ///
351    /// assert_eq!(Range::new(0.0, 10.0).pad_start(2.0), Range::new(2.0, 10.0));
352    /// assert_eq!(Range::new(10.0, 0.0).pad_start(2.0), Range::new(8.0, 0.0));
353    /// ```
354    pub fn pad_start(mut self, pad: Scalar) -> Range {
355        self.start += if self.start <= self.end { pad } else { -pad };
356        self
357    }
358
359    /// The Range with some padding given to the `end` value.
360    ///
361    /// # Examples
362    ///
363    /// ```
364    /// use conrod_core::Range;
365    ///
366    /// assert_eq!(Range::new(0.0, 10.0).pad_end(2.0), Range::new(0.0, 8.0));
367    /// assert_eq!(Range::new(10.0, 0.0).pad_end(2.0), Range::new(10.0, 2.0));
368    /// ```
369    pub fn pad_end(mut self, pad: Scalar) -> Range {
370        self.end += if self.start <= self.end { -pad } else { pad };
371        self
372    }
373
374    /// The Range with some given padding to be applied to each end.
375    ///
376    /// # Examples
377    ///
378    /// ```
379    /// use conrod_core::Range;
380    ///
381    /// assert_eq!(Range::new(0.0, 10.0).pad(2.0), Range::new(2.0, 8.0));
382    /// assert_eq!(Range::new(10.0, 0.0).pad(2.0), Range::new(8.0, 2.0));
383    /// ```
384    pub fn pad(self, pad: Scalar) -> Range {
385        self.pad_start(pad).pad_end(pad)
386    }
387
388    /// The Range with some padding given for each end.
389    ///
390    /// # Examples
391    ///
392    /// ```
393    /// use conrod_core::Range;
394    ///
395    /// assert_eq!(Range::new(0.0, 10.0).pad_ends(1.0, 2.0), Range::new(1.0, 8.0));
396    /// assert_eq!(Range::new(10.0, 0.0).pad_ends(4.0, 3.0), Range::new(6.0, 3.0));
397    /// ```
398    pub fn pad_ends(self, start: Scalar, end: Scalar) -> Range {
399        self.pad_start(start).pad_end(end)
400    }
401
402    /// Clamp the given value to the range.
403    ///
404    /// # Examples
405    ///
406    /// ```
407    /// use conrod_core::Range;
408    ///
409    /// assert_eq!(Range::new(0.0, 5.0).clamp_value(7.0), 5.0);
410    /// assert_eq!(Range::new(5.0, -2.5).clamp_value(-3.0), -2.5);
411    /// assert_eq!(Range::new(5.0, 10.0).clamp_value(0.0), 5.0);
412    /// ```
413    pub fn clamp_value(&self, value: Scalar) -> Scalar {
414        ::utils::clamp(value, self.start, self.end)
415    }
416
417    /// Stretch the end that is closest to the given value only if it lies outside the Range.
418    ///
419    /// The resulting Range will retain the direction of the original range.
420    ///
421    /// # Examples
422    ///
423    /// ```
424    /// use conrod_core::Range;
425    ///
426    /// let a = Range::new(2.5, 5.0);
427    /// assert_eq!(a.stretch_to_value(10.0), Range::new(2.5, 10.0));
428    /// assert_eq!(a.stretch_to_value(0.0), Range::new(0.0, 5.0));
429    ///
430    /// let b = Range::new(0.0, -5.0);
431    /// assert_eq!(b.stretch_to_value(10.0), Range::new(10.0, -5.0));
432    /// assert_eq!(b.stretch_to_value(-10.0), Range::new(0.0, -10.0));
433    /// ```
434    pub fn stretch_to_value(self, value: Scalar) -> Range {
435        let Range { start, end } = self;
436        if start <= end {
437            if value < start {
438                Range {
439                    start: value,
440                    end: end,
441                }
442            } else if value > end {
443                Range {
444                    start: start,
445                    end: value,
446                }
447            } else {
448                self
449            }
450        } else {
451            if value < end {
452                Range {
453                    start: start,
454                    end: value,
455                }
456            } else if value > start {
457                Range {
458                    start: value,
459                    end: end,
460                }
461            } else {
462                self
463            }
464        }
465    }
466
467    /// Does `self` have the same direction as `other`.
468    ///
469    /// # Examples
470    ///
471    /// ```
472    /// use conrod_core::Range;
473    ///
474    /// assert!(Range::new(0.0, 1.0).has_same_direction(Range::new(100.0, 200.0)));
475    /// assert!(Range::new(0.0, -5.0).has_same_direction(Range::new(-2.5, -6.0)));
476    /// assert!(!Range::new(0.0, 5.0).has_same_direction(Range::new(2.5, -2.5)));
477    /// ```
478    pub fn has_same_direction(self, other: Self) -> bool {
479        let self_direction = self.start <= self.end;
480        let other_direction = other.start <= other.end;
481        self_direction == other_direction
482    }
483
484    /// Align the `start` of `self` to the `start` of the `other` **Range**.
485    ///
486    /// If the direction of `other` is different to `self`, `self`'s `end` will be aligned to the
487    /// `start` of `other` instead.
488    ///
489    /// # Examples
490    ///
491    /// ```
492    /// use conrod_core::Range;
493    ///
494    /// let a = Range::new(2.5, 7.5);
495    /// let b = Range::new(0.0, 10.0);
496    /// assert_eq!(a.align_start_of(b), Range::new(0.0, 5.0));
497    /// assert_eq!(b.align_start_of(a), Range::new(2.5, 12.5));
498    ///
499    /// let c = Range::new(2.5, -2.5);
500    /// let d = Range::new(-5.0, 5.0);
501    /// assert_eq!(c.align_start_of(d), Range::new(0.0, -5.0));
502    /// assert_eq!(d.align_start_of(c), Range::new(-7.5, 2.5));
503    /// ```
504    pub fn align_start_of(self, other: Self) -> Self {
505        let diff = if self.has_same_direction(other) {
506            other.start - self.start
507        } else {
508            other.start - self.end
509        };
510        self.shift(diff)
511    }
512
513    /// Align the `end` of `self` to the `end` of the `other` **Range**.
514    ///
515    /// If the direction of `other` is different to `self`, `self`'s `start` will be aligned to the
516    /// `end` of `other` instead.
517    ///
518    /// # Examples
519    ///
520    /// ```
521    /// use conrod_core::Range;
522    ///
523    /// let a = Range::new(2.5, 7.5);
524    /// let b = Range::new(0.0, 10.0);
525    /// assert_eq!(a.align_end_of(b), Range::new(5.0, 10.0));
526    /// assert_eq!(b.align_end_of(a), Range::new(-2.5, 7.5));
527    ///
528    /// let c = Range::new(2.5, -2.5);
529    /// let d = Range::new(-5.0, 5.0);
530    /// assert_eq!(c.align_end_of(d), Range::new(5.0, 0.0));
531    /// assert_eq!(d.align_end_of(c), Range::new(-2.5, 7.5));
532    /// ```
533    pub fn align_end_of(self, other: Self) -> Self {
534        let diff = if self.has_same_direction(other) {
535            other.end - self.end
536        } else {
537            other.end - self.start
538        };
539        self.shift(diff)
540    }
541
542    /// Align the middle of `self` to the middle of the `other` **Range**.
543    ///
544    /// # Examples
545    ///
546    /// ```
547    /// use conrod_core::Range;
548    ///
549    /// let a = Range::new(0.0, 5.0);
550    /// let b = Range::new(0.0, 10.0);
551    /// assert_eq!(a.align_middle_of(b), Range::new(2.5, 7.5));
552    /// assert_eq!(b.align_middle_of(a), Range::new(-2.5, 7.5));
553    ///
554    /// let c = Range::new(2.5, -2.5);
555    /// let d = Range::new(-10.0, 0.0);
556    /// assert_eq!(c.align_middle_of(d), Range::new(-2.5, -7.5));
557    /// assert_eq!(d.align_middle_of(c), Range::new(-5.0, 5.0));
558    /// ```
559    pub fn align_middle_of(self, other: Self) -> Self {
560        let diff = other.middle() - self.middle();
561        self.shift(diff)
562    }
563
564    /// Aligns the `start` of `self` with the `end` of `other`.
565    ///
566    /// If the directions are opposite, aligns the `end` of self with the `end` of `other`.
567    ///
568    /// # Examples
569    ///
570    /// ```
571    /// use conrod_core::Range;
572    ///
573    /// let a = Range::new(2.5, 7.5);
574    /// let b = Range::new(0.0, 10.0);
575    /// assert_eq!(a.align_after(b), Range::new(10.0, 15.0));
576    /// assert_eq!(b.align_after(a), Range::new(7.5, 17.5));
577    ///
578    /// let c = Range::new(2.5, -2.5);
579    /// let d = Range::new(-5.0, 5.0);
580    /// assert_eq!(c.align_after(d), Range::new(10.0, 5.0));
581    /// assert_eq!(d.align_after(c), Range::new(-12.5, -2.5));
582    /// ```
583    pub fn align_after(self, other: Self) -> Self {
584        let diff = if self.has_same_direction(other) {
585            other.end - self.start
586        } else {
587            other.end - self.end
588        };
589        self.shift(diff)
590    }
591
592    /// Aligns the `end` of `self` with the `start` of `other`.
593    ///
594    /// If the directions are opposite, aligns the `start` of self with the `start` of `other`.
595    ///
596    /// # Examples
597    ///
598    /// ```
599    /// use conrod_core::Range;
600    ///
601    /// let a = Range::new(2.5, 7.5);
602    /// let b = Range::new(0.0, 10.0);
603    /// assert_eq!(a.align_before(b), Range::new(-5.0, 0.0));
604    /// assert_eq!(b.align_before(a), Range::new(-7.5, 2.5));
605    ///
606    /// let c = Range::new(2.5, -2.5);
607    /// let d = Range::new(-5.0, 5.0);
608    /// assert_eq!(c.align_before(d), Range::new(-5.0, -10.0));
609    /// assert_eq!(d.align_before(c), Range::new(2.5, 12.5));
610    /// ```
611    pub fn align_before(self, other: Self) -> Self {
612        let diff = if self.has_same_direction(other) {
613            other.start - self.end
614        } else {
615            other.start - self.start
616        };
617        self.shift(diff)
618    }
619
620    /// Align `self` to `other` along the *x* axis in accordance with the given `Align` variant.
621    pub fn align_to(self, align: super::Align, other: Self) -> Self {
622        match align {
623            super::Align::Start => self.align_start_of(other),
624            super::Align::Middle => self.align_middle_of(other),
625            super::Align::End => self.align_end_of(other),
626        }
627    }
628
629    /// The closest **Edge** of `self` to the given `scalar`.
630    ///
631    /// Returns **Start** if the distance between both **Edge**s is equal.
632    ///
633    /// # Examples
634    ///
635    /// ```
636    /// use conrod_core::position::{Edge, Range};
637    ///
638    /// assert_eq!(Range::new(0.0, 10.0).closest_edge(4.0), Edge::Start);
639    /// assert_eq!(Range::new(0.0, 10.0).closest_edge(7.0), Edge::End);
640    /// assert_eq!(Range::new(0.0, 10.0).closest_edge(5.0), Edge::Start);
641    /// ```
642    pub fn closest_edge(&self, scalar: Scalar) -> Edge {
643        let Range { start, end } = *self;
644        let start_diff = if scalar < start {
645            start - scalar
646        } else {
647            scalar - start
648        };
649        let end_diff = if scalar < end {
650            end - scalar
651        } else {
652            scalar - end
653        };
654        if start_diff <= end_diff {
655            Edge::Start
656        } else {
657            Edge::End
658        }
659    }
660}