Revert "Remove almost all 'type' usage to make types more transparent"

This reverts commit 5120a44d0f.

Conflicts:
	Parser/Meshparser.hs
This commit is contained in:
hasufell 2015-02-04 00:51:03 +01:00
parent d6174a975c
commit b5ecd16a2e
No known key found for this signature in database
GPG Key ID: 220CD1C5BDEED020
12 changed files with 166 additions and 172 deletions

View File

@ -4,15 +4,14 @@ module Algebra.Polygon where
import Algebra.Vector import Algebra.Vector
import Data.Maybe import Data.Maybe
import Diagrams.TwoD.Types
import MyPrelude import MyPrelude
-- |Split a polygon by a given segment which must be vertices of the -- |Split a polygon by a given segment which must be vertices of the
-- polygon (returns empty array otherwise). -- polygon (returns empty array otherwise).
splitPoly :: [P2] splitPoly :: [PT]
-> (P2, P2) -> Segment
-> [[P2]] -> [[PT]]
splitPoly pts (a, b) splitPoly pts (a, b)
| elem a pts && elem b pts = | elem a pts && elem b pts =
[b : takeWhile (/= b) shiftedPoly, a : dropWhile (/= b) shiftedPoly] [b : takeWhile (/= b) shiftedPoly, a : dropWhile (/= b) shiftedPoly]
@ -22,7 +21,7 @@ splitPoly pts (a, b)
-- |Get all edges of a polygon. -- |Get all edges of a polygon.
polySegments :: [P2] -> [(P2, P2)] polySegments :: [PT] -> [Segment]
polySegments p@(x':_:_:_) = go p ++ [(last p, x')] polySegments p@(x':_:_:_) = go p ++ [(last p, x')]
where where
go (x:y:xs) = (x, y) : go (y:xs) go (x:y:xs) = (x, y) : go (y:xs)
@ -33,7 +32,7 @@ polySegments _ = []
-- |Check whether the given segment is inside the polygon. -- |Check whether the given segment is inside the polygon.
-- This doesn't check for segments that are completely outside -- This doesn't check for segments that are completely outside
-- of the polygon yet. -- of the polygon yet.
isInsidePoly :: [P2] -> (P2, P2) -> Bool isInsidePoly :: [PT] -> Segment -> Bool
isInsidePoly pts seg = isInsidePoly pts seg =
null null
. catMaybes . catMaybes
@ -42,21 +41,21 @@ isInsidePoly pts seg =
-- |Check whether two points are adjacent vertices of a polygon. -- |Check whether two points are adjacent vertices of a polygon.
adjacent :: P2 -> P2 -> [P2] -> Bool adjacent :: PT -> PT -> [PT] -> Bool
adjacent u v = any (\x -> x == (u, v) || x == (v, u)) . polySegments adjacent u v = any (\x -> x == (u, v) || x == (v, u)) . polySegments
-- |Check whether the polygon is a triangle polygon. -- |Check whether the polygon is a triangle polygon.
isTrianglePoly :: [P2] -> Bool isTrianglePoly :: [PT] -> Bool
isTrianglePoly [_, _, _] = True isTrianglePoly [_, _, _] = True
isTrianglePoly _ = False isTrianglePoly _ = False
-- |Get all triangle polygons. -- |Get all triangle polygons.
triangleOnly :: [[P2]] -> [[P2]] triangleOnly :: [[PT]] -> [[PT]]
triangleOnly = filter isTrianglePoly triangleOnly = filter isTrianglePoly
-- |Get all non-triangle polygons. -- |Get all non-triangle polygons.
nonTriangleOnly :: [[P2]] -> [[P2]] nonTriangleOnly :: [[PT]] -> [[PT]]
nonTriangleOnly = filter (not . isTrianglePoly) nonTriangleOnly = filter (not . isTrianglePoly)

View File

