<commit_before>//! A type for working with one-dimensional ranges.

use geom::DefaultScalar;
use math::{self, BaseNum, two};
use math::num_traits::{Float, One, Zero};
use std::ops::Neg;

/// Some start and end position along a single axis.
///
/// As an example, a **Rect** is made up of two **Range**s; one along the *x* axis, and one along
/// the *y* axis.
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
pub struct Range<S = DefaultScalar> {
    /// The start of some `Range` along an axis.
    pub start: S,
    /// The end of some `Range` along an axis.
    pub end: S,
}

/// Represents either the **Start** or **End** **Edge** of a **Range**.
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub enum Edge {
    /// The beginning of a **Range**.
    Start,
    /// The end of a **Range**.
    End,
}

/// Describes alignment along a range.
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub enum Align { Start, Middle, End }

impl<S> Range<S>
where
    S: BaseNum,
{
    /// Construct a new `Range` from a given range, i.e. `Range::new(start, end)`.
    ///
    /// # Examples
    ///
    /// ```
    /// use nannou::geom::Range;
    ///
    /// assert_eq!(Range { start: 0.0, end: 10.0 }, Range::new(0.0, 10.0));
    /// ```
    pub fn new(start: S, end: S) -> Self {
        Range {
            start: start,
            end: end,
        }
    }

    /// Construct a new `Range` from a given length and its centered position.
    ///
    /// # Examples
    ///
    /// ```
    /// use nannou::geom::Range;
    ///
    /// assert_eq!(Range::new(0.0, 10.0), Range::from_pos_and_len(5.0, 10.0));
    /// assert_eq!(Range::new(-5.0, 1.0), Range::from_pos_and_len(-2.0, 6.0));
    /// assert_eq!(Range::new(-100.0, 200.0), Range::from_pos_and_len(50.0, 300.0));
    /// ```
    pub fn from_pos_and_len(pos: S, len: S) -> Self {
        let half_len = len / two();
        let start = pos - half_len;
        let end = pos + half_len;
        Range::new(start, end)
    }

    /// The `start` value subtracted from the `end` value.
    ///
    /// # Examples
    ///
    /// ```
    /// use nannou::geom::Range;
    ///
    /// assert_eq!(Range::new(-5.0, 5.0).magnitude(), 10.0);
    /// assert_eq!(Range::new(5.0, -5.0).magnitude(), -10.0);
    /// assert_eq!(Range::new(15.0, 10.0).magnitude(), -5.0);
    /// ```
    pub fn magnitude(&self) -> S {
        self.end - self.start
    }

    /// The absolute length of the Range aka the absolute magnitude.
    ///
    /// # Examples
    ///
    /// ```
    /// use nannou::geom::Range;
    ///
    /// assert_eq!(Range::new(-5.0, 5.0).len(), 10.0);
    /// assert_eq!(Range::new(5.0, -5.0).len(), 10.0);
    /// assert_eq!(Range::new(15.0, 10.0).len(), 5.0);
    /// ```
    pub fn len(&self) -> S
    where
        S: Neg<Output=S>,
    {
        let mag = self.magnitude();
        let zero = S::zero();
        if mag < zero { -mag } else { mag }
    }

    /// Return the value directly between the start and end values.
    ///
    /// # Examples
    ///
    /// ```
    /// use nannou::geom::Range;
    ///
    /// assert_eq!(Range::new(-5.0, 5.0).middle(), 0.0);
    /// assert_eq!(Range::new(5.0, -5.0).middle(), 0.0);
    /// assert_eq!(Range::new(10.0, 15.0).middle(), 12.5);
    /// assert_eq!(Range::new(20.0, 40.0).middle(), 30.0);
    /// assert_eq!(Range::new(20.0, -40.0).middle(), -10.0);
    /// ```
    pub fn middle(&self) -> S {
        (self.end + self.start) / two()
    }

    /// The current range with its start and end values swapped.
    ///
    /// # Examples
    ///
    /// ```
    /// use nannou::geom::Range;
    ///
    /// assert_eq!(Range::new(-5.0, 5.0).invert(), Range::new(5.0, -5.0));
    /// assert_eq!(Range::new(-10.0, 10.0).invert(), Range::new(10.0, -10.0));
    /// assert_eq!(Range::new(0.0, 7.25).invert(), Range::new(7.25, 0.0));
    /// assert_eq!(Range::new(5.0, 1.0).invert(), Range::new(1.0, 5.0));
    /// ```
    pub fn invert(self) -> Self {
        Range { start: self.end, end: self.start }
    }

    /// Map the given scalar from `Self` to some other given `Range`.
    ///
    /// # Examples
    ///
    /// ```
    /// use nannou::geom::Range;
    ///
    /// let a = Range::new(0.0, 5.0);
    ///
    /// let b = Range::new(0.0, 10.0);
    /// assert_eq!(a.map_value(2.5, &b), 5.0);
    /// assert_eq!(a.map_value(0.0, &b), 0.0);
    /// assert_eq!(a.map_value(5.0, &b), 10.0);
    /// assert_eq!(a.map_value(-5.0, &b), -10.0);
    /// assert_eq!(a.map_value(10.0, &b), 20.0);
    ///
    /// let c = Range::new(10.0, -10.0);
    /// assert_eq!(a.map_value(2.5, &c), 0.0);
    /// assert_eq!(a.map_value(0.0, &c), 10.0);
    /// assert_eq!(a.map_value(5.0, &c), -10.0);
    /// assert_eq!(a.map_value(-5.0, &c), 30.0);
    /// assert_eq!(a.map_value(10.0, &c), -30.0);
    /// ```
    pub fn map_value(&self, value: S, other: &Self) -> S {
        math::map_range(value, self.start, self.end, other.start, other.end)
    }

    /// Shift the `Range` start and end points by a given scalar.
    ///
    /// # Examples
    ///
    /// ```
    /// use nannou::geom::Range;
    ///
    /// assert_eq!(Range::new(0.0, 5.0).shift(5.0), Range::new(5.0, 10.0));
    /// assert_eq!(Range::new(0.0, 5.0).shift(-5.0), Range::new(-5.0, 0.0));
    /// assert_eq!(Range::new(5.0, -5.0).shift(-5.0), Range::new(0.0, -10.0));
    /// ```<commit_msg>Add Range::lerp method<commit_after>//! A type for working with one-dimensional ranges.

use geom::DefaultScalar;
use math::{self, BaseNum, two};
use math::num_traits::{Float, One, Zero};
use std::ops::Neg;

/// Some start and end position along a single axis.
///
/// As an example, a **Rect** is made up of two **Range**s; one along the *x* axis, and one along
/// the *y* axis.
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
pub struct Range<S = DefaultScalar> {
    /// The start of some `Range` along an axis.
    pub start: S,
    /// The end of some `Range` along an axis.
    pub end: S,
}

/// Represents either the **Start** or **End** **Edge** of a **Range**.
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub enum Edge {
    /// The beginning of a **Range**.
    Start,
    /// The end of a **Range**.
    End,
}

/// Describes alignment along a range.
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub enum Align { Start, Middle, End }

impl<S> Range<S>
where
    S: BaseNum,
{
    /// Construct a new `Range` from a given range, i.e. `Range::new(start, end)`.
    ///
    /// # Examples
    ///
    /// ```
    /// use nannou::geom::Range;
    ///
    /// assert_eq!(Range { start: 0.0, end: 10.0 }, Range::new(0.0, 10.0));
    /// ```
    pub fn new(start: S, end: S) -> Self {
        Range {
            start: start,
            end: end,
        }
    }

    /// Construct a new `Range` from a given length and its centered position.
    ///
    /// # Examples
    ///
    /// ```
    /// use nannou::geom::Range;
    ///
    /// assert_eq!(Range::new(0.0, 10.0), Range::from_pos_and_len(5.0, 10.0));
    /// assert_eq!(Range::new(-5.0, 1.0), Range::from_pos_and_len(-2.0, 6.0));
    /// assert_eq!(Range::new(-100.0, 200.0), Range::from_pos_and_len(50.0, 300.0));
    /// ```
    pub fn from_pos_and_len(pos: S, len: S) -> Self {
        let half_len = len / two();
        let start = pos - half_len;
        let end = pos + half_len;
        Range::new(start, end)
    }

    /// The `start` value subtracted from the `end` value.
    ///
    /// # Examples
    ///
    /// ```
    /// use nannou::geom::Range;
    ///
    /// assert_eq!(Range::new(-5.0, 5.0).magnitude(), 10.0);
    /// assert_eq!(Range::new(5.0, -5.0).magnitude(), -10.0);
    /// assert_eq!(Range::new(15.0, 10.0).magnitude(), -5.0);
    /// ```
    pub fn magnitude(&self) -> S {
        self.end - self.start
    }

    /// The absolute length of the Range aka the absolute magnitude.
    ///
    /// # Examples
    ///
    /// ```
    /// use nannou::geom::Range;
    ///
    /// assert_eq!(Range::new(-5.0, 5.0).len(), 10.0);
    /// assert_eq!(Range::new(5.0, -5.0).len(), 10.0);
    /// assert_eq!(Range::new(15.0, 10.0).len(), 5.0);
    /// ```
    pub fn len(&self) -> S
    where
        S: Neg<Output=S>,
    {
        let mag = self.magnitude();
        let zero = S::zero();
        if mag < zero { -mag } else { mag }
    }

    /// Return the value directly between the start and end values.
    ///
    /// # Examples
    ///
    /// ```
    /// use nannou::geom::Range;
    ///
    /// assert_eq!(Range::new(-5.0, 5.0).middle(), 0.0);
    /// assert_eq!(Range::new(5.0, -5.0).middle(), 0.0);
    /// assert_eq!(Range::new(10.0, 15.0).middle(), 12.5);
    /// assert_eq!(Range::new(20.0, 40.0).middle(), 30.0);
    /// assert_eq!(Range::new(20.0, -40.0).middle(), -10.0);
    /// ```
    pub fn middle(&self) -> S {
        (self.end + self.start) / two()
    }

    /// The current range with its start and end values swapped.
    ///
    /// # Examples
    ///
    /// ```
    /// use nannou::geom::Range;
    ///
    /// assert_eq!(Range::new(-5.0, 5.0).invert(), Range::new(5.0, -5.0));
    /// assert_eq!(Range::new(-10.0, 10.0).invert(), Range::new(10.0, -10.0));
    /// assert_eq!(Range::new(0.0, 7.25).invert(), Range::new(7.25, 0.0));
    /// assert_eq!(Range::new(5.0, 1.0).invert(), Range::new(1.0, 5.0));
    /// ```
    pub fn invert(self) -> Self {
        Range { start: self.end, end: self.start }
    }

    /// Map the given scalar from `Self` to some other given `Range`.
    ///
    /// # Examples
    ///
    /// ```
    /// use nannou::geom::Range;
    ///
    /// let a = Range::new(0.0, 5.0);
    ///
    /// let b = Range::new(0.0, 10.0);
    /// assert_eq!(a.map_value(2.5, &b), 5.0);
    /// assert_eq!(a.map_value(0.0, &b), 0.0);
    /// assert_eq!(a.map_value(5.0, &b), 10.0);
    /// assert_eq!(a.map_value(-5.0, &b), -10.0);
    /// assert_eq!(a.map_value(10.0, &b), 20.0);
    ///
    /// let c = Range::new(10.0, -10.0);
    /// assert_eq!(a.map_value(2.5, &c), 0.0);
    /// assert_eq!(a.map_value(0.0, &c), 10.0);
    /// assert_eq!(a.map_value(5.0, &c), -10.0);
    /// assert_eq!(a.map_value(-5.0, &c), 30.0);
    /// assert_eq!(a.map_value(10.0, &c), -30.0);
    /// ```
    pub fn map_value(&self, value: S, other: &Self) -> S {
        math::map_range(value, self.start, self.end, other.start, other.end)
    }

    /// Interpolates the **Range** using the given `weight`.
    ///
    /// # Examples
    ///
    /// ```
    /// use nannou::geom::Range;
    ///
    /// let r = Range::new(-5.0, 5.0);
    /// assert_eq!(r.lerp(0.0), -5.0);
    /// assert_eq!(r.lerp(1.0), 5.0);
    /// assert_eq!(r.lerp(0.5), 0.0);
    /// ```
    pub fn lerp(&self, amount: S) -> S {
        self.start + ((self.end - self.start) * amount)
    }

    /// Shift the `Range` start and end points by a given scalar.
    ///
    /// # Examples
    ///
    /// ```
    /// use nannou::geom::Range;
    ///
    /// assert_eq!(Range::new(0.0, 5.0).shift(5.0), Range::new(5.0, 10.0));
    /// assert_eq!(Range::new(0.0, 5.0).shift(-5.0), Range::new(-5.0, 0.0));
    /// assert_eq!(Range::new(5.0, -5.0).shift(-5.0), Range::new(0.0, -10.0));
    /// ```
{'fraction_non_alphanumeric': 0.2449215965787598, 'fraction_numerical': 0.04775481111903065, 'mean_word_length': 1.9193758127438232, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 26, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1730114', 'n_tokens_mistral': 4476, 'n_tokens_neox': 4300, 'n_words': 942}