-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | (updated) Small geometry library for dealing with vectors and collision detection -- -- Updated original SG to work with modern GHC. A small geometry library -- for dealing with vectors, points, lines, simple shapes, and their -- various intersection tests. See also the SGdemo project -- (http://hackage.haskell.org/cgi-bin/hackage-scripts/package/SGdemo) -- for an example of using the module. @package SGplus @version 1.1 -- | The module with all the different type-classes for vectors. Generally, -- the main functions you might need from this function are: -- -- -- -- The rest of the functions are mainly just wiring necessary for other -- functions, but must be exported. -- -- As to the vector types, there are two methods to use this library. One -- is to use the types from the Data.SG.Vector.Basic library, -- which support basic vector operations. The other is to use the types -- from the Data.SG.Geometry.TwoDim and -- Data.SG.Geometry.ThreeDim modules, where a position vector is -- differentiated from a relative vector (to increase clarity of code, -- and help prevent errors such as adding two points together). Both -- systems can be used with various useful functions (involving lines -- too) from Data.SG.Geometry. module Data.SG.Vector -- | An isomorphism amongst vectors. Allows you to convert between two -- vectors that have the same dimensions. You will notice that all the -- instances reflect this. class IsomorphicVectors from to iso :: (IsomorphicVectors from to, Num a) => from a -> to a -- | The class that is implemented by all vectors. -- -- Minimal implementation: fromComponents class Foldable p => Coord p where getComponents = toList magSq = sum . map (\ x -> x * x) . getComponents dotProduct a b = sum $ zipWith (*) (getComponents a) (getComponents b) -- | Gets the components of the vector, in the order x, y (, z). getComponents :: (Coord p, Num a) => p a -> [a] -- | Re-constructs a vector from the list of coordinates. If there are too -- few, the rest will be filled with zeroes. If there are too many, the -- latter ones are ignored. fromComponents :: (Coord p, Num a) => [a] -> p a -- | Gets the magnitude squared of the vector. This should be fast for -- repeated calls on Rel2' and Rel3', which cache this -- value. magSq :: (Coord p, Num a) => p a -> a -- | Computes the dot product of the two vectors. dotProduct :: (Coord p, Num a) => p a -> p a -> a -- | This class is implemented by all 2D and 3D vectors, so getX -- gets the X co-ordinate of both 2D and 3D vectors. class Coord p => Coord2 p getX :: Coord2 p => p a -> a getY :: Coord2 p => p a -> a -- | This class is implemented by all 3D vectors. To get the X and Y -- components, use getX and getY from Coord2. class Coord2 p => Coord3 p getZ :: Coord3 p => p a -> a -- | The origin/all-zero vector (can be used with any vector type you like) origin :: (Coord p, Num a) => p a -- | Gets the magnitude of the given vector. mag :: (Coord p, Floating a) => p a -> a -- | Scales the vector so that it has length 1. Note that due to -- floating-point inaccuracies and so on, mag (unitVector v) will not -- necessarily equal 1, but it should be very close. If an all-zero -- vector is passed, the same will be returned. -- -- This function should be very fast when called on Rel2' and -- Rel3'; vectors that are already unit vectors (no processing is -- done). unitVector :: (Coord p, VectorNum p, Ord a, Floating a) => p a -> p a -- | Gets the average vector of all the given vectors. Essentially it is -- the sum of the vectors, divided by the length, so averageVec -- [Point2 (-3, 0), Point2 (5,0)] will give Point2 (1,0). -- If the list is empty, the all-zero vector is returned. averageVec :: (Fractional a, VectorNum p, Num (p a)) => [p a] -> p a -- | Like averageVec composed with unitVector -- gets the average of the -- vectors in the list, and normalises the length. If the list is empty, -- the all-zero vector is returned (which is therefore not a unit -- vector). Similarly, if the average of all the vectors is all-zero, the -- all-zero vector will be returned. averageUnitVec :: (Floating a, Ord a, Coord p, VectorNum p, Num (p a)) => [p a] -> p a -- | Works out if the two vectors are in the same direction (to within a -- small tolerance). sameDirection :: (VectorNum rel, Coord rel, Ord a, Floating a) => rel a -> rel a -> Bool -- | Gives back the vector (first parameter), translated onto given axis -- (second parameter). Note that the scale is always distance, not -- related to the size of the axis vector. projectOnto :: (Floating a, Ord a, VectorNum rel, Coord rel) => rel a -> rel a -> a -- | Projects the first parameter onto the given axes (X, Y), returning a -- point in terms of the new axes. projectOnto2 :: (Floating a, Ord a, VectorNum rel, Coord rel) => rel a -> (rel a, rel a) -> rel a -- | Gives back the point (first parameter), translated onto given axis -- (second parameter). Note that the scale is always distance, not -- related to the size of the axis vector. projectPointOnto :: (Floating a, Ord a, VectorNum rel, Coord rel, IsomorphicVectors pt rel) => pt a -> rel a -> a -- | Projects the point (first parameter) onto the given axes (X, Y), -- returning a point in terms of the new axes. projectPointOnto2 :: (Floating a, Ord a, VectorNum rel, Coord rel, IsomorphicVectors pt rel, Coord pt) => pt a -> (rel a, rel a) -> pt a -- | Works out the distance between two points. distFrom :: (VectorNum pt, Coord pt, Floating a) => pt a -> pt a -> a -- | A modified version of Functor and Applicative that adds -- the Num constraint on the result. You are unlikely to need to -- use this class much directly. Some vectors have Functor and -- Applicative instances anyway. class VectorNum f -- | Like fmap, but with a Num constraint. fmapNum1 :: (VectorNum f, Num b) => (a -> b) -> f a -> f b -- | Like liftA2, but with a Num constraint. fmapNum2 :: (VectorNum f, Num c) => (a -> b -> c) -> f a -> f b -> f c -- | Like fmapNum1, but can only be used if you won't change the -- magnitude: fmapNum1inv :: (VectorNum f, Num a) => (a -> a) -> f a -> f a -- | Like pure (or fromInteger) but with a Num -- constraint. simpleVec :: (VectorNum f, Num a) => a -> f a instance Data.SG.Vector.IsomorphicVectors v v -- | Some types that are very basic vectors. Most of the use that can be -- made of the vectors is in their type-class instances, which support a -- powerful set of operations. For example: -- --
--   fmap (*3) v -- Scales vector v by 3
--   pure 0 -- Creates a vector filled with zeroes
--   v + w -- Adds two vectors (there is a 'Num' instance, basically)
--   
-- -- Plus all the instances for the classes in Data.SG.Vector, which -- allows you to use getX and so on. -- -- You will probably want to create more friendly type synonyms, such as: -- --
--   type Vector2 = Pair Double
--   type Vector3 = Triple Double
--   type Line2 = LinePair Double
--   type Line3 = LineTriple Double
--   
module Data.SG.Vector.Basic -- | A pair, which acts as a 2D vector. newtype Pair a Pair :: (a, a) -> Pair a -- | A triple, which acts as a 3D vector. newtype Triple a Triple :: (a, a, a) -> Triple a -- | A quad, which acts as a 4D vector. newtype Quad a Quad :: (a, a, a, a) -> Quad a -- | A pair of (position vector, direction vector) to be used as a 2D line. newtype LinePair a LinePair :: (Pair a, Pair a) -> LinePair a -- | A pair of (position vector, direction vector) to be used as a 3D line. newtype LineTriple a LineTriple :: (Triple a, Triple a) -> LineTriple a instance GHC.Read.Read a => GHC.Read.Read (Data.SG.Vector.Basic.LineTriple a) instance GHC.Show.Show a => GHC.Show.Show (Data.SG.Vector.Basic.LineTriple a) instance GHC.Classes.Ord a => GHC.Classes.Ord (Data.SG.Vector.Basic.LineTriple a) instance GHC.Classes.Eq a => GHC.Classes.Eq (Data.SG.Vector.Basic.LineTriple a) instance GHC.Read.Read a => GHC.Read.Read (Data.SG.Vector.Basic.LinePair a) instance GHC.Show.Show a => GHC.Show.Show (Data.SG.Vector.Basic.LinePair a) instance GHC.Classes.Ord a => GHC.Classes.Ord (Data.SG.Vector.Basic.LinePair a) instance GHC.Classes.Eq a => GHC.Classes.Eq (Data.SG.Vector.Basic.LinePair a) instance GHC.Read.Read a => GHC.Read.Read (Data.SG.Vector.Basic.Quad a) instance GHC.Show.Show a => GHC.Show.Show (Data.SG.Vector.Basic.Quad a) instance GHC.Classes.Ord a => GHC.Classes.Ord (Data.SG.Vector.Basic.Quad a) instance GHC.Classes.Eq a => GHC.Classes.Eq (Data.SG.Vector.Basic.Quad a) instance GHC.Read.Read a => GHC.Read.Read (Data.SG.Vector.Basic.Triple a) instance GHC.Show.Show a => GHC.Show.Show (Data.SG.Vector.Basic.Triple a) instance GHC.Classes.Ord a => GHC.Classes.Ord (Data.SG.Vector.Basic.Triple a) instance GHC.Classes.Eq a => GHC.Classes.Eq (Data.SG.Vector.Basic.Triple a) instance GHC.Read.Read a => GHC.Read.Read (Data.SG.Vector.Basic.Pair a) instance GHC.Show.Show a => GHC.Show.Show (Data.SG.Vector.Basic.Pair a) instance GHC.Classes.Ord a => GHC.Classes.Ord (Data.SG.Vector.Basic.Pair a) instance GHC.Classes.Eq a => GHC.Classes.Eq (Data.SG.Vector.Basic.Pair a) instance Data.SG.Vector.VectorNum Data.SG.Vector.Basic.Pair instance Data.SG.Vector.VectorNum Data.SG.Vector.Basic.Triple instance Data.SG.Vector.VectorNum Data.SG.Vector.Basic.Quad instance (GHC.Show.Show a, GHC.Classes.Eq a, GHC.Num.Num a) => GHC.Num.Num (Data.SG.Vector.Basic.Pair a) instance (GHC.Show.Show a, GHC.Classes.Eq a, GHC.Num.Num a) => GHC.Num.Num (Data.SG.Vector.Basic.Triple a) instance (GHC.Show.Show a, GHC.Classes.Eq a, GHC.Num.Num a) => GHC.Num.Num (Data.SG.Vector.Basic.Quad a) instance GHC.Base.Applicative Data.SG.Vector.Basic.Pair instance Data.Foldable.Foldable Data.SG.Vector.Basic.Pair instance Data.Traversable.Traversable Data.SG.Vector.Basic.Pair instance GHC.Base.Applicative Data.SG.Vector.Basic.Triple instance Data.Foldable.Foldable Data.SG.Vector.Basic.Triple instance Data.Traversable.Traversable Data.SG.Vector.Basic.Triple instance GHC.Base.Applicative Data.SG.Vector.Basic.Quad instance Data.Foldable.Foldable Data.SG.Vector.Basic.Quad instance Data.Traversable.Traversable Data.SG.Vector.Basic.Quad instance GHC.Base.Functor Data.SG.Vector.Basic.Pair instance GHC.Base.Functor Data.SG.Vector.Basic.Triple instance GHC.Base.Functor Data.SG.Vector.Basic.Quad instance Data.SG.Vector.Coord Data.SG.Vector.Basic.Pair instance Data.SG.Vector.Coord2 Data.SG.Vector.Basic.Pair instance Data.SG.Vector.Coord Data.SG.Vector.Basic.Triple instance Data.SG.Vector.Coord2 Data.SG.Vector.Basic.Triple instance Data.SG.Vector.Coord3 Data.SG.Vector.Basic.Triple instance Data.SG.Vector.Coord Data.SG.Vector.Basic.Quad instance Data.SG.Vector.Coord2 Data.SG.Vector.Basic.Quad instance Data.SG.Vector.Coord3 Data.SG.Vector.Basic.Quad -- | This module has the type-class (and associated functions) for dealing -- with geometric systems of 2 or 3 dimensions. module Data.SG.Geometry -- | A geometry system, parameterised over points, relative (free) vectors, -- and lines. There are separate instances for two dimensions and for -- three dimensions. Each pair of type-class parameters is uniquely -- determined by the other parameter (i.e. by the dimensionality, and -- which vector type you are using). -- -- Minimal implementation: everything but scaleRel. class (VectorNum rel, Coord rel, Coord pt, IsomorphicVectors rel pt, IsomorphicVectors pt rel) => Geometry rel pt ln | rel -> pt ln, pt -> rel ln, ln -> rel pt where scaleRel a = fmapNum1 (* a) -- | Scales a relative (free) vector by the given amount. scaleRel :: (Geometry rel pt ln, Num a) => a -> rel a -> rel a -- | Adds a relative (free) vector to a given point. plusDir :: (Geometry rel pt ln, Num a, Eq a, Show a) => pt a -> rel a -> pt a -- | Determines the relative (free) vector to the first parameter -- from the second parameter. So: -- --
--   Point2 (1,8) `fromPt` Point2 (3,4) == Point2 (-2,3)
--   
fromPt :: (Geometry rel pt ln, Num a, Eq a, Show a) => pt a -> pt a -> rel a -- | Given a line, converts it back into its point and relative vector. It -- should always be the case that uncurry makeLine . getLineVecs -- is the identity function. getLineVecs :: (Geometry rel pt ln, Num a) => ln a -> (pt a, rel a) -- | Given a point and relative vector, creates a line. It should always be -- the case that uncurry makeLine . getLineVecs is the identity -- function. makeLine :: (Geometry rel pt ln, Num a) => pt a -> rel a -> ln a -- | Adds the negation of the relative (free) vector to the point. minusDir :: (Num a, Geometry rel pt ln, Eq a, Show a) => pt a -> rel a -> pt a -- | The flipped version of fromPt. toPt :: (Geometry rel pt ln, Num a, Eq a, Show a) => pt a -> pt a -> rel a -- | Gets the line from the first point, to the second point. lineTo :: (Num a, Geometry rel pt ln, Eq a, Show a) => pt a -> pt a -> ln a -- | The flipped version of lineTo. lineFrom :: (Num a, Geometry rel pt ln, Eq a, Show a) => pt a -> pt a -> ln a -- | Gets the point at the start of the line. getLineStart :: (Num a, Geometry rel pt ln) => ln a -> pt a -- | Gets the direction vector of the line. getLineDir :: (Num a, Geometry rel pt ln) => ln a -> rel a -- | Gets the point at the end of the line. getLineEnd :: (Geometry rel pt ln, Num a, Eq a, Show a) => ln a -> pt a -- | Alters the line to the given length, but with the same start point and -- direction. makeLength :: (Floating a, Ord a, Geometry rel pt ln) => a -> ln a -> ln a -- | Given a multiple of the direction vector (this is not -- distance unless the direction vector is a unit vector), calculates -- that point. alongLine :: (Num a, Geometry rel pt ln, Eq a, Show a) => a -> ln a -> pt a -- | Checks if the given point is on the given line (to within a small -- epsilon-tolerance). If it is, gives back the distance along the line -- (as a multiple of its direction vector) to the point in a Just -- wrapper. If the point is not on the line, Nothing is returned. distAlongLine :: (Geometry rel pt ln, Ord a, Floating a, Show a) => pt a -> ln a -> Maybe a -- | Checks if the given point is on the given line (to within a small -- epsilon-tolerance). isOnLine :: (Geometry rel pt ln, Ord a, Floating a, Show a) => pt a -> ln a -> Bool -- | Finds the nearest point on the line to the given point, and gives back -- its distance along the line (as a multiple of the direction vector). -- Since the nearest distance will be at a right-angle to the point, this -- is the same as projecting the point onto the line. nearestDistOnLine :: (Geometry rel pt ln, Ord a, Floating a, Eq a, Show a) => pt a -> ln a -> a -- | Finds the nearest point on the line to the given point, and gives back -- the point. nearestPointOnLine :: (Geometry rel pt ln, Ord a, Floating a, Show a) => pt a -> ln a -> pt a -- | Gives the distance along the line (2D or 3D) at a given X value. -- Returns Nothing if the line is parallel to the YZ plane (in 2D, if the -- X component of the line is zero). The value returned is a multiple of -- the direction vector of the line, which will only be the same as -- distance if the direction vector is a unit vector. valueAtX :: (Geometry rel pt ln, Coord2 rel, Coord2 pt, Fractional a, Eq a) => ln a -> a -> Maybe a -- | Gives the distance along the line (2D or 3D) at a given Y value. -- Returns Nothing if the line is parallel to the XZ plane (in 2D, if the -- Y component of the line is zero). The value returned is a multiple of -- the direction vector of the line, which will only be the same as -- distance if the direction vector is a unit vector. valueAtY :: (Geometry rel pt ln, Coord2 rel, Coord2 pt, Fractional a, Eq a) => ln a -> a -> Maybe a -- | Gives the distance along the 3D line at a given Z value. Returns -- Nothing if the line is parallel to the XY plane. The value returned is -- a multiple of the direction vector of the line, which will only be the -- same as distance if the direction vector is a unit vector. valueAtZ :: (Geometry rel pt ln, Coord3 rel, Coord3 pt, Fractional a, Eq a) => ln a -> a -> Maybe a -- | pointAtX (and the Y and Z equivalents) are wrappers around -- valueAtX (and similar) that give back the point rather than -- distance along the line. pointAtX :: (Geometry rel pt ln, Coord2 rel, Coord2 pt, Fractional a, Eq a, Show a) => ln a -> a -> Maybe (pt a) -- | pointAtX (and the Y and Z equivalents) are wrappers around -- valueAtX (and similar) that give back the point rather than -- distance along the line. pointAtY :: (Geometry rel pt ln, Coord2 rel, Coord2 pt, Fractional a, Eq a, Show a) => ln a -> a -> Maybe (pt a) pointAtZ :: (Geometry rel pt ln, Coord3 rel, Coord3 pt, Fractional a, Eq a, Show a) => ln a -> a -> Maybe (pt a) instance Data.SG.Geometry.Geometry Data.SG.Vector.Basic.Pair Data.SG.Vector.Basic.Pair Data.SG.Vector.Basic.LinePair instance Data.SG.Geometry.Geometry Data.SG.Vector.Basic.Triple Data.SG.Vector.Basic.Triple Data.SG.Vector.Basic.LineTriple -- | A module with types to use in a 2D system, and various helper -- functions. Several more functions are available for use in the -- Data.SG.Geometry module. module Data.SG.Geometry.TwoDim -- | A point in 2D space. newtype Point2' a Point2 :: (a, a) -> Point2' a -- | A relative vector (free vector) in 2D space. The pair are the x and y -- components, and the last item is the squared magnitude of the -- vector, which is stored with it to speed up various operations. It is -- suggested you use makeRel2 to create one of these, unless the -- square magnitude is easily apparent, e.g. Rel2 (0, 2) 4 data Rel2' a Rel2 :: (a, a) -> a -> Rel2' a -- | Constructs a Rel2' vector. makeRel2 :: Num a => (a, a) -> Rel2' a -- | A line in 2D space. A line is a point, and a free vector indicating -- direction. A line may be treated by a function as either finite -- (taking the magnitude of the free vector as the length) or infinite -- (ignoring the magnitude of the direction vector). data Line2' a Line2 :: (Point2' a) -> (Rel2' a) -> Line2' a [getLineStart2] :: Line2' a -> (Point2' a) [getLineDir2] :: Line2' a -> (Rel2' a) -- | Gets the angle, in radians, anti-clockwise from the x-axis. If -- you pass the all-zero vector, the return value will be zero. toAngle :: RealFloat a => Rel2' a -> a -- | Gets the vector perpendicular to the given 2D vector. If you pass it a -- vector that is in a clockwise direction around a polygon, the result -- will always face away from the polygon. perpendicular2 :: Num a => Rel2' a -> Rel2' a -- | Reflects the first direction vector against the given surface normal. -- The resulting direction vector should have the same magnitude as the -- original first parameter. An example: -- --
--   makeRel2 (-3, -4) `reflectAgainst2` makeRel2 (0,1) == makeRel2 (-3, 4)
--   
reflectAgainst2 :: (Floating a, Ord a, Eq a, Show a) => Rel2' a -> Rel2' a -> Rel2' a -- | Reflects the first direction vector against the given surface normal. -- The resulting direction vector should have the same magnitude as the -- original first parameter. -- -- The reflection is not performed if the given vector points along the -- same direction as the normal, that is: if once projected onto the -- normal vector, the component is positive, the original first parameter -- is returned unmodified. Examples: -- --
--   makeRel2 (-3, -4) `reflectAgainstIfNeeded2` makeRel2 (0,1) == makeRel2 (-3, 4)
--   makeRel2 (-3, 4) `reflectAgainstIfNeeded2` makeRel2 (0,1) == makeRel2 (-3, 4)
--   
reflectAgainstIfNeeded2 :: (Floating a, Ord a, Eq a, Show a) => Rel2' a -> Rel2' a -> Rel2' a -- | Given two 2D lines, finds out their intersection. The first part of -- the result pair is how much to multiply the direction vector of the -- first line by (and add it to the start point of the first line) to -- reach the intersection, and the second part is the corresponding item -- for the second line. So given Just (a, b) = intersectLines2 la -- lb, it should be the case (minus some possible precision loss) -- that alongLine a la == alongLine b lb. If the lines are -- parallel, Nothing is returned. -- -- Note that this function assumes the lines are infinite. If you want to -- check for the intersection of two finite lines, check if the two parts -- of the result pair are both in the range 0 to 1 inclusive. intersectLines2 :: (Fractional a, Eq a, Show a) => Line2' a -> Line2' a -> Maybe (a, a) -- | Finds all the intersections between a line from the first list and a -- line from the second list, and how far along that is each line. That -- is, this is a bit like mapMaybe composed with intersectLines2 on all -- pairings of a line from the first list and a line from the second -- list. findAllIntersections2 :: (Fractional a, Eq a, Show a) => ([Line2' a], [Line2' a]) -> [((Line2' a, a), (Line2' a, a))] -- | Given a line, and a circle (defined by a point and a radius), finds -- the points of intersection. -- -- If the line does not intersect the circle, Nothing is returned. If -- they do intersect, two values are returned that are distances along -- the line. That is, given Just (a, b) = intersectLineCircle l -- c, the two points of intersection are (alongLine l a, -- alongLine l b). -- -- The ordering of the two items in the pair is arbitrary, and if the -- line is a tangent to the circle, the values will be the same. intersectLineCircle :: (Ord a, Floating a) => Line2' a -> (Point2' a, a) -> Maybe (a, a) -- | Like pointAtZ, but returns a 2D vector instead of a 3D vector point2AtZ :: (Geometry rel pt ln, Coord3 rel, Coord3 pt, Fractional a, Eq a, Show a) => ln a -> a -> Maybe (Point2' a) instance GHC.Read.Read a => GHC.Read.Read (Data.SG.Geometry.TwoDim.Line2' a) instance GHC.Show.Show a => GHC.Show.Show (Data.SG.Geometry.TwoDim.Line2' a) instance GHC.Classes.Eq a => GHC.Classes.Eq (Data.SG.Geometry.TwoDim.Line2' a) instance GHC.Read.Read a => GHC.Read.Read (Data.SG.Geometry.TwoDim.Rel2' a) instance GHC.Show.Show a => GHC.Show.Show (Data.SG.Geometry.TwoDim.Rel2' a) instance GHC.Classes.Ord a => GHC.Classes.Ord (Data.SG.Geometry.TwoDim.Rel2' a) instance GHC.Classes.Eq a => GHC.Classes.Eq (Data.SG.Geometry.TwoDim.Rel2' a) instance GHC.Read.Read a => GHC.Read.Read (Data.SG.Geometry.TwoDim.Point2' a) instance GHC.Show.Show a => GHC.Show.Show (Data.SG.Geometry.TwoDim.Point2' a) instance GHC.Classes.Ord a => GHC.Classes.Ord (Data.SG.Geometry.TwoDim.Point2' a) instance GHC.Classes.Eq a => GHC.Classes.Eq (Data.SG.Geometry.TwoDim.Point2' a) instance Data.SG.Vector.IsomorphicVectors Data.SG.Geometry.TwoDim.Rel2' Data.SG.Geometry.TwoDim.Point2' instance Data.SG.Vector.IsomorphicVectors Data.SG.Geometry.TwoDim.Point2' Data.SG.Geometry.TwoDim.Rel2' instance Data.SG.Vector.IsomorphicVectors Data.SG.Geometry.TwoDim.Rel2' Data.SG.Vector.Basic.Pair instance Data.SG.Vector.IsomorphicVectors Data.SG.Vector.Basic.Pair Data.SG.Geometry.TwoDim.Rel2' instance Data.SG.Vector.IsomorphicVectors Data.SG.Geometry.TwoDim.Point2' Data.SG.Vector.Basic.Pair instance Data.SG.Vector.IsomorphicVectors Data.SG.Vector.Basic.Pair Data.SG.Geometry.TwoDim.Point2' instance Data.SG.Vector.VectorNum Data.SG.Geometry.TwoDim.Rel2' instance Data.SG.Vector.VectorNum Data.SG.Geometry.TwoDim.Point2' instance (GHC.Show.Show a, GHC.Classes.Eq a, GHC.Num.Num a) => GHC.Num.Num (Data.SG.Geometry.TwoDim.Rel2' a) instance GHC.Base.Functor Data.SG.Geometry.TwoDim.Point2' instance GHC.Base.Applicative Data.SG.Geometry.TwoDim.Point2' instance Data.Foldable.Foldable Data.SG.Geometry.TwoDim.Point2' instance Data.Foldable.Foldable Data.SG.Geometry.TwoDim.Rel2' instance Data.Traversable.Traversable Data.SG.Geometry.TwoDim.Point2' instance Data.SG.Vector.Coord2 Data.SG.Geometry.TwoDim.Point2' instance Data.SG.Vector.Coord Data.SG.Geometry.TwoDim.Point2' instance Data.SG.Vector.Coord2 Data.SG.Geometry.TwoDim.Rel2' instance Data.SG.Vector.Coord Data.SG.Geometry.TwoDim.Rel2' instance Data.SG.Geometry.Geometry Data.SG.Geometry.TwoDim.Rel2' Data.SG.Geometry.TwoDim.Point2' Data.SG.Geometry.TwoDim.Line2' -- | A module with types to use in a 3D system, and various helper -- functions. Several more functions are available for use in the -- Data.SG.Geometry module. module Data.SG.Geometry.ThreeDim -- | A point in 3D space. newtype Point3' a Point3 :: (a, a, a) -> Point3' a -- | A relative vector (free vector) in 3D space. The triple is the x, y, z -- components, and the last item is the squared magnitude of the -- vector, which is stored with it to speed up various operations. It is -- suggested you use makeRel3 to create one of these, unless the -- magnitude is easily apparent, e.g. Rel3 (0, 1, 1) 2 data Rel3' a Rel3 :: (a, a, a) -> a -> Rel3' a -- | Constructs a Rel3' vector makeRel3 :: Num a => (a, a, a) -> Rel3' a -- | A line in 3D space. A line is a point and a free vector indicating -- direction. A line may be treated by a function as either finite -- (taking the magnitude of the free vector as the length) or infinite -- (ignoring the magnitude of the direction vector). data Line3' a Line3 :: (Point3' a) -> (Rel3' a) -> Line3' a [getLineStart3] :: Line3' a -> (Point3' a) [getLineDir3] :: Line3' a -> (Rel3' a) instance GHC.Read.Read a => GHC.Read.Read (Data.SG.Geometry.ThreeDim.Line3' a) instance GHC.Show.Show a => GHC.Show.Show (Data.SG.Geometry.ThreeDim.Line3' a) instance GHC.Classes.Eq a => GHC.Classes.Eq (Data.SG.Geometry.ThreeDim.Line3' a) instance GHC.Read.Read a => GHC.Read.Read (Data.SG.Geometry.ThreeDim.Rel3' a) instance GHC.Show.Show a => GHC.Show.Show (Data.SG.Geometry.ThreeDim.Rel3' a) instance GHC.Classes.Ord a => GHC.Classes.Ord (Data.SG.Geometry.ThreeDim.Rel3' a) instance GHC.Classes.Eq a => GHC.Classes.Eq (Data.SG.Geometry.ThreeDim.Rel3' a) instance GHC.Read.Read a => GHC.Read.Read (Data.SG.Geometry.ThreeDim.Point3' a) instance GHC.Show.Show a => GHC.Show.Show (Data.SG.Geometry.ThreeDim.Point3' a) instance GHC.Classes.Ord a => GHC.Classes.Ord (Data.SG.Geometry.ThreeDim.Point3' a) instance GHC.Classes.Eq a => GHC.Classes.Eq (Data.SG.Geometry.ThreeDim.Point3' a) instance Data.SG.Vector.IsomorphicVectors Data.SG.Geometry.ThreeDim.Rel3' Data.SG.Geometry.ThreeDim.Point3' instance Data.SG.Vector.IsomorphicVectors Data.SG.Geometry.ThreeDim.Point3' Data.SG.Geometry.ThreeDim.Rel3' instance Data.SG.Vector.IsomorphicVectors Data.SG.Geometry.ThreeDim.Rel3' Data.SG.Vector.Basic.Triple instance Data.SG.Vector.IsomorphicVectors Data.SG.Vector.Basic.Triple Data.SG.Geometry.ThreeDim.Rel3' instance Data.SG.Vector.IsomorphicVectors Data.SG.Geometry.ThreeDim.Point3' Data.SG.Vector.Basic.Triple instance Data.SG.Vector.IsomorphicVectors Data.SG.Vector.Basic.Triple Data.SG.Geometry.ThreeDim.Point3' instance Data.SG.Vector.VectorNum Data.SG.Geometry.ThreeDim.Rel3' instance Data.SG.Vector.VectorNum Data.SG.Geometry.ThreeDim.Point3' instance (GHC.Show.Show a, GHC.Classes.Eq a, GHC.Num.Num a) => GHC.Num.Num (Data.SG.Geometry.ThreeDim.Rel3' a) instance GHC.Base.Functor Data.SG.Geometry.ThreeDim.Point3' instance GHC.Base.Applicative Data.SG.Geometry.ThreeDim.Point3' instance Data.Foldable.Foldable Data.SG.Geometry.ThreeDim.Point3' instance Data.Foldable.Foldable Data.SG.Geometry.ThreeDim.Rel3' instance Data.Traversable.Traversable Data.SG.Geometry.ThreeDim.Point3' instance Data.SG.Vector.Coord2 Data.SG.Geometry.ThreeDim.Point3' instance Data.SG.Vector.Coord3 Data.SG.Geometry.ThreeDim.Point3' instance Data.SG.Vector.Coord2 Data.SG.Geometry.ThreeDim.Rel3' instance Data.SG.Vector.Coord3 Data.SG.Geometry.ThreeDim.Rel3' instance Data.SG.Vector.Coord Data.SG.Geometry.ThreeDim.Point3' instance Data.SG.Vector.Coord Data.SG.Geometry.ThreeDim.Rel3' instance Data.SG.Geometry.Geometry Data.SG.Geometry.ThreeDim.Rel3' Data.SG.Geometry.ThreeDim.Point3' Data.SG.Geometry.ThreeDim.Line3' -- | A module with various simple matrix operations to augment the vector -- stuff. -- -- The Num instances implement proper matrix multiplication as you would -- expect (not element-wise multiplication). module Data.SG.Matrix -- | A 2x2 matrix. Primarily useful via its instances, such as -- Functor, Num, and Matrix. type Matrix22' a = SquareMatrix Pair a -- | A 3x3 matrix. Primarily useful via its instances, such as -- Functor, Num, and Matrix. type Matrix33' a = SquareMatrix Triple a -- | A 4x4 matrix. Primarily useful via its instances, such as -- Functor, Num, and Matrix. type Matrix44' a = SquareMatrix Quad a -- | A square matrix. You will almost certainly want to use -- Matrix22' and similar instead of this directly. It does have a -- variety of useful instances though, especially Functor, -- Num and Matrix. -- -- Its definition is based on a square matrix being, for example, a pair -- of pairs or a triple of triples. newtype SquareMatrix c a SquareMatrix :: (c (c a)) -> SquareMatrix c a -- | The class that all matrices belong to. class Matrix m -- | Gives back the matrix as a list of rows. matrixComponents :: Matrix m => m a -> [[a]] -- | Creates a matrix from a list of rows. Any missing entries are filled -- in with the relevant entries from the identity matrix, hence the -- identity matrix is equivalent to fromMatrixComponents []. fromMatrixComponents :: (Matrix m, Num a) => [[a]] -> m a -- | Transposes a matrix transpose :: Matrix m => m a -> m a -- | The identity matrix. identityMatrix :: (Num a, Matrix m) => m a -- | Matrix multiplication where the size of the vector matches the -- dimensions of the matrix. The complicated type just means that this -- function will work for any combination of matrix types and vectors -- where the width of the square matrix is the same as the number of -- dimensions in the vector. multMatrix :: (Foldable c, Applicative c, Num a, IsomorphicVectors c p, IsomorphicVectors p c) => SquareMatrix c a -> p a -> p a -- | Matrix multiplication. There is no requirement that the size of the -- matrix matches the size of the vector: -- -- -- -- This allows you to do tricks such as multiplying a 4x4 matrix by a 3D -- vector, and doing translation (a standard 3D graphics trick). multMatrixGen :: (Coord p, Matrix m, Num a) => m a -> p a -> p a -- | Given a 2D relative vector, produces a matrix that will translate by -- that much (when you multiply a 2D point with it using multMatrixGen) translate2D :: (Num a, IsomorphicVectors p Pair) => p a -> Matrix33' a -- | Given a 3D relative vector, produces a matrix that will translate by -- that much (when you multiply a 3D point with it using multMatrixGen) translate3D :: (Num a, IsomorphicVectors p Triple) => p a -> Matrix44' a -- | Given an angle in radians, produces a matrix that rotates -- anti-clockwise by that angle around the X axis. Note that this can be -- used to produce a 2x2, 3x3 or 4x4 matrix, but if you produce a 2x2 -- matrix, odd things will happen! rotateXaxis :: (Floating a, Matrix m) => a -> m a -- | Given an angle in radians, produces a matrix that rotates -- anti-clockwise by that angle around the Y axis. Note that this can be -- used to produce a 2x2, 3x3 or 4x4 matrix, but if you produce a 2x2 -- matrix, odd things will happen! rotateYaxis :: (Floating a, Matrix m) => a -> m a -- | Given an angle in radians, produces a matrix that rotates -- anti-clockwise by that angle around the Z axis. Note that this can be -- used to produce a 2x2 (in which case it is a rotation around the -- origin), 3x3 or 4x4 matrix. rotateZaxis :: (Floating a, Matrix m) => a -> m a instance GHC.Base.Functor c => GHC.Base.Functor (Data.SG.Matrix.SquareMatrix c) instance GHC.Base.Applicative c => GHC.Base.Applicative (Data.SG.Matrix.SquareMatrix c) instance (Data.Foldable.Foldable c, GHC.Base.Applicative c, GHC.Classes.Eq a) => GHC.Classes.Eq (Data.SG.Matrix.SquareMatrix c a) instance Data.Foldable.Foldable c => Data.Foldable.Foldable (Data.SG.Matrix.SquareMatrix c) instance Data.Traversable.Traversable c => Data.Traversable.Traversable (Data.SG.Matrix.SquareMatrix c) instance (GHC.Base.Applicative c, Data.Foldable.Foldable c, Data.Traversable.Traversable c, GHC.Base.Functor c, GHC.Show.Show a) => GHC.Show.Show (Data.SG.Matrix.SquareMatrix c a) instance (GHC.Read.Read a, GHC.Num.Num a, GHC.Base.Applicative c, Data.Traversable.Traversable c) => GHC.Read.Read (Data.SG.Matrix.SquareMatrix c a) instance (GHC.Base.Applicative c, Data.Foldable.Foldable c, Data.Traversable.Traversable c, GHC.Base.Functor c) => Data.SG.Matrix.Matrix (Data.SG.Matrix.SquareMatrix c) instance (GHC.Num.Num a, Data.Traversable.Traversable c, Data.Foldable.Foldable c, GHC.Base.Functor c, GHC.Base.Applicative c) => GHC.Num.Num (Data.SG.Matrix.SquareMatrix c a) -- | This module has types and functions for dealing with collision -- detection on simple 2D shapes. module Data.SG.Shape -- | A type for simple 2D convex shapes. It is expected that you will -- define a synonym in your own application such as type Shape = -- Shape' Double, hence the funny name. data Shape' a -- | A rectangle with a centre, and a width (distance from the centre to -- the left or right side of the rectangle) and a height (distance from -- the centre to the top or bottom side of the rectangle. So the -- rectangle with corners (1,1) and (3,2) is Rectangle (Point2 -- (2,1.5)) (1, 0.5). Technically a rectangle is a polygon, of -- course, but a rectangle (which is axis-aligned) can be processed -- faster by most algorithms. Rectangle :: Point2' a -> (a, a) -> Shape' a [shapeCentre] :: Shape' a -> Point2' a [rectSize] :: Shape' a -> (a, a) -- | A circle with a centre and a radius. Circle :: Point2' a -> a -> Shape' a [shapeCentre] :: Shape' a -> Point2' a [circSize] :: Shape' a -> a -- | A polygon with a centre, and a list of points. The points are relative -- vectors from the centre of the polygon, and are expected to be in -- clockwise order. For example, the triangle with corners (1,1) (3,3) -- and (3,1) could be Polygon (Point2 (2.5, 1.5)) [Rel2 (-1.5,-0.5), -- Rel2 (0.5,1.5), Rel2 (-1.5, 1.5)]. -- -- Note that whereabouts the centre is inside the polygon is up to you -- (it does not have to be the geometric average of the points), -- but it should at least be inside the polygon, or else some algorithms -- will behave strangely with it. -- -- The list of points should have at least 3 points in it, or else some -- algorithms will behave strangely. -- -- If your points are not in clockwise order (with the X-Y axes being how -- they are in graphs, not on screens), funny things will happen with the -- collision detection. Polygon :: Point2' a -> [Rel2' a] -> Shape' a [shapeCentre] :: Shape' a -> Point2' a [polyPoints] :: Shape' a -> [Rel2' a] -- | Moves a shape by a given vector (by moving the centre). moveShape :: (Num a, Eq a, Show a) => Rel2' a -> Shape' a -> Shape' a -- | Given an angle in radians, rotates the shape by that angle in -- an anti-clockwise direction. A circle will remain untouched, a polygon -- will have its points rotated, and a rectangle will become a polygon -- and get rotated (even if you pass 0 as the angle). rotateShape :: forall a. Floating a => a -> Shape' a -> Shape' a -- | Scales the size of the shape (for all edges, from the centre) by the -- given factor. scaleShape :: Num a => a -> Shape' a -> Shape' a -- | Given a shape, gets a list of points that make up the vertices of the -- shape. For circles, this list will be empty. shapePoints :: (Num a, Eq a, Show a) => Shape' a -> [Point2' a] -- | Gives back the bounding box of a shape in terms of the minimum X-Y and -- the maximum X-Y corners of the bounding box. boundingBox :: (Num a, Ord a, Eq a, Show a) => Shape' a -> (Point2' a, Point2' a) -- | Checks for overlap between the two shapes. If they do not collide, -- returns Nothing. If they do collide, gives back suggested angles away -- from each other. These are not necessarily the shortest direction to -- separate the two shapes, but should be decent for doing collision -- resolution (by using them as surface normals, or push-away vectors) -- -- The first vector returned is the direction in which the first shape -- should head (or the surface normal to bounce the first shape off), -- whereas the second vector returned is the direction in which the -- second shape should head (or the surface normal to bounce the second -- shape off). -- -- This function includes an initial quick test, followed by a more -- detailed test if necessary. overlap :: (Floating a, Ord a, Eq a, Show a) => Shape' a -> Shape' a -> Maybe (Rel2' a, Rel2' a) -- | Given a line and a shape, finds all possible intersections of the line -- with the shape. Since the shapes are convex, continuous 2D shapes, -- there will either be no intersections or two (which could be the same -- point). The returned value is distance along the line in multiples of -- the direction vector (the return value is the same idea as -- intersectLineCircle). intersectLineShape :: forall a. (Floating a, Ord a, Eq a, Show a) => Line2' a -> Shape' a -> Maybe (a, a) instance GHC.Classes.Ord a => GHC.Classes.Ord (Data.SG.Shape.Shape' a) instance GHC.Classes.Eq a => GHC.Classes.Eq (Data.SG.Shape.Shape' a) instance GHC.Read.Read a => GHC.Read.Read (Data.SG.Shape.Shape' a) instance GHC.Show.Show a => GHC.Show.Show (Data.SG.Shape.Shape' a) -- | A small geometry library, with vectors, matrices and simple shape -- collision detection that is intended to be straightforward in two and -- three dimensions. -- -- The basics of vectors are in the Data.SG.Vector module, the -- basics of lines and geometry tests (e.g. testing whether a point is on -- a line) are in Data.SG.Geometry, with further specialised tests -- in Data.SG.Geometry.TwoDim and -- Data.SG.Geometry.ThreeDim. Matrix transformations are in -- Data.SG.Matrix and shapes (with collision detection) are in -- Data.SG.Shape. -- -- The names for most of the types in this library end with a prime. This -- is because it is intended that you specialise these types (usually to -- Float or Double) in your application as follows: -- --
--   type Point2 = Point2' Double
--   type Rel2 = Rel2' Double
--   type Line2 = Line2' Double
--   type Matrix22 = Matrix22' Double
--   
-- -- Much of the use of the types (especially vectors) in this library is -- made using type-classes such as Num, Functor, Applicative and so on. -- For more explanation on some of the less well-known type-classes, see -- either the article Typeclassopedia in The Monad Reader -- (http://www.haskell.org/haskellwiki/The_Monad.Reader) issue 13 -- (http://www.haskell.org/sitewiki/images/8/85/TMR-Issue13.pdf), -- or my own notes at http://www.twistedsquare.com/haskell.html. -- -- To understand what various functions will actually do, look at the -- SGdemo project -- (http://hackage.haskell.org/cgi-bin/hackage-scripts/package/SGdemo) -- on Hackage (and its code) which provides a visual demonstration of -- several of the functions. module Data.SG