@ -13,6 +13,13 @@ import GHC.Float
import MyPrelude import MyPrelude
type Vec = R2
type PT = P2
type Coord = (Double, Double)
type Segment = (PT, PT)
type Square = (Coord, Coord)
data Alignment = CW data Alignment = CW
| CCW | CCW
| CL | CL
@ -24,13 +31,13 @@ data Alignment = CW
-- ((xmin, ymin), (xmax, ymax)) -- ((xmin, ymin), (xmax, ymax))
dimToSquare :: (Double, Double) -- ^ x dimension dimToSquare :: (Double, Double) -- ^ x dimension
-> (Double, Double) -- ^ y dimension -> (Double, Double) -- ^ y dimension
-> ((Double, Double), (Double, Double)) -- ^ square describing those dimensions -> Square -- ^ square describing those dimensions
dimToSquare (x1, x2) (y1, y2) = ((x1, y1), (x2, y2)) dimToSquare (x1, x2) (y1, y2) = ((x1, y1), (x2, y2))
-- |Checks whether the Point is in a given Square. -- |Checks whether the Point is in a given Square.
inRange :: ((Double, Double), (Double, Double)) -- ^ the square: ((xmin, ymin), (xmax, ymax)) inRange :: Square -- ^ the square: ((xmin, ymin), (xmax, ymax))
-> P2 -- ^ Coordinate -> PT -- ^ Coordinate
-> Bool -- ^ result -> Bool -- ^ result
inRange ((xmin, ymin), (xmax, ymax)) (coords -> x :& y) inRange ((xmin, ymin), (xmax, ymax)) (coords -> x :& y)
= x >= min xmin xmax = x >= min xmin xmax
@ -40,7 +47,7 @@ inRange ((xmin, ymin), (xmax, ymax)) (coords -> x :& y)
-- |Get the angle between two vectors. -- |Get the angle between two vectors.
getAngle :: R2 -> R2 -> Double getAngle :: Vec -> Vec -> Double
getAngle a b = getAngle a b =
acos acos
. flip (/) (vecLength a * vecLength b) . flip (/) (vecLength a * vecLength b)
@ -49,50 +56,48 @@ getAngle a b =
-- |Get the length of a vector. -- |Get the length of a vector.
vecLength :: R2 -> Double vecLength :: Vec -> Double
vecLength v = sqrt (x^(2 :: Int) + y^(2 :: Int)) vecLength v = sqrt (x^(2 :: Int) + y^(2 :: Int))
where where
(x, y) = unr2 v (x, y) = unr2 v
-- |Compute the scalar product of two vectors. -- |Compute the scalar product of two vectors.
scalarProd :: R2 -> R2 -> Double scalarProd :: Vec -> Vec -> Double
scalarProd (R2 a1 a2) (R2 b1 b2) = a1 * b1 + a2 * b2 scalarProd (R2 a1 a2) (R2 b1 b2) = a1 * b1 + a2 * b2
-- |Multiply a scalar with a vector. -- |Multiply a scalar with a vector.
scalarMul :: Double -> R2 -> R2 scalarMul :: Double -> Vec -> Vec
scalarMul d (R2 a b) = R2 (a * d) (b * d) scalarMul d (R2 a b) = R2 (a * d) (b * d)
-- |Construct a vector that points to a point from the origin. -- |Construct a vector that points to a point from the origin.
pt2Vec :: P2 -> R2 pt2Vec :: PT -> Vec
pt2Vec = r2 . unp2 pt2Vec = r2 . unp2
-- |Give the point which is at the coordinates the vector -- |Give the point which is at the coordinates the vector
-- points to from the origin. -- points to from the origin.
vec2Pt :: R2 -> P2 vec2Pt :: Vec -> PT
vec2Pt = p2 . unr2 vec2Pt = p2 . unr2
-- |Construct a vector between two points. -- |Construct a vector between two points.
vp2 :: P2 -- ^ vector origin vp2 :: PT -- ^ vector origin
-> P2 -- ^ vector points here -> PT -- ^ vector points here
-> R2 -> Vec
vp2 a b = pt2Vec b - pt2Vec a vp2 a b = pt2Vec b - pt2Vec a
-- |Computes the determinant of 3 points. -- |Computes the determinant of 3 points.
det :: P2 -> P2 -> P2 -> Double det :: PT -> PT -> PT -> Double
det (coords -> ax :& ay) (coords -> bx :& by) (coords -> cx :& cy) = det (coords -> ax :& ay) (coords -> bx :& by) (coords -> cx :& cy) =
(bx - ax) * (cy - ay) - (by - ay) * (cx - ax) (bx - ax) * (cy - ay) - (by - ay) * (cx - ax)
-- |Get the point where two lines intesect, if any. -- |Get the point where two lines intesect, if any.
intersectSeg' :: (P2, P2) -- ^ first segment intersectSeg' :: Segment -> Segment -> Maybe PT
-> (P2, P2) -- ^ second segment
-> Maybe P2
intersectSeg' (a, b) (c, d) = intersectSeg' (a, b) (c, d) =
glossToPt <$> intersectSegSeg (ptToGloss a) glossToPt <$> intersectSegSeg (ptToGloss a)
(ptToGloss b) (ptToGloss b)
@ -105,7 +110,7 @@ intersectSeg' (a, b) (c, d) =
-- |Get the point where two lines intesect, if any. Excludes the -- |Get the point where two lines intesect, if any. Excludes the
-- case of end-points intersecting. -- case of end-points intersecting.
intersectSeg'' :: (P2, P2) -> (P2, P2) -> Maybe P2 intersectSeg'' :: Segment -> Segment -> Maybe PT
intersectSeg'' (a, b) (c, d) = case intersectSeg' (a, b) (c, d) of intersectSeg'' (a, b) (c, d) = case intersectSeg' (a, b) (c, d) of
Just x -> if x `notElem` [a,b,c,d] then Just a else Nothing Just x -> if x `notElem` [a,b,c,d] then Just a else Nothing
Nothing -> Nothing Nothing -> Nothing
@ -115,7 +120,7 @@ intersectSeg'' (a, b) (c, d) = case intersectSeg' (a, b) (c, d) of
-- * clock-wise -- * clock-wise
-- * counter-clock-wise -- * counter-clock-wise
-- * collinear -- * collinear
getOrient :: P2 -> P2 -> P2 -> Alignment getOrient :: PT -> PT -> PT -> Alignment
getOrient a b c = case compare (det a b c) 0 of getOrient a b c = case compare (det a b c) 0 of
LT -> CW LT -> CW
GT -> CCW GT -> CCW
@ -125,7 +130,7 @@ getOrient a b c = case compare (det a b c) 0 of
--- |Checks if 3 points a,b,c do not build a clockwise triangle by --- |Checks if 3 points a,b,c do not build a clockwise triangle by
--- connecting a-b-c. This is done by computing the determinant and --- connecting a-b-c. This is done by computing the determinant and
--- checking the algebraic sign. --- checking the algebraic sign.
notcw :: P2 -> P2 -> P2 -> Bool notcw :: PT -> PT -> PT -> Bool
notcw a b c = case getOrient a b c of notcw a b c = case getOrient a b c of
CW -> False CW -> False
_ -> True _ -> True
@ -134,22 +139,22 @@ notcw a b c = case getOrient a b c of
--- |Checks if 3 points a,b,c do build a clockwise triangle by --- |Checks if 3 points a,b,c do build a clockwise triangle by
--- connecting a-b-c. This is done by computing the determinant and --- connecting a-b-c. This is done by computing the determinant and
--- checking the algebraic sign. --- checking the algebraic sign.
cw :: P2 -> P2 -> P2 -> Bool cw :: PT -> PT -> PT -> Bool
cw a b c = not . notcw a b $ c cw a b c = not . notcw a b $ c
-- |Sort X and Y coordinates lexicographically. -- |Sort X and Y coordinates lexicographically.
sortedXY :: [P2] -> [P2] sortedXY :: [PT] -> [PT]
sortedXY = fmap p2 . sortLex . fmap unp2 sortedXY = fmap p2 . sortLex . fmap unp2
-- |Sort Y and X coordinates lexicographically. -- |Sort Y and X coordinates lexicographically.
sortedYX :: [P2] -> [P2] sortedYX :: [PT] -> [PT]
sortedYX = fmap p2 . sortLexSwapped . fmap unp2 sortedYX = fmap p2 . sortLexSwapped . fmap unp2
-- |Sort all points according to their X-coordinates only. -- |Sort all points according to their X-coordinates only.
sortedX :: [P2] -> [P2] sortedX :: [PT] -> [PT]
sortedX xs = sortedX xs =
fmap p2 fmap p2
. sortBy (\(a1, _) (a2, _) -> compare a1 a2) . sortBy (\(a1, _) (a2, _) -> compare a1 a2)
@ -157,7 +162,7 @@ sortedX xs =
-- |Sort all points according to their Y-coordinates only. -- |Sort all points according to their Y-coordinates only.
sortedY :: [P2] -> [P2] sortedY :: [PT] -> [PT]
sortedY xs = sortedY xs =
fmap p2 fmap p2
. sortBy (\(_, b1) (_, b2) -> compare b1 b2) . sortBy (\(_, b1) (_, b2) -> compare b1 b2)
@ -165,25 +170,25 @@ sortedY xs =
-- |Apply a function on the coordinates of a point. -- |Apply a function on the coordinates of a point.
onPT :: ((Double, Double) -> (Double, Double)) -> P2 -> P2 onPT :: (Coord -> Coord) -> PT -> PT
onPT f = p2 . f . unp2 onPT f = p2 . f . unp2
-- |Compare the y-coordinate of two points. -- |Compare the y-coordinate of two points.
ptCmpY :: P2 -> P2 -> Ordering ptCmpY :: PT -> PT -> Ordering
ptCmpY (coords -> _ :& y1) (coords -> _ :& y2) = ptCmpY (coords -> _ :& y1) (coords -> _ :& y2) =
compare y1 y2 compare y1 y2
-- |Compare the x-coordinate of two points. -- |Compare the x-coordinate of two points.
ptCmpX :: P2 -> P2 -> Ordering ptCmpX :: PT -> PT -> Ordering
ptCmpX (coords -> x1 :& _) (coords -> x2 :& _) = ptCmpX (coords -> x1 :& _) (coords -> x2 :& _) =
compare x1 x2 compare x1 x2
posInfPT :: P2 posInfPT :: PT
posInfPT = p2 (read "Infinity", read "Infinity") posInfPT = p2 (read "Infinity", read "Infinity")
negInfPT :: P2 negInfPT :: PT
negInfPT = p2 (negate . read $ "Infinity", negate . read $ "Infinity") negInfPT = p2 (negate . read $ "Infinity", negate . read $ "Infinity")

View File

