AC-Vector 2.0.0 → 2.1.0
raw patch · 6 files changed
+273/−5 lines, 6 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Data.BoundingBox.B1: BBox1 :: Range -> BBox1
+ Data.BoundingBox.B1: bounds :: Vector1 -> Vector1 -> BBox1
+ Data.BoundingBox.B1: instance Eq BBox1
+ Data.BoundingBox.B1: instance Show BBox1
+ Data.BoundingBox.B1: isect :: BBox1 -> BBox1 -> Maybe BBox1
+ Data.BoundingBox.B1: max_bound :: BBox1 -> Vector1
+ Data.BoundingBox.B1: min_bound :: BBox1 -> Vector1
+ Data.BoundingBox.B1: newtype BBox1
+ Data.BoundingBox.B1: range :: BBox1 -> Range
+ Data.BoundingBox.B1: union :: BBox1 -> BBox1 -> BBox1
+ Data.BoundingBox.B1: within_bounds :: Vector1 -> BBox1 -> Bool
+ Data.BoundingBox.B2: BBox2 :: !!Scalar -> !!Scalar -> !!Scalar -> !!Scalar -> BBox2
+ Data.BoundingBox.B2: bounds :: Vector2 -> Vector2 -> BBox2
+ Data.BoundingBox.B2: data BBox2
+ Data.BoundingBox.B2: instance Eq BBox2
+ Data.BoundingBox.B2: instance Show BBox2
+ Data.BoundingBox.B2: isect :: BBox2 -> BBox2 -> Maybe BBox2
+ Data.BoundingBox.B2: maxX :: BBox2 -> !!Scalar
+ Data.BoundingBox.B2: maxY :: BBox2 -> !!Scalar
+ Data.BoundingBox.B2: max_bound :: BBox2 -> Vector2
+ Data.BoundingBox.B2: minX :: BBox2 -> !!Scalar
+ Data.BoundingBox.B2: minY :: BBox2 -> !!Scalar
+ Data.BoundingBox.B2: min_bound :: BBox2 -> Vector2
+ Data.BoundingBox.B2: rangeX :: BBox2 -> Range
+ Data.BoundingBox.B2: rangeXY :: Range -> Range -> BBox2
+ Data.BoundingBox.B2: rangeY :: BBox2 -> Range
+ Data.BoundingBox.B2: union :: BBox2 -> BBox2 -> BBox2
+ Data.BoundingBox.B2: within_bounds :: Vector2 -> BBox2 -> Bool
+ Data.BoundingBox.B3: BBox3 :: !!Scalar -> !!Scalar -> !!Scalar -> !!Scalar -> !!Scalar -> !!Scalar -> BBox3
+ Data.BoundingBox.B3: bounds :: Vector3 -> Vector3 -> BBox3
+ Data.BoundingBox.B3: data BBox3
+ Data.BoundingBox.B3: instance Eq BBox3
+ Data.BoundingBox.B3: instance Show BBox3
+ Data.BoundingBox.B3: isect :: BBox3 -> BBox3 -> Maybe BBox3
+ Data.BoundingBox.B3: maxX :: BBox3 -> !!Scalar
+ Data.BoundingBox.B3: maxY :: BBox3 -> !!Scalar
+ Data.BoundingBox.B3: maxZ :: BBox3 -> !!Scalar
+ Data.BoundingBox.B3: max_bound :: BBox3 -> Vector3
+ Data.BoundingBox.B3: minX :: BBox3 -> !!Scalar
+ Data.BoundingBox.B3: minY :: BBox3 -> !!Scalar
+ Data.BoundingBox.B3: minZ :: BBox3 -> !!Scalar
+ Data.BoundingBox.B3: min_bound :: BBox3 -> Vector3
+ Data.BoundingBox.B3: rangeX :: BBox3 -> Range
+ Data.BoundingBox.B3: rangeXYZ :: Range -> Range -> Range -> BBox3
+ Data.BoundingBox.B3: rangeY :: BBox3 -> Range
+ Data.BoundingBox.B3: rangeZ :: BBox3 -> Range
+ Data.BoundingBox.B3: union :: BBox3 -> BBox3 -> BBox3
+ Data.BoundingBox.B3: within_bounds :: Vector3 -> BBox3 -> Bool
+ Data.BoundingBox.B4: BBox4 :: !!Scalar -> !!Scalar -> !!Scalar -> !!Scalar -> !!Scalar -> !!Scalar -> !!Scalar -> !!Scalar -> BBox4
+ Data.BoundingBox.B4: bounds :: Vector4 -> Vector4 -> BBox4
+ Data.BoundingBox.B4: data BBox4
+ Data.BoundingBox.B4: instance Eq BBox4
+ Data.BoundingBox.B4: instance Show BBox4
+ Data.BoundingBox.B4: isect :: BBox4 -> BBox4 -> Maybe BBox4
+ Data.BoundingBox.B4: maxW :: BBox4 -> !!Scalar
+ Data.BoundingBox.B4: maxX :: BBox4 -> !!Scalar
+ Data.BoundingBox.B4: maxY :: BBox4 -> !!Scalar
+ Data.BoundingBox.B4: maxZ :: BBox4 -> !!Scalar
+ Data.BoundingBox.B4: max_bound :: BBox4 -> Vector4
+ Data.BoundingBox.B4: minW :: BBox4 -> !!Scalar
+ Data.BoundingBox.B4: minX :: BBox4 -> !!Scalar
+ Data.BoundingBox.B4: minY :: BBox4 -> !!Scalar
+ Data.BoundingBox.B4: minZ :: BBox4 -> !!Scalar
+ Data.BoundingBox.B4: min_bound :: BBox4 -> Vector4
+ Data.BoundingBox.B4: rangeW :: BBox4 -> Range
+ Data.BoundingBox.B4: rangeX :: BBox4 -> Range
+ Data.BoundingBox.B4: rangeXYZW :: Range -> Range -> Range -> Range -> BBox4
+ Data.BoundingBox.B4: rangeY :: BBox4 -> Range
+ Data.BoundingBox.B4: rangeZ :: BBox4 -> Range
+ Data.BoundingBox.B4: union :: BBox4 -> BBox4 -> BBox4
+ Data.BoundingBox.B4: within_bounds :: Vector4 -> BBox4 -> Bool
+ Data.BoundingBox.Range: Range :: !!Scalar -> !!Scalar -> Range
+ Data.BoundingBox.Range: bounds :: Scalar -> Scalar -> Range
+ Data.BoundingBox.Range: data Range
+ Data.BoundingBox.Range: instance Eq Range
+ Data.BoundingBox.Range: instance Show Range
+ Data.BoundingBox.Range: isect :: Range -> Range -> Maybe Range
+ Data.BoundingBox.Range: max_bound :: Range -> !!Scalar
+ Data.BoundingBox.Range: min_bound :: Range -> !!Scalar
+ Data.BoundingBox.Range: union :: Range -> Range -> Range
+ Data.BoundingBox.Range: within_bounds :: Scalar -> Range -> Bool
Files
- AC-Vector.cabal +11/−5
- Data/BoundingBox/B1.hs +38/−0
- Data/BoundingBox/B2.hs +57/−0
- Data/BoundingBox/B3.hs +64/−0
- Data/BoundingBox/B4.hs +72/−0
- Data/BoundingBox/Range.hs +31/−0
AC-Vector.cabal view
@@ -1,6 +1,6 @@ Cabal-Version: >= 1.6 Name: AC-Vector -Version: 2.0.0 +Version: 2.1.0 Stability: Experimental Synopsis: Efficient geometric vectors and transformations. @@ -10,10 +10,11 @@ with @Double@ fields, with seperate types for each size of vector, and a type class for handling vectors generally. - Existing API has been rearranged. Now supports 4D vectors - and linear transformations. + Now includes \"bounding box\" types, useful for graphical work. + (Note that this package itself has no graphics facilities as + such. It just provides data structures useful for graphics.) -Category: Data, Math, Numerical +Category: Data, Math, Numerical, Graphics License: BSD3 License-file: License.txt Author: Andrew Coppin @@ -33,6 +34,11 @@ Data.Vector.Transform.T1, Data.Vector.Transform.T2, Data.Vector.Transform.T3, - Data.Vector.Transform.T4 + Data.Vector.Transform.T4, + Data.BoundingBox.Range, + Data.BoundingBox.B1, + Data.BoundingBox.B2, + Data.BoundingBox.B3, + Data.BoundingBox.B4 Build-Depends: base >= 4 && < 5 HS-Source-Dirs: .
+ Data/BoundingBox/B1.hs view
@@ -0,0 +1,38 @@+{- | + This module provides the 'BBox1' type (mainly for completeness). +-} + +module Data.BoundingBox.B1 where + +import Data.Vector.Class +import Data.Vector.V1 +import Data.BoundingBox.Range as R + +-- | The 'BBox1' type is basically a 'Range', but all the operations over it work with 'Vector1' (which is really 'Scalar'). While it's called a bounding /box/, a 1-dimensional box is in truth a simple line interval, just like 'Range'. +newtype BBox1 = BBox1 {range :: Range} deriving (Eq, Show) + +-- | Given two vectors, construct a bounding box (swapping the endpoints if necessary). +bounds :: Vector1 -> Vector1 -> BBox1 +bounds (Vector1 xa) (Vector1 xb) = BBox1 $ R.bounds xa xb + +-- | Test whether a 'Vector1' lies within a 'BBox1'. +within_bounds :: Vector1 -> BBox1 -> Bool +within_bounds (Vector1 x) (BBox1 r) = x `R.within_bounds` r + +-- | Return the minimum endpoint for a 'BBox1'. +min_bound :: BBox1 -> Vector1 +min_bound = Vector1 . R.min_bound . range + +-- | Return the maximum endpoint for a 'BBox1'. +max_bound :: BBox1 -> Vector1 +max_bound = Vector1 . R.max_bound . range + +-- | Take the union of two 'BBox1' values. The result is a new 'BBox1' that contains all the points the original boxes contained, plus any extra space between them. +union :: BBox1 -> BBox1 -> BBox1 +union (BBox1 r0) (BBox1 r1) = BBox1 (r0 `R.union` r1) + +-- | Take the intersection of two 'BBox1' values. If the boxes do not overlap, return 'Nothing'. Otherwise return a 'BBox1' containing only the points common to both argument boxes. +isect :: BBox1 -> BBox1 -> Maybe BBox1 +isect (BBox1 r0) (BBox1 r1) = do + r <- (r0 `R.isect` r1) + return (BBox1 r)
+ Data/BoundingBox/B2.hs view
@@ -0,0 +1,57 @@+{- | + This module provides the 'BBox2' type for 2-dimensional bounding boxes. +-} + +module Data.BoundingBox.B2 where + +import Data.Vector.Class +import Data.Vector.V2 +import Data.BoundingBox.Range as R + +-- | A 'BBox2' is a 2D bounding box (aligned to the coordinate axies). +data BBox2 = BBox2 {minX, minY, maxX, maxY :: {-# UNPACK #-} !Scalar} deriving (Eq, Show) + +-- | Return the X-range that this bounding box covers. +rangeX :: BBox2 -> Range +rangeX b = Range (minX b) (maxX b) + +-- | Return the Y-range that this bounding box covers. +rangeY :: BBox2 -> Range +rangeY b = Range (minY b) (maxY b) + +-- | Given ranges for each coordinate axis, construct a bounding box. +rangeXY :: Range -> Range -> BBox2 +rangeXY (Range x0 x1) (Range y0 y1) = BBox2 x0 y0 x1 y1 + +-- | Given a pair of corner points, construct a bounding box. (The points must be from opposite corners, but it doesn't matter /which/ corners nor which order they are given in.) +bounds :: Vector2 -> Vector2 -> BBox2 +bounds (Vector2 xa ya) (Vector2 xb yb) = BBox2 (min xa xb) (min ya yb) (max xa xb) (max ya yb) + +-- | Test whether a given 2D vector is inside this bounding box. +within_bounds :: Vector2 -> BBox2 -> Bool +within_bounds (Vector2 x y) b = + x `R.within_bounds` (rangeX b) && + y `R.within_bounds` (rangeY b) + +-- | Return the minimum values for both coordinates. (In usual 2D space, the bottom-left corner point.) +min_bound :: BBox2 -> Vector2 +min_bound (BBox2 x0 y0 x1 y1) = Vector2 x0 y0 + +-- | Return the maximum values for both coordinates. (In usual 2D space, the top-right corner point.) +max_bound :: BBox2 -> Vector2 +max_bound (BBox2 x0 y0 x1 y1) = Vector2 x1 y1 + +-- | Take the union of two bounding boxes. The result is a new bounding box that contains all the points the original boxes contained, plus any extra space between them. +union :: BBox2 -> BBox2 -> BBox2 +union b0 b1 = + let + rx = (rangeX b0) `R.union` (rangeX b1) + ry = (rangeY b0) `R.union` (rangeY b1) + in rangeXY rx ry + +-- | Take the intersection of two bounding boxes. If the boxes do not overlap, return 'Nothing'. Otherwise return a new bounding box containing only the points common to both argument boxes. +isect :: BBox2 -> BBox2 -> Maybe BBox2 +isect b0 b1 = do + rx <- (rangeX b0) `R.isect` (rangeX b1) + ry <- (rangeY b0) `R.isect` (rangeY b1) + return (rangeXY rx ry)
+ Data/BoundingBox/B3.hs view
@@ -0,0 +1,64 @@+{- | + This module provides the 'BBox3' type for 3-dimensional bounding boxes (\"bounding volumes\"). +-} + +module Data.BoundingBox.B3 where + +import Data.Vector.Class +import Data.Vector.V3 +import Data.BoundingBox.Range as R + +-- | A 'BBox3' is a 3D bounding box (aligned to the coordinate axies). +data BBox3 = BBox3 {minX, minY, minZ, maxX, maxY, maxZ :: {-# UNPACK #-} !Scalar} deriving (Eq, Show) + +-- | Return the X-range that this bounding box covers. +rangeX :: BBox3 -> Range +rangeX b = Range (minX b) (maxX b) + +-- | Return the Y-range that this bounding box covers. +rangeY :: BBox3 -> Range +rangeY b = Range (minY b) (maxY b) + +-- | Return the Z-range that this bounding box covers. +rangeZ :: BBox3 -> Range +rangeZ b = Range (minZ b) (maxZ b) + +-- | Given ranges for each coordinate axis, construct a bounding box. +rangeXYZ :: Range -> Range -> Range -> BBox3 +rangeXYZ (Range x0 x1) (Range y0 y1) (Range z0 z1) = BBox3 x0 y0 z0 x1 y1 z1 + +-- | Given a pair of corner points, construct a bounding box. (The points must be from opposite corners, but it doesn't matter /which/ corners nor which order they are given in.) +bounds :: Vector3 -> Vector3 -> BBox3 +bounds (Vector3 xa ya za) (Vector3 xb yb zb) = BBox3 (min xa xb) (min ya yb) (min za zb) (max xa xb) (max ya yb) (max za zb) + +-- | Test whether a given 3D vector is inside this bounding box. +within_bounds :: Vector3 -> BBox3 -> Bool +within_bounds (Vector3 x y z) b = + x `R.within_bounds` (rangeX b) && + y `R.within_bounds` (rangeY b) && + z `R.within_bounds` (rangeZ b) + +-- | Return the minimum values for all coordinates. +min_bound :: BBox3 -> Vector3 +min_bound (BBox3 x0 y0 z0 x1 y1 z1) = Vector3 x0 y0 z0 + +-- | Return the maximum values for all coordinates. +max_bound :: BBox3 -> Vector3 +max_bound (BBox3 x0 y0 z0 x1 y1 z1) = Vector3 x1 y1 z1 + +-- | Take the union of two bounding boxes. The result is a new bounding box that contains all the points the original boxes contained, plus any extra space between them. +union :: BBox3 -> BBox3 -> BBox3 +union b0 b1 = + let + rx = (rangeX b0) `R.union` (rangeX b1) + ry = (rangeY b0) `R.union` (rangeY b1) + rz = (rangeZ b0) `R.union` (rangeZ b1) + in rangeXYZ rx ry rz + +-- | Take the intersection of two bounding boxes. If the boxes do not overlap, return 'Nothing'. Otherwise return a new bounding box containing only the points common to both argument boxes. +isect :: BBox3 -> BBox3 -> Maybe BBox3 +isect b0 b1 = do + rx <- (rangeX b0) `R.isect` (rangeX b1) + ry <- (rangeY b0) `R.isect` (rangeY b1) + rz <- (rangeZ b0) `R.isect` (rangeZ b1) + return (rangeXYZ rx ry rz)
+ Data/BoundingBox/B4.hs view
@@ -0,0 +1,72 @@+{- | + This module provides the 'BBox4' type for 4-dimensional bounding boxes (bounding hyper-volumes\). +-} + +module Data.BoundingBox.B4 where + +import Data.Vector.Class +import Data.Vector.V4 +import Data.BoundingBox.Range as R + +-- | A 'BBox4' is a 4D bounding box (aligned to the coordinate axies). +data BBox4 = BBox4 {minX, minY, minZ, minW, maxX, maxY, maxZ, maxW :: {-# UNPACK #-} !Scalar} deriving (Eq, Show) + +-- | Return the X-range that this bounding box covers. +rangeX :: BBox4 -> Range +rangeX b = Range (minX b) (maxX b) + +-- | Return the Y-range that this bounding box covers. +rangeY :: BBox4 -> Range +rangeY b = Range (minY b) (maxY b) + +-- | Return the Z-range that this bounding box covers. +rangeZ :: BBox4 -> Range +rangeZ b = Range (minZ b) (maxZ b) + +-- | Return the W-range (4th coordinate) that this bounding box covers. +rangeW :: BBox4 -> Range +rangeW b = Range (minW b) (maxW b) + +-- | Given ranges for each coordinate axis, construct a bounding box. +rangeXYZW :: Range -> Range -> Range -> Range -> BBox4 +rangeXYZW (Range x0 x1) (Range y0 y1) (Range z0 z1) (Range w0 w1) = BBox4 x0 y0 z0 w0 x1 y1 z1 w1 + +-- | Given a pair of corner points, construct a bounding box. (The points must be from opposite corners, but it doesn't matter /which/ corners nor which order they are given in.) +bounds :: Vector4 -> Vector4 -> BBox4 +bounds (Vector4 xa ya za wa) (Vector4 xb yb zb wb) = + BBox4 (min xa xb) (min ya yb) (min za zb) (min wa wb) (max xa xb) (max ya yb) (max za zb) (max wa wb) + +-- | Test whether a given 4D vector is inside this bounding box. +within_bounds :: Vector4 -> BBox4 -> Bool +within_bounds (Vector4 x y z w) b = + x `R.within_bounds` (rangeX b) && + y `R.within_bounds` (rangeY b) && + z `R.within_bounds` (rangeZ b) && + w `R.within_bounds` (rangeW b) + +-- | Return the minimum values for all coordinates. +min_bound :: BBox4 -> Vector4 +min_bound (BBox4 x0 y0 z0 w0 x1 y1 z1 w1) = Vector4 x0 y0 z0 w0 + +-- | Return the maximum values for all coordinates. +max_bound :: BBox4 -> Vector4 +max_bound (BBox4 x0 y0 z0 w0 x1 y1 z1 w1) = Vector4 x1 y1 z1 w1 + +-- | Take the union of two bounding boxes. The result is a new bounding box that contains all the points the original boxes contained, plus any extra space between them. +union :: BBox4 -> BBox4 -> BBox4 +union b0 b1 = + let + rx = (rangeX b0) `R.union` (rangeX b1) + ry = (rangeY b0) `R.union` (rangeY b1) + rz = (rangeZ b0) `R.union` (rangeZ b1) + rw = (rangeW b0) `R.union` (rangeW b1) + in rangeXYZW rx ry rz rw + +-- | Take the intersection of two bounding boxes. If the boxes do not overlap, return 'Nothing'. Otherwise return a new bounding box containing only the points common to both argument boxes. +isect :: BBox4 -> BBox4 -> Maybe BBox4 +isect b0 b1 = do + rx <- (rangeX b0) `R.isect` (rangeX b1) + ry <- (rangeY b0) `R.isect` (rangeY b1) + rz <- (rangeZ b0) `R.isect` (rangeZ b1) + rw <- (rangeW b0) `R.isect` (rangeW b1) + return (rangeXYZW rx ry rz rw)
+ Data/BoundingBox/Range.hs view
@@ -0,0 +1,31 @@+{- | + 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_bound, max_bound :: {-# 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. +bounds :: Scalar -> Scalar -> Range +bounds xa xb = Range (min xa xb) (max xa xb) + +-- | 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