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}