@ -3,7 +3,6 @@
module Algorithms.GrahamScan where module Algorithms.GrahamScan where
import Algebra.Vector import Algebra.Vector
import Diagrams.TwoD.Types
import MyPrelude import MyPrelude
@ -75,18 +74,18 @@ ys = []
return [(100, 100), (400, 200)] return [(100, 100), (400, 200)]
========================================================= =========================================================
--} --}
grahamCH :: [P2] -> [P2] grahamCH :: [PT] -> [PT]
grahamCH vs = grahamUCH vs ++ (tailInit . grahamLCH $ vs) grahamCH vs = grahamUCH vs ++ (tailInit . grahamLCH $ vs)
-- |Get the lower part of the convex hull. -- |Get the lower part of the convex hull.
grahamLCH :: [P2] -> [P2] grahamLCH :: [PT] -> [PT]
grahamLCH vs = uncurry (\x y -> last . scanH x $ y) grahamLCH vs = uncurry (\x y -> last . scanH x $ y)
(first reverse . splitAt 3 . sortedXY $ vs) (first reverse . splitAt 3 . sortedXY $ vs)
-- |Get the upper part of the convex hull. -- |Get the upper part of the convex hull.
grahamUCH :: [P2] -> [P2] grahamUCH :: [PT] -> [PT]
grahamUCH vs = uncurry (\x y -> last . scanH x $ y) grahamUCH vs = uncurry (\x y -> last . scanH x $ y)
(first reverse . splitAt 3 . reverse . sortedXY $ vs) (first reverse . splitAt 3 . reverse . sortedXY $ vs)
@ -96,9 +95,9 @@ grahamUCH vs = uncurry (\x y -> last . scanH x $ y)
-- If it's the upper or lower half depends on the input. -- If it's the upper or lower half depends on the input.
-- Also, the first list is expected to be reversed since we only care -- Also, the first list is expected to be reversed since we only care
-- about the last 3 elements and want to stay efficient. -- about the last 3 elements and want to stay efficient.
scanH :: [P2] -- ^ the first 3 starting points in reversed order scanH :: [PT] -- ^ the first 3 starting points in reversed order
-> [P2] -- ^ the rest of the points -> [PT] -- ^ the rest of the points
-> [[P2]] -- ^ all convex hull points iterations for the half -> [[PT]] -- ^ all convex hull points iterations for the half
scanH hs@(x:y:z:xs) (r':rs') scanH hs@(x:y:z:xs) (r':rs')
| notcw z y x = hs : scanH (r':hs) rs' | notcw z y x = hs : scanH (r':hs) rs'
| otherwise = hs : scanH (x:z:xs) (r':rs') | otherwise = hs : scanH (x:z:xs) (r':rs')
@ -112,12 +111,12 @@ scanH hs _ = [hs]
-- |Compute all steps of the graham scan algorithm to allow -- |Compute all steps of the graham scan algorithm to allow
-- visualizing it. -- visualizing it.
-- Whether the upper or lower hull is computed depends on the input. -- Whether the upper or lower hull is computed depends on the input.
grahamCHSteps :: Int -> [P2] -> [P2] -> [[P2]] grahamCHSteps :: Int -> [PT] -> [PT] -> [[PT]]
grahamCHSteps c xs' ys' = take c . scanH xs' $ ys' grahamCHSteps c xs' ys' = take c . scanH xs' $ ys'
-- |Get all iterations of the upper hull of the graham scan algorithm. -- |Get all iterations of the upper hull of the graham scan algorithm.
grahamUHSteps :: [P2] -> [[P2]] grahamUHSteps :: [PT] -> [[PT]]
grahamUHSteps vs = grahamUHSteps vs =
(++) [getLastX 2 . sortedXY $ vs] (++) [getLastX 2 . sortedXY $ vs]
. rmdups . rmdups
@ -128,7 +127,7 @@ grahamUHSteps vs =
-- |Get all iterations of the lower hull of the graham scan algorithm. -- |Get all iterations of the lower hull of the graham scan algorithm.
grahamLHSteps :: [P2] -> [[P2]] grahamLHSteps :: [PT] -> [[PT]]
grahamLHSteps vs = grahamLHSteps vs =
(++) [take 2 . sortedXY $ vs] (++) [take 2 . sortedXY $ vs]
. rmdups . rmdups

View File

@ -42,9 +42,9 @@ instance Not Direction where
-- |Construct a kd-tree from a list of points in O(n log n). -- |Construct a kd-tree from a list of points in O(n log n).
kdTree :: [P2] -- ^ list of points to construct the kd-tree from kdTree :: [PT] -- ^ list of points to construct the kd-tree from
-> Direction -- ^ initial direction of the root-node -> Direction -- ^ initial direction of the root-node
-> KDTree P2 -- ^ resulting kd-tree -> KDTree PT -- ^ resulting kd-tree
kdTree xs' = go (sortedX xs') (sortedY xs') kdTree xs' = go (sortedX xs') (sortedY xs')
where where
go [] _ _ = KTNil go [] _ _ = KTNil
@ -67,10 +67,10 @@ kdTree xs' = go (sortedX xs') (sortedY xs')
-- If you want to partition against the pivot of X, then you pass -- If you want to partition against the pivot of X, then you pass
-- partition' (pivot xs) (ys, xs) -- partition' (pivot xs) (ys, xs)
-- and get ((y1, y2), (x1, x2)). -- and get ((y1, y2), (x1, x2)).
partition' :: P2 -- ^ the pivot to partition against partition' :: PT -- ^ the pivot to partition against
-> (P2 -> P2 -> Ordering) -- ^ ptCmpY or ptCmpX -> (PT -> PT -> Ordering) -- ^ ptCmpY or ptCmpX
-> ([P2], [P2]) -- ^ both lists (X, Y) or (Y, X) -> ([PT], [PT]) -- ^ both lists (X, Y) or (Y, X)
-> (([P2], [P2]), ([P2], [P2])) -- ^ ((x1, x2), (y1, y2)) or -> (([PT], [PT]), ([PT], [PT])) -- ^ ((x1, x2), (y1, y2)) or
-- ((y1, y2), (x1, x2)) -- ((y1, y2), (x1, x2))
partition' piv cmp' (xs, ys) = ((x1, x2), (y1, y2)) partition' piv cmp' (xs, ys) = ((x1, x2), (y1, y2))
where where
@ -83,16 +83,16 @@ partition' piv cmp' (xs, ys) = ((x1, x2), (y1, y2))
-- |Partition two sorted lists of points X and Y against the pivot of -- |Partition two sorted lists of points X and Y against the pivot of
-- Y. This function is unsafe as it does not check if there is a valid -- Y. This function is unsafe as it does not check if there is a valid
-- pivot. -- pivot.
partitionY :: ([P2], [P2]) -- ^ both lists (X, Y) partitionY :: ([PT], [PT]) -- ^ both lists (X, Y)
-> (([P2], [P2]), ([P2], [P2])) -- ^ ((x1, x2), (y1, y2)) -> (([PT], [PT]), ([PT], [PT])) -- ^ ((x1, x2), (y1, y2))
partitionY (xs, ys) = partition' (fromJust . pivot $ ys) ptCmpY (xs, ys) partitionY (xs, ys) = partition' (fromJust . pivot $ ys) ptCmpY (xs, ys)
-- |Partition two sorted lists of points X and Y against the pivot of -- |Partition two sorted lists of points X and Y against the pivot of
-- X. This function is unsafe as it does not check if there is a valid -- X. This function is unsafe as it does not check if there is a valid
-- pivot. -- pivot.
partitionX :: ([P2], [P2]) -- ^ both lists (X, Y) partitionX :: ([PT], [PT]) -- ^ both lists (X, Y)
-> (([P2], [P2]), ([P2], [P2])) -- ^ ((x1, x2), (y1, y2)) -> (([PT], [PT]), ([PT], [PT])) -- ^ ((x1, x2), (y1, y2))
partitionX (xs, ys) = (\(x, y) -> (y, x)) partitionX (xs, ys) = (\(x, y) -> (y, x))
. partition' (fromJust . pivot $ xs) ptCmpX $ (ys, xs) . partition' (fromJust . pivot $ xs) ptCmpX $ (ys, xs)
@ -100,9 +100,7 @@ partitionX (xs, ys) = (\(x, y) -> (y, x))
-- |Execute a range search in O(log n). It returns a tuple -- |Execute a range search in O(log n). It returns a tuple
-- of the points found in the range and also gives back a pretty -- of the points found in the range and also gives back a pretty
-- rose tree suitable for printing. -- rose tree suitable for printing.
rangeSearch :: KDTree P2 -- ^ tree to search in rangeSearch :: KDTree PT -> Square -> ([PT], Tree String)
-> ((Double, Double), (Double, Double)) -- ^ square describing the range
-> ([P2], Tree String)
rangeSearch kd' sq' = (goPt kd' sq', goTree kd' sq' True) rangeSearch kd' sq' = (goPt kd' sq', goTree kd' sq' True)
where where
-- either y1 or x1 depending on the orientation -- either y1 or x1 depending on the orientation
@ -112,7 +110,7 @@ rangeSearch kd' sq' = (goPt kd' sq', goTree kd' sq' True)
-- either the second or first of the tuple, depending on the orientation -- either the second or first of the tuple, depending on the orientation
cur' dir = if' (dir == Vertical) snd fst cur' dir = if' (dir == Vertical) snd fst
-- All points in the range. -- All points in the range.
goPt :: KDTree P2 -> ((Double, Double), (Double, Double)) -> [P2] goPt :: KDTree PT -> Square -> [PT]
goPt KTNil _ = [] goPt KTNil _ = []
goPt (KTNode ln pt dir rn) sq = goPt (KTNode ln pt dir rn) sq =
[pt | inRange sq pt] [pt | inRange sq pt]
@ -124,7 +122,7 @@ rangeSearch kd' sq' = (goPt kd' sq', goTree kd' sq' True)
(goPt rn sq) (goPt rn sq)
[]) [])
-- A pretty rose tree suitable for printing. -- A pretty rose tree suitable for printing.
goTree :: KDTree P2 -> ((Double, Double), (Double, Double)) -> Bool -> Tree String goTree :: KDTree PT -> Square -> Bool -> Tree String
goTree KTNil _ _ = Node "nil" [] goTree KTNil _ _ = Node "nil" []
goTree (KTNode ln pt dir rn) sq vis goTree (KTNode ln pt dir rn) sq vis
| ln == KTNil && rn == KTNil = Node treeText [] | ln == KTNil && rn == KTNil = Node treeText []
@ -181,7 +179,7 @@ getDirection _ = Nothing
-- |Convert a kd-tree to a rose tree, for pretty printing. -- |Convert a kd-tree to a rose tree, for pretty printing.
kdTreeToRoseTree :: KDTree P2 -> Tree String kdTreeToRoseTree :: KDTree PT -> Tree String
kdTreeToRoseTree (KTNil) = Node "nil" [] kdTreeToRoseTree (KTNil) = Node "nil" []
kdTreeToRoseTree (KTNode ln val _ rn) = kdTreeToRoseTree (KTNode ln val _ rn) =
Node (show . unp2 $ val) [kdTreeToRoseTree ln, kdTreeToRoseTree rn] Node (show . unp2 $ val) [kdTreeToRoseTree ln, kdTreeToRoseTree rn]

