Copyright | (C) Frank Staals |
---|---|
License | see the LICENSE file |
Maintainer | Frank Staals |
Safe Haskell | None |
Language | Haskell2010 |
Basic Geometry Types
Synopsis
- module Data.Geometry.Properties
- module Data.Geometry.Transformation
- module Data.Geometry.Point
- imap :: (Vector v a, Vector v b) => (Int -> a -> b) -> v a -> v b
- replicate :: Vector v a => a -> v a
- distanceA :: (Floating a, Foldable (Diff p), Affine p) => p a -> p a -> a
- qdA :: (Affine p, Foldable (Diff p), Num a) => p a -> p a -> a
- class Additive (Diff p) => Affine (p :: Type -> Type) where
- dot :: (Metric f, Num a) => f a -> f a -> a
- norm :: (Metric f, Floating a) => f a -> a
- signorm :: (Metric f, Floating a) => f a -> f a
- outer :: (Functor f, Functor g, Num a) => f a -> g a -> f (g a)
- unit :: (Additive t, Num a) => ASetter' (t a) a -> t a
- scaled :: (Traversable t, Num a) => t a -> t (t a)
- basisFor :: (Traversable t, Num a) => t b -> [t a]
- basis :: (Additive t, Traversable t, Num a) => [t a]
- (^/) :: (Functor f, Fractional a) => f a -> a -> f a
- (^*) :: (Functor f, Num a) => f a -> a -> f a
- (*^) :: (Functor f, Num a) => a -> f a -> f a
- sumV :: (Foldable f, Additive v, Num a) => f (v a) -> v a
- negated :: (Functor f, Num a) => f a -> f a
- newtype E (t :: Type -> Type) = E {}
- class Functor f => Additive (f :: Type -> Type) where
- data C (n :: Nat) = C
- type Arity d = (ImplicitArity (Peano d), KnownNat d)
- newtype Vector (d :: Nat) (r :: *) = MKVector {
- _unV :: VectorFamily (Peano d) r
- pattern Vector4 :: r -> r -> r -> r -> Vector 4 r
- pattern Vector3 :: r -> r -> r -> Vector 3 r
- pattern Vector2 :: r -> r -> Vector 2 r
- pattern Vector1 :: r -> Vector 1 r
- pattern Vector :: VectorFamilyF (Peano d) r -> Vector d r
- unV :: Lens (Vector d r) (Vector d s) (VectorFamily (Peano d) r) (VectorFamily (Peano d) s)
- readVec :: forall d r. (Arity d, Read r) => ReadP (Vector d r)
- vectorFromList :: Arity d => [r] -> Maybe (Vector d r)
- vectorFromListUnsafe :: Arity d => [r] -> Vector d r
- destruct :: (Arity d, Arity (d + 1)) => Vector (d + 1) r -> (r, Vector d r)
- head :: (Arity d, 1 <= d) => Vector d r -> r
- element :: forall proxy i d r. (Arity d, KnownNat i, (i + 1) <= d) => proxy i -> Lens' (Vector d r) r
- element' :: forall d r. Arity d => Int -> Traversal' (Vector d r) r
- snoc :: (Arity (d + 1), Arity d) => Vector d r -> r -> Vector (d + 1) r
- init :: (Arity d, Arity (d + 1)) => Vector (d + 1) r -> Vector d r
- prefix :: forall i d r. (Arity d, Arity i, i <= d) => Vector d r -> Vector i r
- cross :: Num r => Vector 3 r -> Vector 3 r -> Vector 3 r
- isScalarMultipleOf :: (Eq r, Fractional r, Arity d) => Vector d r -> Vector d r -> Bool
- scalarMultiple :: (Eq r, Fractional r, Arity d) => Vector d r -> Vector d r -> Maybe r
- xComponent :: (1 <= d, Arity d) => Lens' (Vector d r) r
- yComponent :: (2 <= d, Arity d) => Lens' (Vector d r) r
- zComponent :: (3 <= d, Arity d) => Lens' (Vector d r) r
- module Data.Geometry.Line
- module Data.Geometry.LineSegment
- newtype PolyLine d p r = PolyLine {}
- points :: forall d p r d p r. Iso (PolyLine d p r) (PolyLine d p r) (LSeq 2 ((:+) (Point d r) p)) (LSeq 2 ((:+) (Point d r) p))
- fromPoints' :: Monoid p => [Point d r] -> PolyLine d p r
- fromLineSegment :: LineSegment d p r -> PolyLine d p r
- asLineSegment :: PolyLine d p r -> LineSegment d p r
- asLineSegment' :: PolyLine d p r -> Maybe (LineSegment d p r)
- type SomePolygon p r = Either (Polygon Simple p r) (Polygon Multi p r)
- type MultiPolygon = Polygon Multi
- type SimplePolygon = Polygon Simple
- data Polygon (t :: PolygonType) p r where
- data PolygonType
- _SimplePolygon :: Prism' (Polygon Simple p r) (CSeq (Point 2 r :+ p))
- _MultiPolygon :: Prism' (Polygon Multi p r) (CSeq (Point 2 r :+ p), [Polygon Simple p r])
- outerBoundary :: forall t p r. Lens' (Polygon t p r) (CSeq (Point 2 r :+ p))
- polygonHoles :: forall p r. Lens' (Polygon Multi p r) [Polygon Simple p r]
- polygonHoles' :: Traversal' (Polygon t p r) [Polygon Simple p r]
- outerVertex :: Int -> Lens' (Polygon t p r) (Point 2 r :+ p)
- outerBoundaryEdge :: Int -> Polygon t p r -> LineSegment 2 p r
- holeList :: Polygon t p r -> [Polygon Simple p r]
- polygonVertices :: Polygon t p r -> NonEmpty (Point 2 r :+ p)
- outerBoundaryEdges :: Polygon t p r -> CSeq (LineSegment 2 p r)
- listEdges :: Polygon t p r -> [LineSegment 2 p r]
- withIncidentEdges :: Polygon t p r -> Polygon t (Two (LineSegment 2 p r)) r
- onBoundary :: (Fractional r, Ord r) => Point 2 r -> Polygon t p r -> Bool
- inPolygon :: forall t p r. (Fractional r, Ord r) => Point 2 r -> Polygon t p r -> PointLocationResult
- insidePolygon :: (Fractional r, Ord r) => Point 2 r -> Polygon t p r -> Bool
- area :: Fractional r => Polygon t p r -> r
- signedArea :: Fractional r => SimplePolygon p r -> r
- centroid :: Fractional r => SimplePolygon p r -> Point 2 r
- pickPoint :: (Ord r, Fractional r) => Polygon p t r -> Point 2 r
- isTriangle :: Polygon p t r -> Bool
- findDiagonal :: (Ord r, Fractional r) => Polygon t p r -> LineSegment 2 p r
- isCounterClockwise :: (Eq r, Fractional r) => Polygon t p r -> Bool
- toClockwiseOrder :: (Eq r, Fractional r) => Polygon t p r -> Polygon t p r
- toClockwiseOrder' :: (Eq r, Fractional r) => Polygon t p r -> Polygon t p r
- toCounterClockWiseOrder :: (Eq r, Fractional r) => Polygon t p r -> Polygon t p r
- toCounterClockWiseOrder' :: (Eq r, Fractional r) => Polygon t p r -> Polygon t p r
- reverseOuterBoundary :: Polygon t p r -> Polygon t p r
- asSimplePolygon :: Polygon t p r -> SimplePolygon p r
- numberVertices :: Polygon t p r -> Polygon t (SP Int p) r
- cmpExtreme :: (Num r, Ord r) => Vector 2 r -> (Point 2 r :+ p) -> (Point 2 r :+ q) -> Ordering
- extremesLinear :: (Ord r, Num r) => Vector 2 r -> Polygon t p r -> (Point 2 r :+ p, Point 2 r :+ p)
- isStarShaped :: (MonadRandom m, Ord r, Fractional r) => SimplePolygon p r -> m (Maybe (Point 2 r))
Documentation
module Data.Geometry.Properties
module Data.Geometry.Transformation
module Data.Geometry.Point
imap :: (Vector v a, Vector v b) => (Int -> a -> b) -> v a -> v b #
Apply function to every element of the vector and its index.
replicate :: Vector v a => a -> v a #
Replicate value n times.
Examples:
>>>
import Data.Vector.Fixed.Boxed (Vec2)
>>>
replicate 1 :: Vec2 Int
fromList [1,1]
>>>
replicate 2 :: (Double,Double,Double)
(2.0,2.0,2.0)
>>>
import Data.Vector.Fixed.Boxed (Vec4)
>>>
replicate "foo" :: Vec4 String
fromList ["foo","foo","foo","foo"]
distanceA :: (Floating a, Foldable (Diff p), Affine p) => p a -> p a -> a #
Distance between two points in an affine space
qdA :: (Affine p, Foldable (Diff p), Num a) => p a -> p a -> a #
Compute the quadrance of the difference (the square of the distance)
class Additive (Diff p) => Affine (p :: Type -> Type) where #
An affine space is roughly a vector space in which we have forgotten or at least pretend to have forgotten the origin.
a .+^ (b .-. a) = b@ (a .+^ u) .+^ v = a .+^ (u ^+^ v)@ (a .-. b) ^+^ v = (a .+^ v) .-. q@
(.-.) :: Num a => p a -> p a -> Diff p a infixl 6 #
Get the difference between two points as a vector offset.
(.+^) :: Num a => p a -> Diff p a -> p a infixl 6 #
Add a vector offset to a point.
(.-^) :: Num a => p a -> Diff p a -> p a infixl 6 #
Subtract a vector offset from a point.
Instances
dot :: (Metric f, Num a) => f a -> f a -> a #
Compute the inner product of two vectors or (equivalently)
convert a vector f a
into a covector f a -> a
.
>>>
V2 1 2 `dot` V2 3 4
11
outer :: (Functor f, Functor g, Num a) => f a -> g a -> f (g a) #
Outer (tensor) product of two vectors
unit :: (Additive t, Num a) => ASetter' (t a) a -> t a #
Create a unit vector.
>>>
unit _x :: V2 Int
V2 1 0
scaled :: (Traversable t, Num a) => t a -> t (t a) #
Produce a diagonal (scale) matrix from a vector.
>>>
scaled (V2 2 3)
V2 (V2 2 0) (V2 0 3)
basisFor :: (Traversable t, Num a) => t b -> [t a] #
Produce a default basis for a vector space from which the argument is drawn.
basis :: (Additive t, Traversable t, Num a) => [t a] #
Produce a default basis for a vector space. If the dimensionality
of the vector space is not statically known, see basisFor
.
(^/) :: (Functor f, Fractional a) => f a -> a -> f a infixl 7 #
Compute division by a scalar on the right.
(^*) :: (Functor f, Num a) => f a -> a -> f a infixl 7 #
Compute the right scalar product
>>>
V2 3 4 ^* 2
V2 6 8
(*^) :: (Functor f, Num a) => a -> f a -> f a infixl 7 #
Compute the left scalar product
>>>
2 *^ V2 3 4
V2 6 8
sumV :: (Foldable f, Additive v, Num a) => f (v a) -> v a #
Sum over multiple vectors
>>>
sumV [V2 1 1, V2 3 4]
V2 4 5
negated :: (Functor f, Num a) => f a -> f a #
Compute the negation of a vector
>>>
negated (V2 2 4)
V2 (-2) (-4)
newtype E (t :: Type -> Type) #
Basis element
Instances
class Functor f => Additive (f :: Type -> Type) where #
A vector is an additive group with additional structure.
Nothing
The zero vector
(^+^) :: Num a => f a -> f a -> f a infixl 6 #
Compute the sum of two vectors
>>>
V2 1 2 ^+^ V2 3 4
V2 4 6
(^-^) :: Num a => f a -> f a -> f a infixl 6 #
Compute the difference between two vectors
>>>
V2 4 5 ^-^ V2 3 1
V2 1 4
lerp :: Num a => a -> f a -> f a -> f a #
Linearly interpolate between two vectors.
liftU2 :: (a -> a -> a) -> f a -> f a -> f a #
Apply a function to merge the 'non-zero' components of two vectors, unioning the rest of the values.
liftI2 :: (a -> b -> c) -> f a -> f b -> f c #
Apply a function to the components of two vectors.
- For a dense vector this is equivalent to
liftA2
. - For a sparse vector this is equivalent to
intersectionWith
.
Instances
A proxy which can be used for the coordinates.
newtype Vector (d :: Nat) (r :: *) Source #
Datatype representing d dimensional vectors. The default implementation is based n VectorFixed. However, for small vectors we automatically select a more efficient representation.
MKVector | |
|
Instances
unV :: Lens (Vector d r) (Vector d s) (VectorFamily (Peano d) r) (VectorFamily (Peano d) s) Source #
vectorFromListUnsafe :: Arity d => [r] -> Vector d r Source #
element :: forall proxy i d r. (Arity d, KnownNat i, (i + 1) <= d) => proxy i -> Lens' (Vector d r) r Source #
Lens into the i th element
element' :: forall d r. Arity d => Int -> Traversal' (Vector d r) r Source #
Similar to element
above. Except that we don't have a static guarantee
that the index is in bounds. Hence, we can only return a Traversal
snoc :: (Arity (d + 1), Arity d) => Vector d r -> r -> Vector (d + 1) r Source #
Add an element at the back of the vector
init :: (Arity d, Arity (d + 1)) => Vector (d + 1) r -> Vector d r Source #
Get a vector of the first d - 1 elements.
prefix :: forall i d r. (Arity d, Arity i, i <= d) => Vector d r -> Vector i r Source #
Get a prefix of i elements of a vector
cross :: Num r => Vector 3 r -> Vector 3 r -> Vector 3 r Source #
Cross product of two three-dimensional vectors
isScalarMultipleOf :: (Eq r, Fractional r, Arity d) => Vector d r -> Vector d r -> Bool Source #
'isScalarmultipleof u v' test if v is a scalar multiple of u.
>>>
Vector2 1 1 `isScalarMultipleOf` Vector2 10 10
True>>>
Vector2 1 1 `isScalarMultipleOf` Vector2 10 1
False>>>
Vector2 1 1 `isScalarMultipleOf` Vector2 11.1 11.1
True>>>
Vector2 1 1 `isScalarMultipleOf` Vector2 11.1 11.2
False>>>
Vector2 2 1 `isScalarMultipleOf` Vector2 11.1 11.2
False>>>
Vector2 2 1 `isScalarMultipleOf` Vector2 4 2
True>>>
Vector2 2 1 `isScalarMultipleOf` Vector2 4 0
False
scalarMultiple :: (Eq r, Fractional r, Arity d) => Vector d r -> Vector d r -> Maybe r Source #
scalarMultiple u v computes the scalar labmda s.t. v = lambda * u (if it exists)
module Data.Geometry.Line
module Data.Geometry.LineSegment
newtype PolyLine d p r Source #
A Poly line in R^d has at least 2 vertices
Instances
points :: forall d p r d p r. Iso (PolyLine d p r) (PolyLine d p r) (LSeq 2 ((:+) (Point d r) p)) (LSeq 2 ((:+) (Point d r) p)) Source #
fromPoints' :: Monoid p => [Point d r] -> PolyLine d p r Source #
pre: The input list contains at least two points. All extra vields are initialized with mempty.
fromLineSegment :: LineSegment d p r -> PolyLine d p r Source #
We consider the line-segment as closed.
asLineSegment :: PolyLine d p r -> LineSegment d p r Source #
Convert to a closed line segment by taking the first two points.
asLineSegment' :: PolyLine d p r -> Maybe (LineSegment d p r) Source #
Stricter version of asLineSegment that fails if the Polyline contains more than two points.
type SomePolygon p r = Either (Polygon Simple p r) (Polygon Multi p r) Source #
Either a simple or multipolygon
type MultiPolygon = Polygon Multi Source #
type SimplePolygon = Polygon Simple Source #
data Polygon (t :: PolygonType) p r where Source #
SimplePolygon :: CSeq (Point 2 r :+ p) -> Polygon Simple p r | |
MultiPolygon :: CSeq (Point 2 r :+ p) -> [Polygon Simple p r] -> Polygon Multi p r |
Instances
data PolygonType Source #
We distinguish between simple polygons (without holes) and Polygons with holes.
_SimplePolygon :: Prism' (Polygon Simple p r) (CSeq (Point 2 r :+ p)) Source #
Prism to test
if we are a simple polygon
_MultiPolygon :: Prism' (Polygon Multi p r) (CSeq (Point 2 r :+ p), [Polygon Simple p r]) Source #
Prism to test
if we are a Multi polygon
polygonHoles' :: Traversal' (Polygon t p r) [Polygon Simple p r] Source #
outerVertex :: Int -> Lens' (Polygon t p r) (Point 2 r :+ p) Source #
Access the i^th vertex on the outer boundary
outerBoundaryEdge :: Int -> Polygon t p r -> LineSegment 2 p r Source #
polygonVertices :: Polygon t p r -> NonEmpty (Point 2 r :+ p) Source #
The vertices in the polygon. No guarantees are given on the order in which they appear!
outerBoundaryEdges :: Polygon t p r -> CSeq (LineSegment 2 p r) Source #
The edges along the outer boundary of the polygon. The edges are half open.
running time: \(O(n)\)
listEdges :: Polygon t p r -> [LineSegment 2 p r] Source #
Lists all edges. The edges on the outer boundary are given before the ones on the holes. However, no other guarantees are given on the order.
running time: \(O(n)\)
withIncidentEdges :: Polygon t p r -> Polygon t (Two (LineSegment 2 p r)) r Source #
Pairs every vertex with its incident edges. The first one is its predecessor edge, the second one its successor edge (in terms of the ordering along the boundary).
>>>
mapM_ print . polygonVertices $ withIncidentEdges simplePoly
Point2 [0 % 1,0 % 1] :+ SP LineSegment (Closed (Point2 [1 % 1,11 % 1] :+ ())) (Closed (Point2 [0 % 1,0 % 1] :+ ())) LineSegment (Closed (Point2 [0 % 1,0 % 1] :+ ())) (Closed (Point2 [10 % 1,0 % 1] :+ ())) Point2 [10 % 1,0 % 1] :+ SP LineSegment (Closed (Point2 [0 % 1,0 % 1] :+ ())) (Closed (Point2 [10 % 1,0 % 1] :+ ())) LineSegment (Closed (Point2 [10 % 1,0 % 1] :+ ())) (Closed (Point2 [10 % 1,10 % 1] :+ ())) Point2 [10 % 1,10 % 1] :+ SP LineSegment (Closed (Point2 [10 % 1,0 % 1] :+ ())) (Closed (Point2 [10 % 1,10 % 1] :+ ())) LineSegment (Closed (Point2 [10 % 1,10 % 1] :+ ())) (Closed (Point2 [5 % 1,15 % 1] :+ ())) Point2 [5 % 1,15 % 1] :+ SP LineSegment (Closed (Point2 [10 % 1,10 % 1] :+ ())) (Closed (Point2 [5 % 1,15 % 1] :+ ())) LineSegment (Closed (Point2 [5 % 1,15 % 1] :+ ())) (Closed (Point2 [1 % 1,11 % 1] :+ ())) Point2 [1 % 1,11 % 1] :+ SP LineSegment (Closed (Point2 [5 % 1,15 % 1] :+ ())) (Closed (Point2 [1 % 1,11 % 1] :+ ())) LineSegment (Closed (Point2 [1 % 1,11 % 1] :+ ())) (Closed (Point2 [0 % 1,0 % 1] :+ ()))
onBoundary :: (Fractional r, Ord r) => Point 2 r -> Polygon t p r -> Bool Source #
Test if q lies on the boundary of the polygon. Running time: O(n)
>>>
Point2 1 1 `onBoundary` simplePoly
False>>>
Point2 0 0 `onBoundary` simplePoly
True>>>
Point2 10 0 `onBoundary` simplePoly
True>>>
Point2 5 13 `onBoundary` simplePoly
False>>>
Point2 5 10 `onBoundary` simplePoly
False>>>
Point2 10 5 `onBoundary` simplePoly
True>>>
Point2 20 5 `onBoundary` simplePoly
False
TODO: testcases multipolygon
inPolygon :: forall t p r. (Fractional r, Ord r) => Point 2 r -> Polygon t p r -> PointLocationResult Source #
Check if a point lies inside a polygon, on the boundary, or outside of the polygon. Running time: O(n).
>>>
Point2 1 1 `inPolygon` simplePoly
Inside>>>
Point2 0 0 `inPolygon` simplePoly
OnBoundary>>>
Point2 10 0 `inPolygon` simplePoly
OnBoundary>>>
Point2 5 13 `inPolygon` simplePoly
Inside>>>
Point2 5 10 `inPolygon` simplePoly
Inside>>>
Point2 10 5 `inPolygon` simplePoly
OnBoundary>>>
Point2 20 5 `inPolygon` simplePoly
Outside
TODO: Add some testcases with multiPolygons TODO: Add some more onBoundary testcases
insidePolygon :: (Fractional r, Ord r) => Point 2 r -> Polygon t p r -> Bool Source #
Test if a point lies strictly inside the polgyon.
area :: Fractional r => Polygon t p r -> r Source #
Compute the area of a polygon
signedArea :: Fractional r => SimplePolygon p r -> r Source #
Compute the signed area of a simple polygon. The the vertices are in clockwise order, the signed area will be negative, if the verices are given in counter clockwise order, the area will be positive.
centroid :: Fractional r => SimplePolygon p r -> Point 2 r Source #
Compute the centroid of a simple polygon.
pickPoint :: (Ord r, Fractional r) => Polygon p t r -> Point 2 r Source #
Pick a point that is inside the polygon.
(note: if the polygon is degenerate; i.e. has <3 vertices, we report a vertex of the polygon instead.)
pre: the polygon is given in CCW order
running time: \(O(n)\)
isTriangle :: Polygon p t r -> Bool Source #
Test if the polygon is a triangle
running time: \(O(1)\)
findDiagonal :: (Ord r, Fractional r) => Polygon t p r -> LineSegment 2 p r Source #
Find a diagonal of the polygon.
pre: the polygon is given in CCW order
running time: \(O(n)\)
isCounterClockwise :: (Eq r, Fractional r) => Polygon t p r -> Bool Source #
Test if the outer boundary of the polygon is in clockwise or counter clockwise order.
running time: \(O(n)\)
toClockwiseOrder :: (Eq r, Fractional r) => Polygon t p r -> Polygon t p r Source #
Make sure that every edge has the polygon's interior on its right, by orienting the outer boundary into clockwise order, and the inner borders (i.e. any holes, if they exist) into counter-clockwise order.
running time: \(O(n)\) | Orient the outer boundary of the polygon to clockwise order
toClockwiseOrder' :: (Eq r, Fractional r) => Polygon t p r -> Polygon t p r Source #
Orient the outer boundary into clockwise order. Leaves any holes as they are.
toCounterClockWiseOrder :: (Eq r, Fractional r) => Polygon t p r -> Polygon t p r Source #
Make sure that every edge has the polygon's interior on its left, by orienting the outer boundary into counter-clockwise order, and the inner borders (i.e. any holes, if they exist) into clockwise order.
running time: \(O(n)\)
toCounterClockWiseOrder' :: (Eq r, Fractional r) => Polygon t p r -> Polygon t p r Source #
Orient the outer boundary into counter-clockwise order. Leaves any holes as they are.
reverseOuterBoundary :: Polygon t p r -> Polygon t p r Source #
asSimplePolygon :: Polygon t p r -> SimplePolygon p r Source #
Convert a Polygon to a simple polygon by forgetting about any holes.
numberVertices :: Polygon t p r -> Polygon t (SP Int p) r Source #
assigns unique integer numbers to all vertices. Numbers start from 0, and are increasing along the outer boundary. The vertices of holes will be numbered last, in the same order.
>>>
numberVertices simplePoly
SimplePolygon (CSeq [Point2 [0 % 1,0 % 1] :+ SP 0 (),Point2 [10 % 1,0 % 1] :+ SP 1 (),Point2 [10 % 1,10 % 1] :+ SP 2 (),Point2 [5 % 1,15 % 1] :+ SP 3 (),Point2 [1 % 1,11 % 1] :+ SP 4 ()])
cmpExtreme :: (Num r, Ord r) => Vector 2 r -> (Point 2 r :+ p) -> (Point 2 r :+ q) -> Ordering Source #
Comparison that compares which point is larger
in the direction given by
the vector u.
extremesLinear :: (Ord r, Num r) => Vector 2 r -> Polygon t p r -> (Point 2 r :+ p, Point 2 r :+ p) Source #
Finds the extreme points, minimum and maximum, in a given direction
running time: \(O(n)\)
isStarShaped :: (MonadRandom m, Ord r, Fractional r) => SimplePolygon p r -> m (Maybe (Point 2 r)) Source #
Test if a Simple polygon is star-shaped. Returns a point in the kernel (i.e. from which the entire polygon is visible), if it exists.
\(O(n)\) expected time