{- |
  This module provides the 'Range' type and several functions for working with ranges.
-}

module Data.BoundingBox.Range where

import Data.Vector.Class

{- |
  A 'Range' represents a continuous interval between two 'Scalar' endpoints.
-}
data Range = Range {Range -> Scalar
min_point, Range -> Scalar
max_point :: {-# UNPACK #-} !Scalar} deriving (Range -> Range -> Bool
(Range -> Range -> Bool) -> (Range -> Range -> Bool) -> Eq Range
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Range -> Range -> Bool
== :: Range -> Range -> Bool
$c/= :: Range -> Range -> Bool
/= :: Range -> Range -> Bool
Eq, Int -> Range -> ShowS
[Range] -> ShowS
Range -> String
(Int -> Range -> ShowS)
-> (Range -> String) -> ([Range] -> ShowS) -> Show Range
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Range -> ShowS
showsPrec :: Int -> Range -> ShowS
$cshow :: Range -> String
show :: Range -> String
$cshowList :: [Range] -> ShowS
showList :: [Range] -> ShowS
Show)

-- | Given two 'Scalar's, construct a 'Range' (swapping the endpoints if necessary so that they are in the correct order.
bound_corners :: Scalar -> Scalar -> Range
bound_corners :: Scalar -> Scalar -> Range
bound_corners Scalar
xa Scalar
xb = Scalar -> Scalar -> Range
Range (Scalar -> Scalar -> Scalar
forall a. Ord a => a -> a -> a
min Scalar
xa Scalar
xb) (Scalar -> Scalar -> Scalar
forall a. Ord a => a -> a -> a
max Scalar
xa Scalar
xb)

-- | Find the bounds of a list of points. (Throws an exception if the list is empty.)
bound_points :: [Scalar] -> Range
bound_points :: [Scalar] -> Range
bound_points [Scalar]
xs = Scalar -> Scalar -> Range
Range ([Scalar] -> Scalar
forall a. Ord a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
minimum [Scalar]
xs) ([Scalar] -> Scalar
forall a. Ord a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum [Scalar]
xs)

-- | Test whether a given 'Scalar' falls within a particular 'Range'.
within_bounds :: Scalar -> Range -> Bool
within_bounds :: Scalar -> Range -> Bool
within_bounds Scalar
x (Range Scalar
x0 Scalar
x1) = Scalar
x0 Scalar -> Scalar -> Bool
forall a. Ord a => a -> a -> Bool
<= Scalar
x Bool -> Bool -> Bool
&& Scalar
x Scalar -> Scalar -> Bool
forall a. Ord a => a -> a -> Bool
<= Scalar
x1

-- | Take the union of two ranges. The resulting 'Range' contains all points that the original ranges contained, plus any points between them (if the original ranges don't overlap).
union :: Range -> Range -> Range
union :: Range -> Range -> Range
union (Range Scalar
ll Scalar
lh) (Range Scalar
rl Scalar
rh) = Scalar -> Scalar -> Range
Range (Scalar -> Scalar -> Scalar
forall a. Ord a => a -> a -> a
min Scalar
ll Scalar
rl) (Scalar -> Scalar -> Scalar
forall a. Ord a => a -> a -> a
max Scalar
lh Scalar
rh)

-- | Take the intersection of two ranges. If the ranges do not overlap, the intersection is empty, and 'Nothing' is returned. (This is a good way to check whether two ranges overlap or not.) Otherwise a new 'Range' is returned that contains only the points common to both ranges.
isect :: Range -> Range -> Maybe Range
isect :: Range -> Range -> Maybe Range
isect (Range Scalar
ll Scalar
lh) (Range Scalar
rl Scalar
rh) =
  let
    nl :: Scalar
nl = Scalar -> Scalar -> Scalar
forall a. Ord a => a -> a -> a
max Scalar
ll Scalar
rl
    nh :: Scalar
nh = Scalar -> Scalar -> Scalar
forall a. Ord a => a -> a -> a
min Scalar
lh Scalar
rh
  in  if Scalar
nl Scalar -> Scalar -> Bool
forall a. Ord a => a -> a -> Bool
> Scalar
nh then Maybe Range
forall a. Maybe a
Nothing else Range -> Maybe Range
forall a. a -> Maybe a
Just (Scalar -> Scalar -> Range
Range Scalar
nl Scalar
nh)

-- | Efficiently compute the union of a list of ranges.
unions :: [Range] -> Range
unions :: [Range] -> Range
unions [Range]
rs = Scalar -> Scalar -> Range
Range ([Scalar] -> Scalar
forall a. Ord a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
minimum ([Scalar] -> Scalar) -> [Scalar] -> Scalar
forall a b. (a -> b) -> a -> b
$ (Range -> Scalar) -> [Range] -> [Scalar]
forall a b. (a -> b) -> [a] -> [b]
map Range -> Scalar
min_point [Range]
rs) ([Scalar] -> Scalar
forall a. Ord a => [a] -> a
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum ([Scalar] -> Scalar) -> [Scalar] -> Scalar
forall a b. (a -> b) -> a -> b
$ (Range -> Scalar) -> [Range] -> [Scalar]
forall a b. (a -> b) -> [a] -> [b]
map Range -> Scalar
max_point [Range]
rs)