View File

@ -18,14 +18,14 @@ import QueueEx
-- successor are saved for convenience. -- successor are saved for convenience.
data PolyPT = data PolyPT =
PolyA { PolyA {
id' :: P2 id' :: PT
, pre :: P2 , pre :: PT
, suc :: P2 , suc :: PT
} }
| PolyB { | PolyB {
id' :: P2 id' :: PT
, pre :: P2 , pre :: PT
, suc :: P2 , suc :: PT
} }
deriving (Show, Eq) deriving (Show, Eq)
@ -42,7 +42,7 @@ isPolyB = not . isPolyA
-- |Shift a list of sorted convex hull points of a polygon so that -- |Shift a list of sorted convex hull points of a polygon so that
-- the first element in the list is the one with the highest y-coordinate. -- the first element in the list is the one with the highest y-coordinate.
-- This is done in O(n). -- This is done in O(n).
sortLexPoly :: [P2] -> [P2] sortLexPoly :: [PT] -> [PT]
sortLexPoly ps = maybe [] (`shiftM` ps) (elemIndex (yMax ps) ps) sortLexPoly ps = maybe [] (`shiftM` ps) (elemIndex (yMax ps) ps)
where where
yMax = foldl1 (\x y -> if ptCmpY x y == GT then x else y) yMax = foldl1 (\x y -> if ptCmpY x y == GT then x else y)
@ -50,8 +50,8 @@ sortLexPoly ps = maybe [] (`shiftM` ps) (elemIndex (yMax ps) ps)
-- |Make a PolyPT list out of a regular list of points, so -- |Make a PolyPT list out of a regular list of points, so
-- the predecessor and successors are all saved. -- the predecessor and successors are all saved.
mkPolyPTList :: (P2 -> P2 -> P2 -> PolyPT) -- ^ PolyA or PolyB function mkPolyPTList :: (PT -> PT -> PT -> PolyPT) -- ^ PolyA or PolyB function
-> [P2] -- ^ polygon points -> [PT] -- ^ polygon points
-> [PolyPT] -> [PolyPT]
mkPolyPTList f' pts@(x':y':_:_) = mkPolyPTList f' pts@(x':y':_:_) =
f' x' (last pts) y' : go f' pts f' x' (last pts) y' : go f' pts
@ -64,7 +64,7 @@ mkPolyPTList _ _ = []
-- |Sort the points of two polygons according to their y-coordinates, -- |Sort the points of two polygons according to their y-coordinates,
-- while saving the origin of that point. This is done in O(n). -- while saving the origin of that point. This is done in O(n).
sortLexPolys :: ([P2], [P2]) -> [PolyPT] sortLexPolys :: ([PT], [PT]) -> [PolyPT]
sortLexPolys (pA'@(_:_), pB'@(_:_)) = sortLexPolys (pA'@(_:_), pB'@(_:_)) =
queueToList $ go (Q.fromList . mkPolyPTList PolyA . sortLexPoly $ pA') queueToList $ go (Q.fromList . mkPolyPTList PolyA . sortLexPoly $ pA')
(Q.fromList . mkPolyPTList PolyB . sortLexPoly $ pB') (Q.fromList . mkPolyPTList PolyB . sortLexPoly $ pB')
@ -104,7 +104,7 @@ sortLexPolys _ = []
-- |Get all points that intersect between both polygons. This is done -- |Get all points that intersect between both polygons. This is done
-- in O(n). -- in O(n).
intersectionPoints :: [PolyPT] -> [P2] intersectionPoints :: [PolyPT] -> [PT]
intersectionPoints xs' = rmdups . go $ xs' intersectionPoints xs' = rmdups . go $ xs'
where where
go [] = [] go [] = []
@ -113,7 +113,7 @@ intersectionPoints xs' = rmdups . go $ xs'
-- Get the scan line or in other words the -- Get the scan line or in other words the
-- Segment pairs we are going to check for intersection. -- Segment pairs we are going to check for intersection.
scanLine :: [PolyPT] -> ([(P2, P2)], [(P2, P2)]) scanLine :: [PolyPT] -> ([Segment], [Segment])
scanLine sp@(_:_) = (,) (getSegment isPolyA) (getSegment isPolyB) scanLine sp@(_:_) = (,) (getSegment isPolyA) (getSegment isPolyB)
where where
getSegment f = fromMaybe [] getSegment f = fromMaybe []
@ -124,7 +124,7 @@ intersectionPoints xs' = rmdups . go $ xs'
-- Gets the actual intersections between the segments of -- Gets the actual intersections between the segments of
-- both polygons we currently examine. This is done in O(1) -- both polygons we currently examine. This is done in O(1)
-- since we have max 4 segments. -- since we have max 4 segments.
segIntersections :: ([(P2, P2)], [(P2, P2)]) -> [P2] segIntersections :: ([Segment], [Segment]) -> [PT]
segIntersections (a@(_:_), b@(_:_)) = segIntersections (a@(_:_), b@(_:_)) =
catMaybes catMaybes
. fmap (\[x, y] -> intersectSeg' x y) . fmap (\[x, y] -> intersectSeg' x y)

View File

