{- | 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 {min_point, max_point :: {-# UNPACK #-} !Scalar} deriving (Eq, 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 xa xb = Range (min xa xb) (max xa xb) -- | Find the bounds of a list of points. (Throws an exception if the list is empty.) bound_points :: [Scalar] -> Range bound_points xs = Range (minimum xs) (maximum xs) -- | Test whether a given 'Scalar' falls within a particular 'Range'. within_bounds :: Scalar -> Range -> Bool within_bounds x (Range x0 x1) = x0 <= x && x <= 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 x00 x01) (Range x10 x11) = Range (min x00 x01) (max x01 x11) -- | 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 x00 x01) (Range x10 x11) = if x00 < x10 then if x10 < x01 then Just (Range x10 (min x01 x11)) else Nothing else if x00 < x11 then Just (Range x00 (min x01 x11)) else Nothing -- | Efficiently compute the union of a list of ranges. unions :: [Range] -> Range unions rs = Range (minimum $ map min_point rs) (maximum $ map max_point rs)