@ -6,7 +6,6 @@ import Algebra.Polygon
import Algebra.Vector import Algebra.Vector
import qualified Control.Arrow as A import qualified Control.Arrow as A
import Data.Maybe import Data.Maybe
import Diagrams.TwoD.Types
import Safe import Safe
@ -19,12 +18,12 @@ data VCategory = VStart
-- |Classify all vertices on a polygon into five categories (see VCategory). -- |Classify all vertices on a polygon into five categories (see VCategory).
classifyList :: [P2] -> [(P2, VCategory)] classifyList :: [PT] -> [(PT, VCategory)]
classifyList p@(x:y:_:_) = classifyList p@(x:y:_:_) =
-- need to handle the first and last element separately -- need to handle the first and last element separately
[classify (last p) x y] ++ go p ++ [classify (last . init $ p) (last p) x] [classify (last p) x y] ++ go p ++ [classify (last . init $ p) (last p) x]
where where
go :: [P2] -> [(P2, VCategory)] go :: [PT] -> [(PT, VCategory)]
go (x':y':z':xs) = classify x' y' z' : go (y':z':xs) go (x':y':z':xs) = classify x' y' z' : go (y':z':xs)
go _ = [] go _ = []
classifyList _ = [] classifyList _ = []
@ -32,10 +31,10 @@ classifyList _ = []
-- |Classify a vertex on a polygon given it's next and previous vertex -- |Classify a vertex on a polygon given it's next and previous vertex
-- into five categories (see VCategory). -- into five categories (see VCategory).
classify :: P2 -- ^ prev vertex classify :: PT -- ^ prev vertex
-> P2 -- ^ classify this one -> PT -- ^ classify this one
-> P2 -- ^ next vertex -> PT -- ^ next vertex
-> (P2, VCategory) -> (PT, VCategory)
classify prev v next classify prev v next
| isVStart prev v next = (v, VStart) | isVStart prev v next = (v, VStart)
| isVSplit prev v next = (v, VSplit) | isVSplit prev v next = (v, VSplit)
@ -46,9 +45,9 @@ classify prev v next
-- |Whether the vertex, given it's next and previous vertex, -- |Whether the vertex, given it's next and previous vertex,
-- is a start vertex. -- is a start vertex.
isVStart :: P2 -- ^ previous vertex isVStart :: PT -- ^ previous vertex
-> P2 -- ^ vertice to check -> PT -- ^ vertice to check
-> P2 -- ^ next vertex -> PT -- ^ next vertex
-> Bool -> Bool
isVStart prev v next = isVStart prev v next =
ptCmpY next v == LT && ptCmpY prev v == LT && cw next v prev ptCmpY next v == LT && ptCmpY prev v == LT && cw next v prev
@ -56,9 +55,9 @@ isVStart prev v next =
-- |Whether the vertex, given it's next and previous vertex, -- |Whether the vertex, given it's next and previous vertex,
-- is a split vertex. -- is a split vertex.
isVSplit :: P2 -- ^ previous vertex isVSplit :: PT -- ^ previous vertex
-> P2 -- ^ vertice to check -> PT -- ^ vertice to check
-> P2 -- ^ next vertex -> PT -- ^ next vertex
-> Bool -> Bool
isVSplit prev v next = isVSplit prev v next =
ptCmpY prev v == LT && ptCmpY next v == LT && cw prev v next ptCmpY prev v == LT && ptCmpY next v == LT && cw prev v next
@ -66,9 +65,9 @@ isVSplit prev v next =
-- |Whether the vertex, given it's next and previous vertex, -- |Whether the vertex, given it's next and previous vertex,
-- is an end vertex. -- is an end vertex.
isVEnd :: P2 -- ^ previous vertex isVEnd :: PT -- ^ previous vertex
-> P2 -- ^ vertice to check -> PT -- ^ vertice to check
-> P2 -- ^ next vertex -> PT -- ^ next vertex
-> Bool -> Bool
isVEnd prev v next = isVEnd prev v next =
ptCmpY prev v == GT && ptCmpY next v == GT && cw next v prev ptCmpY prev v == GT && ptCmpY next v == GT && cw next v prev
@ -76,9 +75,9 @@ isVEnd prev v next =
-- |Whether the vertex, given it's next and previous vertex, -- |Whether the vertex, given it's next and previous vertex,
-- is a merge vertex. -- is a merge vertex.
isVMerge :: P2 -- ^ previous vertex isVMerge :: PT -- ^ previous vertex
-> P2 -- ^ vertice to check -> PT -- ^ vertice to check
-> P2 -- ^ next vertex -> PT -- ^ next vertex
-> Bool -> Bool
isVMerge prev v next = isVMerge prev v next =
ptCmpY next v == GT && ptCmpY prev v == GT && cw prev v next ptCmpY next v == GT && ptCmpY prev v == GT && cw prev v next
@ -86,9 +85,9 @@ isVMerge prev v next =
-- |Whether the vertex, given it's next and previous vertex, -- |Whether the vertex, given it's next and previous vertex,
-- is a regular vertex. -- is a regular vertex.
isVRegular :: P2 -- ^ previous vertex isVRegular :: PT -- ^ previous vertex
-> P2 -- ^ vertice to check -> PT -- ^ vertice to check
-> P2 -- ^ next vertex -> PT -- ^ next vertex
-> Bool -> Bool
isVRegular prev v next = isVRegular prev v next =
(not . isVStart prev v $ next) (not . isVStart prev v $ next)
@ -99,7 +98,7 @@ isVRegular prev v next =
-- |A polygon P is y-monotone, if it has no split and merge vertices. -- |A polygon P is y-monotone, if it has no split and merge vertices.
isYmonotone :: [P2] -> Bool isYmonotone :: [PT] -> Bool
isYmonotone poly = isYmonotone poly =
not not
. any (\x -> x == VSplit || x == VMerge) . any (\x -> x == VSplit || x == VMerge)
@ -108,12 +107,12 @@ isYmonotone poly =
-- |Partition P into y-monotone pieces. -- |Partition P into y-monotone pieces.
monotonePartitioning :: [P2] -> [[P2]] monotonePartitioning :: [PT] -> [[PT]]
monotonePartitioning pts monotonePartitioning pts
| isYmonotone pts = [pts] | isYmonotone pts = [pts]
| otherwise = go (monotoneDiagonals pts) pts | otherwise = go (monotoneDiagonals pts) pts
where where
go :: [(P2, P2)] -> [P2] -> [[P2]] go :: [Segment] -> [PT] -> [[PT]]
go (x:xs) pts'@(_:_) go (x:xs) pts'@(_:_)
| isYmonotone a && isYmonotone b = [a, b] | isYmonotone a && isYmonotone b = [a, b]
| isYmonotone b = b : go xs a | isYmonotone b = b : go xs a
@ -125,37 +124,37 @@ monotonePartitioning pts
-- |Try to eliminate the merge and split vertices by computing the -- |Try to eliminate the merge and split vertices by computing the
-- diagonals we have to use for splitting the polygon. -- diagonals we have to use for splitting the polygon.
monotoneDiagonals :: [P2] -> [(P2, P2)] monotoneDiagonals :: [PT] -> [Segment]
monotoneDiagonals pts = catMaybes . go $ classifyList pts monotoneDiagonals pts = catMaybes . go $ classifyList pts
where where
go :: [(P2, VCategory)] -> [Maybe (P2, P2)] go :: [(PT, VCategory)] -> [Maybe Segment]
go (x:xs) = case snd x of go (x:xs) = case snd x of
VMerge -> getSeg (belowS . fst $ x) (fst x) : go xs VMerge -> getSeg (belowS . fst $ x) (fst x) : go xs
VSplit -> getSeg (aboveS . fst $ x) (fst x) : go xs VSplit -> getSeg (aboveS . fst $ x) (fst x) : go xs
_ -> [] ++ go xs _ -> [] ++ go xs
go [] = [] go [] = []
getSeg :: [P2] -- all points above/below the current point getSeg :: [PT] -- all points above/below the current point
-> P2 -- current point -> PT -- current point
-> Maybe (P2, P2) -> Maybe Segment
getSeg [] _ = Nothing getSeg [] _ = Nothing
getSeg (z:zs) pt getSeg (z:zs) pt
| isInsidePoly pts (z, pt) = Just (z, pt) | isInsidePoly pts (z, pt) = Just (z, pt)
| otherwise = getSeg zs pt | otherwise = getSeg zs pt
aboveS :: P2 -> [P2] aboveS :: PT -> [PT]
aboveS pt = tail . dropWhile (/= pt) $ sortedYX pts aboveS pt = tail . dropWhile (/= pt) $ sortedYX pts
belowS :: P2 -> [P2] belowS :: PT -> [PT]
belowS pt = reverse . takeWhile (/= pt) $ sortedYX pts belowS pt = reverse . takeWhile (/= pt) $ sortedYX pts
-- |Triangulate a y-monotone polygon. -- |Triangulate a y-monotone polygon.
triangulate :: [P2] -> [[P2]] triangulate :: [PT] -> [[PT]]
triangulate pts = triangulate pts =
go pts . A.first reverse . splitAt 3 . reverse . sortedYX $ pts go pts . A.first reverse . splitAt 3 . reverse . sortedYX $ pts
where where
go :: [P2] -- current polygon go :: [PT] -- current polygon
-> ([P2], [P2]) -- (stack of visited vertices, rest) -> ([PT], [PT]) -- (stack of visited vertices, rest)
-- sorted by Y-coordinate -- sorted by Y-coordinate
-> [[P2]] -> [[PT]]
go xs (p@[_, _], r:rs) = go xs (r:p, rs) go xs (p@[_, _], r:rs) = go xs (r:p, rs)
go xs (p@(u:vi:vi1:ys), rs) go xs (p@(u:vi:vi1:ys), rs)
-- case 1 and 3 -- case 1 and 3

View File

@ -56,8 +56,7 @@ data Orient = North | South | East | West
-- |Get a sub-square of the current square, e.g. nw, ne, sw or se. -- |Get a sub-square of the current square, e.g. nw, ne, sw or se.
nwSq, neSq, swSq, seSq :: ((Double, Double), (Double, Double)) -- ^ current square nwSq, neSq, swSq, seSq :: Square -> Square
-> ((Double, Double), (Double, Double)) -- ^ sub-square
nwSq ((xl, yl), (xu, yu)) = (,) (xl, (yl + yu) / 2) ((xl + xu) / 2, yu) nwSq ((xl, yl), (xu, yu)) = (,) (xl, (yl + yu) / 2) ((xl + xu) / 2, yu)
neSq ((xl, yl), (xu, yu)) = (,) ((xl + xu) / 2, (yl + yu) / 2) (xu, yu) neSq ((xl, yl), (xu, yu)) = (,) ((xl + xu) / 2, (yl + yu) / 2) (xu, yu)
swSq ((xl, yl), (xu, yu)) = (,) (xl, yl) ((xl + xu) / 2, (yl + yu) / 2) swSq ((xl, yl), (xu, yu)) = (,) (xl, yl) ((xl + xu) / 2, (yl + yu) / 2)
@ -80,9 +79,9 @@ isSEchild _ = False
-- |Builds a quadtree of a list of points which recursively divides up 2D -- |Builds a quadtree of a list of points which recursively divides up 2D
-- space into quadrants, so that every leaf-quadrant stores either zero or one -- space into quadrants, so that every leaf-quadrant stores either zero or one
-- point. -- point.
quadTree :: [P2] -- ^ the points to divide quadTree :: [PT] -- ^ the points to divide
-> ((Double, Double), (Double, Double)) -- ^ the initial square around the points -> Square -- ^ the initial square around the points
-> QuadTree P2 -- ^ the quad tree -> QuadTree PT -- ^ the quad tree
quadTree [] _ = TNil quadTree [] _ = TNil
quadTree [pt] _ = TLeaf pt quadTree [pt] _ = TLeaf pt
quadTree pts sq = TNode (quadTree nWPT . nwSq $ sq) (quadTree nEPT . neSq $ sq) quadTree pts sq = TNode (quadTree nWPT . nwSq $ sq) (quadTree nEPT . neSq $ sq)
@ -96,9 +95,9 @@ quadTree pts sq = TNode (quadTree nWPT . nwSq $ sq) (quadTree nEPT . neSq $ sq)
-- |Get all squares of a quad tree. -- |Get all squares of a quad tree.
quadTreeSquares :: ((Double, Double), (Double, Double)) -- ^ the initial square around the points quadTreeSquares :: Square -- ^ the initial square around the points
-> QuadTree P2 -- ^ the quad tree -> QuadTree PT -- ^ the quad tree
-> [((Double, Double), (Double, Double))] -- ^ all squares of the quad tree -> [Square] -- ^ all squares of the quad tree
quadTreeSquares sq (TNil) = [sq] quadTreeSquares sq (TNil) = [sq]
quadTreeSquares sq (TLeaf _) = [sq] quadTreeSquares sq (TLeaf _) = [sq]
quadTreeSquares sq (TNode nw ne sw se) = quadTreeSquares sq (TNode nw ne sw se) =
@ -108,9 +107,7 @@ quadTreeSquares sq (TNode nw ne sw se) =
-- |Get the current square of the zipper, relative to the given top -- |Get the current square of the zipper, relative to the given top
-- square. -- square.
getSquareByZipper :: ((Double, Double), (Double, Double)) -- ^ top square getSquareByZipper :: Square -> QTZipper a -> Square
-> QTZipper a
-> ((Double, Double), (Double, Double)) -- ^ current square
getSquareByZipper sq z = go sq (reverse . snd $ z) getSquareByZipper sq z = go sq (reverse . snd $ z)
where where
go sq' [] = sq' go sq' [] = sq'
@ -203,7 +200,7 @@ lookupByNeighbors :: [Orient] -> QTZipper a -> Maybe (QTZipper a)
lookupByNeighbors = flip (foldlM (flip findNeighbor)) lookupByNeighbors = flip (foldlM (flip findNeighbor))
quadTreeToRoseTree :: QTZipper P2 -> Tree String quadTreeToRoseTree :: QTZipper PT -> Tree String
quadTreeToRoseTree z' = go (rootNode z') quadTreeToRoseTree z' = go (rootNode z')
where where
go z = case z of go z = case z of

View File

@ -2,6 +2,7 @@
module Graphics.Diagram.AlgoDiags where module Graphics.Diagram.AlgoDiags where
import Algebra.Vector(PT,Square)
import Algorithms.GrahamScan import Algorithms.GrahamScan
import Algorithms.QuadTree import Algorithms.QuadTree
import Algorithms.KDTree import Algorithms.KDTree
@ -123,9 +124,7 @@ kdSquares = Diag f
where where
-- Gets all lines that make up the kdSquares. Every line is -- Gets all lines that make up the kdSquares. Every line is
-- described by two points, start and end respectively. -- described by two points, start and end respectively.
kdLines :: KDTree P2 kdLines :: KDTree PT -> Square -> [(PT, PT)]
-> ((Double, Double), (Double, Double)) -- ^ square
-> [(P2, P2)]
kdLines (KTNode ln pt Horizontal rn) ((xmin, ymin), (xmax, ymax)) = kdLines (KTNode ln pt Horizontal rn) ((xmin, ymin), (xmax, ymax)) =
(\(x, _) -> [(p2 (x, ymin), p2 (x, ymax))]) (\(x, _) -> [(p2 (x, ymin), p2 (x, ymax))])
(unp2 pt) (unp2 pt)
@ -180,7 +179,7 @@ kdTreeDiag = Diag f
-- |Get the quad tree corresponding to the given points and diagram properties. -- |Get the quad tree corresponding to the given points and diagram properties.
qt :: [P2] -> DiagProp -> QuadTree P2 qt :: [PT] -> DiagProp -> QuadTree PT
qt vt p = quadTree vt (diagDimSquare p) qt vt p = quadTree vt (diagDimSquare p)
@ -193,9 +192,7 @@ quadPathSquare = Diag f
(uncurry rectByDiagonal # lw thin # lc red) (uncurry rectByDiagonal # lw thin # lc red)
(getSquare (stringToQuads (quadPath p)) (qt (mconcat vts) p, [])) (getSquare (stringToQuads (quadPath p)) (qt (mconcat vts) p, []))
where where
getSquare :: [Either Quad Orient] getSquare :: [Either Quad Orient] -> QTZipper PT -> Square
-> QTZipper P2
-> ((Double, Double), (Double, Double))
getSquare [] z = getSquareByZipper (diagDimSquare p) z getSquare [] z = getSquareByZipper (diagDimSquare p) z
getSquare (q:qs) z = case q of getSquare (q:qs) z = case q of
Right x -> getSquare qs (fromMaybe z (findNeighbor x z)) Right x -> getSquare qs (fromMaybe z (findNeighbor x z))
@ -211,9 +208,7 @@ gifQuadPath = GifDiag f
(uncurry rectByDiagonal # lw thick # lc col) (uncurry rectByDiagonal # lw thick # lc col)
<$> getSquares (stringToQuads (quadPath p)) (qt vt p, []) <$> getSquares (stringToQuads (quadPath p)) (qt vt p, [])
where where
getSquares :: [Either Quad Orient] getSquares :: [Either Quad Orient] -> QTZipper PT -> [Square]
-> QTZipper P2
-> [((Double, Double), (Double, Double))]
getSquares [] z = [getSquareByZipper (diagDimSquare p) z] getSquares [] z = [getSquareByZipper (diagDimSquare p) z]
getSquares (q:qs) z = case q of getSquares (q:qs) z = case q of
Right x -> getSquareByZipper (diagDimSquare p) z : Right x -> getSquareByZipper (diagDimSquare p) z :
@ -233,7 +228,7 @@ treePretty = Diag f
. quadPath . quadPath
$ p) $ p)
where where
getCurQT :: [Either Quad Orient] -> QTZipper P2 -> QTZipper P2 getCurQT :: [Either Quad Orient] -> QTZipper PT -> QTZipper PT
getCurQT [] z = z getCurQT [] z = z
getCurQT (q:qs) z = case q of getCurQT (q:qs) z = case q of
Right x -> getCurQT qs (fromMaybe z (findNeighbor x z)) Right x -> getCurQT qs (fromMaybe z (findNeighbor x z))

View File

@ -15,15 +15,15 @@ data Diag =
Diag Diag
{ {
mkDiag :: DiagProp mkDiag :: DiagProp
-> [[P2]] -> [[PT]]
-> Diagram Cairo R2 -> Diagram Cairo R2
} }
| GifDiag | GifDiag
{ {
mkGifDiag :: DiagProp mkGifDiag :: DiagProp
-> Colour Double -> Colour Double
-> ([P2] -> [[P2]]) -> ([PT] -> [[PT]])
-> [P2] -> [PT]
-> [Diagram Cairo R2] -> [Diagram Cairo R2]
} }
| EmptyDiag (Diagram Cairo R2) | EmptyDiag (Diagram Cairo R2)
@ -49,7 +49,7 @@ data DiagProp = MkProp {
-- |The path to a quad in the quad tree. -- |The path to a quad in the quad tree.
quadPath :: String, quadPath :: String,
-- |The square for the kd-tree range search. -- |The square for the kd-tree range search.
rangeSquare :: ((Double, Double), (Double, Double)) rangeSquare :: Square
} }
@ -134,19 +134,19 @@ maybeDiag b d
| otherwise = mempty | otherwise = mempty
filterValidPT :: DiagProp -> [P2] -> [P2] filterValidPT :: DiagProp -> [PT] -> [PT]
filterValidPT = filterValidPT =
filter filter
. inRange . inRange
. diagDimSquare . diagDimSquare
diagDimSquare :: DiagProp -> ((Double, Double), (Double, Double)) diagDimSquare :: DiagProp -> Square
diagDimSquare p = dimToSquare (xDimension p) $ yDimension p diagDimSquare p = dimToSquare (xDimension p) $ yDimension p
-- |Draw a list of points. -- |Draw a list of points.
drawP :: [P2] -- ^ the points to draw drawP :: [PT] -- ^ the points to draw
-> Double -- ^ dot size -> Double -- ^ dot size
-> Diagram Cairo R2 -- ^ the resulting diagram -> Diagram Cairo R2 -- ^ the resulting diagram
drawP [] _ = mempty drawP [] _ = mempty
@ -172,7 +172,7 @@ rectByDiagonal (xmin, ymin) (xmax, ymax) =
-- |Creates a Diagram from a point that shows the coordinates -- |Creates a Diagram from a point that shows the coordinates
-- in text format, such as "(1.0, 2.0)". -- in text format, such as "(1.0, 2.0)".
pointToTextCoord :: P2 -> Diagram Cairo R2 pointToTextCoord :: PT -> Diagram Cairo R2
pointToTextCoord pt = pointToTextCoord pt =
text ("(" ++ (show . trim') x ++ ", " ++ (show . trim') y ++ ")") # scale 10 text ("(" ++ (show . trim') x ++ ", " ++ (show . trim') y ++ ")") # scale 10
where where

View File

@ -2,6 +2,7 @@
module Graphics.Diagram.Gtk where module Graphics.Diagram.Gtk where
import Algebra.Vector(PT)
import qualified Data.ByteString.Char8 as B import qualified Data.ByteString.Char8 as B
import Data.List(find) import Data.List(find)
import Diagrams.Backend.Cairo import Diagrams.Backend.Cairo
@ -45,7 +46,7 @@ diagTreAlgos =
-- |Create the Diagram from the points. -- |Create the Diagram from the points.
diag :: DiagProp -> [DiagAlgo] -> [[P2]] -> Diagram Cairo R2 diag :: DiagProp -> [DiagAlgo] -> [[PT]] -> Diagram Cairo R2
diag p das vts = maybe mempty (\x -> mkDiag x p vts) diag p das vts = maybe mempty (\x -> mkDiag x p vts)
$ mconcat $ mconcat
-- get the actual [Diag] array -- get the actual [Diag] array

View File

@ -2,6 +2,7 @@
module Parser.Meshparser where module Parser.Meshparser where
import Algebra.Vector(PT)
import Control.Applicative import Control.Applicative
import Data.Attoparsec.ByteString.Char8 import Data.Attoparsec.ByteString.Char8
import Data.Either import Data.Either
@ -11,7 +12,7 @@ import Diagrams.TwoD.Types
-- |Convert a text String with multiple vertices and faces into -- |Convert a text String with multiple vertices and faces into
-- a list of vertices, ordered by the faces specification. -- a list of vertices, ordered by the faces specification.
meshFaceVertices :: B.ByteString -> [[P2]] meshFaceVertices :: B.ByteString -> [[PT]]
meshFaceVertices str = fmap (fmap (\y -> meshVertices str !! (y - 1))) meshFaceVertices str = fmap (fmap (\y -> meshVertices str !! (y - 1)))
(meshFaces str) (meshFaces str)
@ -19,7 +20,7 @@ meshFaceVertices str = fmap (fmap (\y -> meshVertices str !! (y - 1)))
-- |Convert a text String with multiple vertices into -- |Convert a text String with multiple vertices into
-- an array of float tuples. -- an array of float tuples.
meshVertices :: B.ByteString -- ^ the string to convert meshVertices :: B.ByteString -- ^ the string to convert
-> [P2] -- ^ the resulting vertice table -> [PT] -- ^ the resulting vertice table
meshVertices meshVertices
= fmap p2 = fmap p2
. rights . rights

View File

@ -82,40 +82,40 @@ instance Arbitrary P2 where
-- the point describing the lower left corner of the square -- the point describing the lower left corner of the square
-- must be part of the square -- must be part of the square
inRangeProp1 :: ((Double, Double), (Double, Double)) -> Bool inRangeProp1 :: Square -> Bool
inRangeProp1 sq@((x1, y1), _) = inRangeProp1 sq@((x1, y1), _) =
inRange sq (p2 (x1, y1)) inRange sq (p2 (x1, y1))
-- the point describing the upper right corner of the square -- the point describing the upper right corner of the square
-- must be part of the square -- must be part of the square
inRangeProp2 :: ((Double, Double), (Double, Double)) -> Bool inRangeProp2 :: Square -> Bool
inRangeProp2 sq@(_, (x2, y2)) = inRangeProp2 sq@(_, (x2, y2)) =
inRange sq (p2 (x2, y2)) inRange sq (p2 (x2, y2))
-- the point describing the upper left corner of the square -- the point describing the upper left corner of the square
-- must be part of the square -- must be part of the square
inRangeProp3 :: ((Double, Double), (Double, Double)) -> Bool inRangeProp3 :: Square -> Bool
inRangeProp3 sq@((x1, _), (_, y2)) = inRangeProp3 sq@((x1, _), (_, y2)) =
inRange sq (p2 (x1, y2)) inRange sq (p2 (x1, y2))
-- the point describing the lower right corner of the square -- the point describing the lower right corner of the square
-- must be part of the square -- must be part of the square
inRangeProp4 :: ((Double, Double), (Double, Double)) -> Bool inRangeProp4 :: Square -> Bool
inRangeProp4 sq@((_, y1), (x2, _)) = inRangeProp4 sq@((_, y1), (x2, _)) =
inRange sq (p2 (x2, y1)) inRange sq (p2 (x2, y1))
-- generating random points within the square -- generating random points within the square
inRangeProp5 :: ((Double, Double), (Double, Double)) -> Positive Double -> Positive Double -> Bool inRangeProp5 :: Square -> Positive Double -> Positive Double -> Bool
inRangeProp5 sq@((x1, y1), (x2, y2)) (Positive a) (Positive b) = inRangeProp5 sq@((x1, y1), (x2, y2)) (Positive a) (Positive b) =
inRange sq (p2 (x1 + ((x2 - x1) / (a + 1)), y1 + ((y2 - y1) / (b + 1)))) inRange sq (p2 (x1 + ((x2 - x1) / (a + 1)), y1 + ((y2 - y1) / (b + 1))))
-- generating random points outside of the square -- generating random points outside of the square
inRangeProp6 :: ((Double, Double), (Double, Double)) -> Positive Double -> Positive Double -> Bool inRangeProp6 :: Square -> Positive Double -> Positive Double -> Bool
inRangeProp6 sq@((x1, y1), (x2, y2)) (Positive a) (Positive b) = inRangeProp6 sq@((x1, y1), (x2, y2)) (Positive a) (Positive b) =
(not . inRange sq $ p2 (max x1 x2 + (a + 1), max y1 y2 + (b + 1))) (not . inRange sq $ p2 (max x1 x2 + (a + 1), max y1 y2 + (b + 1)))
&& (not . inRange sq $ p2 (max x1 x2 + (a + 1), max y1 y2 - (b + 1))) && (not . inRange sq $ p2 (max x1 x2 + (a + 1), max y1 y2 - (b + 1)))
@ -126,51 +126,51 @@ inRangeProp6 sq@((x1, y1), (x2, y2)) (Positive a) (Positive b) =
-- apply id function on the point -- apply id function on the point
onPTProp1 :: P2 -> Bool onPTProp1 :: PT -> Bool
onPTProp1 pt = onPT id pt == pt onPTProp1 pt = onPT id pt == pt
-- add a random value to the point coordinates -- add a random value to the point coordinates
onPTProp2 :: P2 -> Positive R2 -> Bool onPTProp2 :: PT -> Positive R2 -> Bool
onPTProp2 pt (Positive (R2 rx ry)) onPTProp2 pt (Positive (R2 rx ry))
= onPT (\(x, y) -> (x + rx, y + ry)) pt /= pt = onPT (\(x, y) -> (x + rx, y + ry)) pt /= pt
-- angle between two vectors both on the x-axis must be 0 -- angle between two vectors both on the x-axis must be 0
getAngleProp1 :: Positive R2 -> Positive R2 -> Bool getAngleProp1 :: Positive Vec -> Positive Vec -> Bool
getAngleProp1 (Positive (R2 x1 _)) (Positive (R2 x2 _)) getAngleProp1 (Positive (R2 x1 _)) (Positive (R2 x2 _))
= getAngle (R2 x1 0) (R2 x2 0) == 0 = getAngle (R2 x1 0) (R2 x2 0) == 0
-- angle between two vectors both on the y-axis must be 0 -- angle between two vectors both on the y-axis must be 0
getAngleProp2 :: Positive R2 -> Positive R2 -> Bool getAngleProp2 :: Positive Vec -> Positive Vec -> Bool
getAngleProp2 (Positive (R2 _ y1)) (Positive (R2 _ y2)) getAngleProp2 (Positive (R2 _ y1)) (Positive (R2 _ y2))
= getAngle (R2 0 y1) (R2 0 y2) == 0 = getAngle (R2 0 y1) (R2 0 y2) == 0
-- angle between two vectors both on the x-axis but with opposite direction -- angle between two vectors both on the x-axis but with opposite direction
-- must be pi -- must be pi
getAngleProp3 :: Positive R2 -> Positive R2 -> Bool getAngleProp3 :: Positive Vec -> Positive Vec -> Bool
getAngleProp3 (Positive (R2 x1 _)) (Positive (R2 x2 _)) getAngleProp3 (Positive (R2 x1 _)) (Positive (R2 x2 _))
= getAngle (R2 (negate x1) 0) (R2 x2 0) == pi = getAngle (R2 (negate x1) 0) (R2 x2 0) == pi
-- angle between two vectors both on the y-axis but with opposite direction -- angle between two vectors both on the y-axis but with opposite direction
-- must be pi -- must be pi
getAngleProp4 :: Positive R2 -> Positive R2 -> Bool getAngleProp4 :: Positive Vec -> Positive Vec -> Bool
getAngleProp4 (Positive (R2 _ y1)) (Positive (R2 _ y2)) getAngleProp4 (Positive (R2 _ y1)) (Positive (R2 _ y2))
= getAngle (R2 0 (negate y1)) (R2 0 y2) == pi = getAngle (R2 0 (negate y1)) (R2 0 y2) == pi
-- angle between vector in x-axis direction and y-axis direction must be -- angle between vector in x-axis direction and y-axis direction must be
-- p/2 -- p/2
getAngleProp5 :: Positive R2 -> Positive R2 -> Bool getAngleProp5 :: Positive Vec -> Positive Vec -> Bool
getAngleProp5 (Positive (R2 x1 _)) (Positive (R2 _ y2)) getAngleProp5 (Positive (R2 x1 _)) (Positive (R2 _ y2))
= getAngle (R2 x1 0) (R2 0 y2) == pi / 2 = getAngle (R2 x1 0) (R2 0 y2) == pi / 2
-- commutative -- commutative
getAngleProp6 :: Positive R2 -> Positive R2 -> Bool getAngleProp6 :: Positive Vec -> Positive Vec -> Bool
getAngleProp6 (Positive v1) (Positive v2) getAngleProp6 (Positive v1) (Positive v2)
= getAngle v1 v2 == getAngle v2 v1 = getAngle v1 v2 == getAngle v2 v1
@ -183,7 +183,7 @@ getAngleProp7 (PosRoundR2 v)
-- commutative -- commutative
scalarProdProp1 :: R2 -> R2 -> Bool scalarProdProp1 :: Vec -> Vec -> Bool
scalarProdProp1 v1 v2 = v1 `scalarProd` v2 == v2 `scalarProd` v1 scalarProdProp1 v1 v2 = v1 `scalarProd` v2 == v2 `scalarProd` v1
@ -212,7 +212,7 @@ scalarProdProp4 (RoundDouble s1) (RoundDouble s2) (RoundR2 v1) (RoundR2 v2)
-- orthogonal -- orthogonal
scalarProdProp5 :: Positive R2 -> Positive R2 -> Bool scalarProdProp5 :: Positive Vec -> Positive Vec -> Bool
scalarProdProp5 (Positive (R2 x1 _)) (Positive (R2 _ y2)) scalarProdProp5 (Positive (R2 x1 _)) (Positive (R2 _ y2))
= scalarProd (R2 x1 0) (R2 0 y2) == 0 = scalarProd (R2 x1 0) (R2 0 y2) == 0
@ -226,40 +226,40 @@ dimToSquareProp1 (x1, x2) (y1, y2) =
-- multiply scalar with result of vecLength or with the vector itself... -- multiply scalar with result of vecLength or with the vector itself...
-- both results must be the same. We can't check against 0 -- both results must be the same. We can't check against 0
-- because of sqrt in vecLength. -- because of sqrt in vecLength.
vecLengthProp1 :: PosRoundDouble -> R2 -> Bool vecLengthProp1 :: PosRoundDouble -> Vec -> Bool
vecLengthProp1 (PosRoundDouble r) v vecLengthProp1 (PosRoundDouble r) v
= abs (vecLength v * r - vecLength (scalarMul r v)) < 0.0001 = abs (vecLength v * r - vecLength (scalarMul r v)) < 0.0001
-- convert to vector and back again -- convert to vector and back again
pt2VecProp1 :: P2 -> Bool pt2VecProp1 :: PT -> Bool
pt2VecProp1 pt = (vec2Pt . pt2Vec $ pt) == pt pt2VecProp1 pt = (vec2Pt . pt2Vec $ pt) == pt
-- unbox coordinates and check if equal -- unbox coordinates and check if equal
pt2VecProp2 :: P2 -> Bool pt2VecProp2 :: PT -> Bool
pt2VecProp2 pt = (unr2 . pt2Vec $ pt) == unp2 pt pt2VecProp2 pt = (unr2 . pt2Vec $ pt) == unp2 pt
-- convert to point and back again -- convert to point and back again
vec2PtProp1 :: R2 -> Bool vec2PtProp1 :: Vec -> Bool
vec2PtProp1 v = (pt2Vec . vec2Pt $ v) == v vec2PtProp1 v = (pt2Vec . vec2Pt $ v) == v
-- unbox coordinates and check if equal -- unbox coordinates and check if equal
vec2PtProp2 :: R2 -> Bool vec2PtProp2 :: Vec -> Bool
vec2PtProp2 v = (unp2 . vec2Pt $ v) == unr2 v vec2PtProp2 v = (unp2 . vec2Pt $ v) == unr2 v
-- vector from a to b must not be the same as b to a -- vector from a to b must not be the same as b to a
vp2Prop1 :: P2 -> P2 -> Bool vp2Prop1 :: PT -> PT -> Bool
vp2Prop1 p1' p2' vp2Prop1 p1' p2'
| p1' == origin && p2' == origin = True | p1' == origin && p2' == origin = True
| otherwise = vp2 p1' p2' /= vp2 p2' p1' | otherwise = vp2 p1' p2' /= vp2 p2' p1'
-- negating vector from a to be must be the same as vector b to a -- negating vector from a to be must be the same as vector b to a
vp2Prop2 :: P2 -> P2 -> Bool vp2Prop2 :: PT -> PT -> Bool
vp2Prop2 p1' p2' vp2Prop2 p1' p2'
| p1' == origin && p2' == origin = True | p1' == origin && p2' == origin = True
| otherwise = vp2 p1' p2' == (\(R2 x y) -> negate x ^& negate y) | otherwise = vp2 p1' p2' == (\(R2 x y) -> negate x ^& negate y)
@ -270,5 +270,5 @@ vp2Prop2 p1' p2'
-- determinant of the 3 same points is always 0 -- determinant of the 3 same points is always 0
detProp1 :: P2 -> Bool detProp1 :: PT -> Bool
detProp1 pt' = det pt' pt' pt' == 0 detProp1 pt' = det pt' pt' pt' == 0