From b5ecd16a2e99404158c8b2783521d529594d1152 Mon Sep 17 00:00:00 2001 From: hasufell Date: Wed, 4 Feb 2015 00:51:03 +0100 Subject: [PATCH] Revert "Remove almost all 'type' usage to make types more transparent" This reverts commit 5120a44d0f77f02b55c9efc902daacb62b998938. Conflicts: Parser/Meshparser.hs --- Algebra/Polygon.hs | 19 ++++---- Algebra/Vector.hs | 63 ++++++++++++++------------ Algorithms/GrahamScan.hs | 19 ++++---- Algorithms/KDTree.hs | 30 ++++++------- Algorithms/PolygonIntersection.hs | 26 +++++------ Algorithms/PolygonTriangulation.hs | 71 +++++++++++++++--------------- Algorithms/QuadTree.hs | 21 ++++----- Graphics/Diagram/AlgoDiags.hs | 17 +++---- Graphics/Diagram/Core.hs | 16 +++---- Graphics/Diagram/Gtk.hs | 3 +- Parser/Meshparser.hs | 5 ++- Test/Vector.hs | 48 ++++++++++---------- 12 files changed, 166 insertions(+), 172 deletions(-) diff --git a/Algebra/Polygon.hs b/Algebra/Polygon.hs index 3b1d5e3..cd1d654 100644 --- a/Algebra/Polygon.hs +++ b/Algebra/Polygon.hs @@ -4,15 +4,14 @@ module Algebra.Polygon where import Algebra.Vector import Data.Maybe -import Diagrams.TwoD.Types import MyPrelude -- |Split a polygon by a given segment which must be vertices of the -- polygon (returns empty array otherwise). -splitPoly :: [P2] - -> (P2, P2) - -> [[P2]] +splitPoly :: [PT] + -> Segment + -> [[PT]] splitPoly pts (a, b) | elem a pts && elem b pts = [b : takeWhile (/= b) shiftedPoly, a : dropWhile (/= b) shiftedPoly] @@ -22,7 +21,7 @@ splitPoly pts (a, b) -- |Get all edges of a polygon. -polySegments :: [P2] -> [(P2, P2)] +polySegments :: [PT] -> [Segment] polySegments p@(x':_:_:_) = go p ++ [(last p, x')] where go (x:y:xs) = (x, y) : go (y:xs) @@ -33,7 +32,7 @@ polySegments _ = [] -- |Check whether the given segment is inside the polygon. -- This doesn't check for segments that are completely outside -- of the polygon yet. -isInsidePoly :: [P2] -> (P2, P2) -> Bool +isInsidePoly :: [PT] -> Segment -> Bool isInsidePoly pts seg = null . catMaybes @@ -42,21 +41,21 @@ isInsidePoly pts seg = -- |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 -- |Check whether the polygon is a triangle polygon. -isTrianglePoly :: [P2] -> Bool +isTrianglePoly :: [PT] -> Bool isTrianglePoly [_, _, _] = True isTrianglePoly _ = False -- |Get all triangle polygons. -triangleOnly :: [[P2]] -> [[P2]] +triangleOnly :: [[PT]] -> [[PT]] triangleOnly = filter isTrianglePoly -- |Get all non-triangle polygons. -nonTriangleOnly :: [[P2]] -> [[P2]] +nonTriangleOnly :: [[PT]] -> [[PT]] nonTriangleOnly = filter (not . isTrianglePoly) diff --git a/Algebra/Vector.hs b/Algebra/Vector.hs index 12934dd..4bbbf44 100644 --- a/Algebra/Vector.hs +++ b/Algebra/Vector.hs @@ -13,6 +13,13 @@ import GHC.Float import MyPrelude +type Vec = R2 +type PT = P2 +type Coord = (Double, Double) +type Segment = (PT, PT) +type Square = (Coord, Coord) + + data Alignment = CW | CCW | CL @@ -24,13 +31,13 @@ data Alignment = CW -- ((xmin, ymin), (xmax, ymax)) dimToSquare :: (Double, Double) -- ^ x 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)) -- |Checks whether the Point is in a given Square. -inRange :: ((Double, Double), (Double, Double)) -- ^ the square: ((xmin, ymin), (xmax, ymax)) - -> P2 -- ^ Coordinate +inRange :: Square -- ^ the square: ((xmin, ymin), (xmax, ymax)) + -> PT -- ^ Coordinate -> Bool -- ^ result inRange ((xmin, ymin), (xmax, ymax)) (coords -> x :& y) = x >= min xmin xmax @@ -40,7 +47,7 @@ inRange ((xmin, ymin), (xmax, ymax)) (coords -> x :& y) -- |Get the angle between two vectors. -getAngle :: R2 -> R2 -> Double +getAngle :: Vec -> Vec -> Double getAngle a b = acos . flip (/) (vecLength a * vecLength b) @@ -49,50 +56,48 @@ getAngle a b = -- |Get the length of a vector. -vecLength :: R2 -> Double +vecLength :: Vec -> Double vecLength v = sqrt (x^(2 :: Int) + y^(2 :: Int)) where (x, y) = unr2 v -- |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 -- |Multiply a scalar with a vector. -scalarMul :: Double -> R2 -> R2 +scalarMul :: Double -> Vec -> Vec scalarMul d (R2 a b) = R2 (a * d) (b * d) -- |Construct a vector that points to a point from the origin. -pt2Vec :: P2 -> R2 +pt2Vec :: PT -> Vec pt2Vec = r2 . unp2 -- |Give the point which is at the coordinates the vector -- points to from the origin. -vec2Pt :: R2 -> P2 +vec2Pt :: Vec -> PT vec2Pt = p2 . unr2 -- |Construct a vector between two points. -vp2 :: P2 -- ^ vector origin - -> P2 -- ^ vector points here - -> R2 +vp2 :: PT -- ^ vector origin + -> PT -- ^ vector points here + -> Vec vp2 a b = pt2Vec b - pt2Vec a -- |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) = (bx - ax) * (cy - ay) - (by - ay) * (cx - ax) -- |Get the point where two lines intesect, if any. -intersectSeg' :: (P2, P2) -- ^ first segment - -> (P2, P2) -- ^ second segment - -> Maybe P2 +intersectSeg' :: Segment -> Segment -> Maybe PT intersectSeg' (a, b) (c, d) = glossToPt <$> intersectSegSeg (ptToGloss a) (ptToGloss b) @@ -105,7 +110,7 @@ intersectSeg' (a, b) (c, d) = -- |Get the point where two lines intesect, if any. Excludes the -- 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 Just x -> if x `notElem` [a,b,c,d] then Just a else Nothing Nothing -> Nothing @@ -115,7 +120,7 @@ intersectSeg'' (a, b) (c, d) = case intersectSeg' (a, b) (c, d) of -- * clock-wise -- * counter-clock-wise -- * collinear -getOrient :: P2 -> P2 -> P2 -> Alignment +getOrient :: PT -> PT -> PT -> Alignment getOrient a b c = case compare (det a b c) 0 of LT -> CW 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 --- connecting a-b-c. This is done by computing the determinant and --- checking the algebraic sign. -notcw :: P2 -> P2 -> P2 -> Bool +notcw :: PT -> PT -> PT -> Bool notcw a b c = case getOrient a b c of CW -> False _ -> 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 --- connecting a-b-c. This is done by computing the determinant and --- checking the algebraic sign. -cw :: P2 -> P2 -> P2 -> Bool +cw :: PT -> PT -> PT -> Bool cw a b c = not . notcw a b $ c -- |Sort X and Y coordinates lexicographically. -sortedXY :: [P2] -> [P2] +sortedXY :: [PT] -> [PT] sortedXY = fmap p2 . sortLex . fmap unp2 -- |Sort Y and X coordinates lexicographically. -sortedYX :: [P2] -> [P2] +sortedYX :: [PT] -> [PT] sortedYX = fmap p2 . sortLexSwapped . fmap unp2 -- |Sort all points according to their X-coordinates only. -sortedX :: [P2] -> [P2] +sortedX :: [PT] -> [PT] sortedX xs = fmap p2 . sortBy (\(a1, _) (a2, _) -> compare a1 a2) @@ -157,7 +162,7 @@ sortedX xs = -- |Sort all points according to their Y-coordinates only. -sortedY :: [P2] -> [P2] +sortedY :: [PT] -> [PT] sortedY xs = fmap p2 . sortBy (\(_, b1) (_, b2) -> compare b1 b2) @@ -165,25 +170,25 @@ sortedY xs = -- |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 -- |Compare the y-coordinate of two points. -ptCmpY :: P2 -> P2 -> Ordering +ptCmpY :: PT -> PT -> Ordering ptCmpY (coords -> _ :& y1) (coords -> _ :& y2) = compare y1 y2 -- |Compare the x-coordinate of two points. -ptCmpX :: P2 -> P2 -> Ordering +ptCmpX :: PT -> PT -> Ordering ptCmpX (coords -> x1 :& _) (coords -> x2 :& _) = compare x1 x2 -posInfPT :: P2 +posInfPT :: PT posInfPT = p2 (read "Infinity", read "Infinity") -negInfPT :: P2 +negInfPT :: PT negInfPT = p2 (negate . read $ "Infinity", negate . read $ "Infinity") diff --git a/Algorithms/GrahamScan.hs b/Algorithms/GrahamScan.hs index d394fae..1cd4ac9 100644 --- a/Algorithms/GrahamScan.hs +++ b/Algorithms/GrahamScan.hs @@ -3,7 +3,6 @@ module Algorithms.GrahamScan where import Algebra.Vector -import Diagrams.TwoD.Types import MyPrelude @@ -75,18 +74,18 @@ ys = [] return [(100, 100), (400, 200)] ========================================================= --} -grahamCH :: [P2] -> [P2] +grahamCH :: [PT] -> [PT] grahamCH vs = grahamUCH vs ++ (tailInit . grahamLCH $ vs) -- |Get the lower part of the convex hull. -grahamLCH :: [P2] -> [P2] +grahamLCH :: [PT] -> [PT] grahamLCH vs = uncurry (\x y -> last . scanH x $ y) (first reverse . splitAt 3 . sortedXY $ vs) -- |Get the upper part of the convex hull. -grahamUCH :: [P2] -> [P2] +grahamUCH :: [PT] -> [PT] grahamUCH vs = uncurry (\x y -> last . scanH x $ y) (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. -- Also, the first list is expected to be reversed since we only care -- about the last 3 elements and want to stay efficient. -scanH :: [P2] -- ^ the first 3 starting points in reversed order - -> [P2] -- ^ the rest of the points - -> [[P2]] -- ^ all convex hull points iterations for the half +scanH :: [PT] -- ^ the first 3 starting points in reversed order + -> [PT] -- ^ the rest of the points + -> [[PT]] -- ^ all convex hull points iterations for the half scanH hs@(x:y:z:xs) (r':rs') | notcw z y x = hs : scanH (r':hs) 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 -- visualizing it. -- 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' -- |Get all iterations of the upper hull of the graham scan algorithm. -grahamUHSteps :: [P2] -> [[P2]] +grahamUHSteps :: [PT] -> [[PT]] grahamUHSteps vs = (++) [getLastX 2 . sortedXY $ vs] . rmdups @@ -128,7 +127,7 @@ grahamUHSteps vs = -- |Get all iterations of the lower hull of the graham scan algorithm. -grahamLHSteps :: [P2] -> [[P2]] +grahamLHSteps :: [PT] -> [[PT]] grahamLHSteps vs = (++) [take 2 . sortedXY $ vs] . rmdups diff --git a/Algorithms/KDTree.hs b/Algorithms/KDTree.hs index 7d7b35f..82ab39a 100644 --- a/Algorithms/KDTree.hs +++ b/Algorithms/KDTree.hs @@ -42,9 +42,9 @@ instance Not Direction where -- |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 - -> KDTree P2 -- ^ resulting kd-tree + -> KDTree PT -- ^ resulting kd-tree kdTree xs' = go (sortedX xs') (sortedY xs') where 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 -- partition' (pivot xs) (ys, xs) -- and get ((y1, y2), (x1, x2)). -partition' :: P2 -- ^ the pivot to partition against - -> (P2 -> P2 -> Ordering) -- ^ ptCmpY or ptCmpX - -> ([P2], [P2]) -- ^ both lists (X, Y) or (Y, X) - -> (([P2], [P2]), ([P2], [P2])) -- ^ ((x1, x2), (y1, y2)) or +partition' :: PT -- ^ the pivot to partition against + -> (PT -> PT -> Ordering) -- ^ ptCmpY or ptCmpX + -> ([PT], [PT]) -- ^ both lists (X, Y) or (Y, X) + -> (([PT], [PT]), ([PT], [PT])) -- ^ ((x1, x2), (y1, y2)) or -- ((y1, y2), (x1, x2)) partition' piv cmp' (xs, ys) = ((x1, x2), (y1, y2)) 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 -- Y. This function is unsafe as it does not check if there is a valid -- pivot. -partitionY :: ([P2], [P2]) -- ^ both lists (X, Y) - -> (([P2], [P2]), ([P2], [P2])) -- ^ ((x1, x2), (y1, y2)) +partitionY :: ([PT], [PT]) -- ^ both lists (X, Y) + -> (([PT], [PT]), ([PT], [PT])) -- ^ ((x1, x2), (y1, y2)) partitionY (xs, ys) = partition' (fromJust . pivot $ ys) ptCmpY (xs, ys) -- |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 -- pivot. -partitionX :: ([P2], [P2]) -- ^ both lists (X, Y) - -> (([P2], [P2]), ([P2], [P2])) -- ^ ((x1, x2), (y1, y2)) +partitionX :: ([PT], [PT]) -- ^ both lists (X, Y) + -> (([PT], [PT]), ([PT], [PT])) -- ^ ((x1, x2), (y1, y2)) partitionX (xs, ys) = (\(x, y) -> (y, x)) . 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 -- of the points found in the range and also gives back a pretty -- rose tree suitable for printing. -rangeSearch :: KDTree P2 -- ^ tree to search in - -> ((Double, Double), (Double, Double)) -- ^ square describing the range - -> ([P2], Tree String) +rangeSearch :: KDTree PT -> Square -> ([PT], Tree String) rangeSearch kd' sq' = (goPt kd' sq', goTree kd' sq' True) where -- 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 cur' dir = if' (dir == Vertical) snd fst -- All points in the range. - goPt :: KDTree P2 -> ((Double, Double), (Double, Double)) -> [P2] + goPt :: KDTree PT -> Square -> [PT] goPt KTNil _ = [] goPt (KTNode ln pt dir rn) sq = [pt | inRange sq pt] @@ -124,7 +122,7 @@ rangeSearch kd' sq' = (goPt kd' sq', goTree kd' sq' True) (goPt rn sq) []) -- 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 (KTNode ln pt dir rn) sq vis | ln == KTNil && rn == KTNil = Node treeText [] @@ -181,7 +179,7 @@ getDirection _ = Nothing -- |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 (KTNode ln val _ rn) = Node (show . unp2 $ val) [kdTreeToRoseTree ln, kdTreeToRoseTree rn] diff --git a/Algorithms/PolygonIntersection.hs b/Algorithms/PolygonIntersection.hs index 85998d3..5969b43 100644 --- a/Algorithms/PolygonIntersection.hs +++ b/Algorithms/PolygonIntersection.hs @@ -18,14 +18,14 @@ import QueueEx -- successor are saved for convenience. data PolyPT = PolyA { - id' :: P2 - , pre :: P2 - , suc :: P2 + id' :: PT + , pre :: PT + , suc :: PT } | PolyB { - id' :: P2 - , pre :: P2 - , suc :: P2 + id' :: PT + , pre :: PT + , suc :: PT } deriving (Show, Eq) @@ -42,7 +42,7 @@ isPolyB = not . isPolyA -- |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. -- This is done in O(n). -sortLexPoly :: [P2] -> [P2] +sortLexPoly :: [PT] -> [PT] sortLexPoly ps = maybe [] (`shiftM` ps) (elemIndex (yMax ps) ps) where 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 -- the predecessor and successors are all saved. -mkPolyPTList :: (P2 -> P2 -> P2 -> PolyPT) -- ^ PolyA or PolyB function - -> [P2] -- ^ polygon points +mkPolyPTList :: (PT -> PT -> PT -> PolyPT) -- ^ PolyA or PolyB function + -> [PT] -- ^ polygon points -> [PolyPT] mkPolyPTList f' pts@(x':y':_:_) = f' x' (last pts) y' : go f' pts @@ -64,7 +64,7 @@ mkPolyPTList _ _ = [] -- |Sort the points of two polygons according to their y-coordinates, -- while saving the origin of that point. This is done in O(n). -sortLexPolys :: ([P2], [P2]) -> [PolyPT] +sortLexPolys :: ([PT], [PT]) -> [PolyPT] sortLexPolys (pA'@(_:_), pB'@(_:_)) = queueToList $ go (Q.fromList . mkPolyPTList PolyA . sortLexPoly $ pA') (Q.fromList . mkPolyPTList PolyB . sortLexPoly $ pB') @@ -104,7 +104,7 @@ sortLexPolys _ = [] -- |Get all points that intersect between both polygons. This is done -- in O(n). -intersectionPoints :: [PolyPT] -> [P2] +intersectionPoints :: [PolyPT] -> [PT] intersectionPoints xs' = rmdups . go $ xs' where go [] = [] @@ -113,7 +113,7 @@ intersectionPoints xs' = rmdups . go $ xs' -- Get the scan line or in other words the -- 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) where getSegment f = fromMaybe [] @@ -124,7 +124,7 @@ intersectionPoints xs' = rmdups . go $ xs' -- Gets the actual intersections between the segments of -- both polygons we currently examine. This is done in O(1) -- since we have max 4 segments. - segIntersections :: ([(P2, P2)], [(P2, P2)]) -> [P2] + segIntersections :: ([Segment], [Segment]) -> [PT] segIntersections (a@(_:_), b@(_:_)) = catMaybes . fmap (\[x, y] -> intersectSeg' x y) diff --git a/Algorithms/PolygonTriangulation.hs b/Algorithms/PolygonTriangulation.hs index 5c34295..7313a96 100644 --- a/Algorithms/PolygonTriangulation.hs +++ b/Algorithms/PolygonTriangulation.hs @@ -6,7 +6,6 @@ import Algebra.Polygon import Algebra.Vector import qualified Control.Arrow as A import Data.Maybe -import Diagrams.TwoD.Types import Safe @@ -19,12 +18,12 @@ data VCategory = VStart -- |Classify all vertices on a polygon into five categories (see VCategory). -classifyList :: [P2] -> [(P2, VCategory)] +classifyList :: [PT] -> [(PT, VCategory)] classifyList p@(x:y:_:_) = -- need to handle the first and last element separately [classify (last p) x y] ++ go p ++ [classify (last . init $ p) (last p) x] where - go :: [P2] -> [(P2, VCategory)] + go :: [PT] -> [(PT, VCategory)] go (x':y':z':xs) = classify x' y' z' : go (y':z':xs) go _ = [] classifyList _ = [] @@ -32,10 +31,10 @@ classifyList _ = [] -- |Classify a vertex on a polygon given it's next and previous vertex -- into five categories (see VCategory). -classify :: P2 -- ^ prev vertex - -> P2 -- ^ classify this one - -> P2 -- ^ next vertex - -> (P2, VCategory) +classify :: PT -- ^ prev vertex + -> PT -- ^ classify this one + -> PT -- ^ next vertex + -> (PT, VCategory) classify prev v next | isVStart prev v next = (v, VStart) | isVSplit prev v next = (v, VSplit) @@ -46,9 +45,9 @@ classify prev v next -- |Whether the vertex, given it's next and previous vertex, -- is a start vertex. -isVStart :: P2 -- ^ previous vertex - -> P2 -- ^ vertice to check - -> P2 -- ^ next vertex +isVStart :: PT -- ^ previous vertex + -> PT -- ^ vertice to check + -> PT -- ^ next vertex -> Bool isVStart prev v next = 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, -- is a split vertex. -isVSplit :: P2 -- ^ previous vertex - -> P2 -- ^ vertice to check - -> P2 -- ^ next vertex +isVSplit :: PT -- ^ previous vertex + -> PT -- ^ vertice to check + -> PT -- ^ next vertex -> Bool isVSplit 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, -- is an end vertex. -isVEnd :: P2 -- ^ previous vertex - -> P2 -- ^ vertice to check - -> P2 -- ^ next vertex +isVEnd :: PT -- ^ previous vertex + -> PT -- ^ vertice to check + -> PT -- ^ next vertex -> Bool isVEnd prev v next = 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, -- is a merge vertex. -isVMerge :: P2 -- ^ previous vertex - -> P2 -- ^ vertice to check - -> P2 -- ^ next vertex +isVMerge :: PT -- ^ previous vertex + -> PT -- ^ vertice to check + -> PT -- ^ next vertex -> Bool isVMerge 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, -- is a regular vertex. -isVRegular :: P2 -- ^ previous vertex - -> P2 -- ^ vertice to check - -> P2 -- ^ next vertex +isVRegular :: PT -- ^ previous vertex + -> PT -- ^ vertice to check + -> PT -- ^ next vertex -> Bool isVRegular 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. -isYmonotone :: [P2] -> Bool +isYmonotone :: [PT] -> Bool isYmonotone poly = not . any (\x -> x == VSplit || x == VMerge) @@ -108,12 +107,12 @@ isYmonotone poly = -- |Partition P into y-monotone pieces. -monotonePartitioning :: [P2] -> [[P2]] +monotonePartitioning :: [PT] -> [[PT]] monotonePartitioning pts | isYmonotone pts = [pts] | otherwise = go (monotoneDiagonals pts) pts where - go :: [(P2, P2)] -> [P2] -> [[P2]] + go :: [Segment] -> [PT] -> [[PT]] go (x:xs) pts'@(_:_) | isYmonotone a && isYmonotone b = [a, b] | isYmonotone b = b : go xs a @@ -125,37 +124,37 @@ monotonePartitioning pts -- |Try to eliminate the merge and split vertices by computing the -- diagonals we have to use for splitting the polygon. -monotoneDiagonals :: [P2] -> [(P2, P2)] +monotoneDiagonals :: [PT] -> [Segment] monotoneDiagonals pts = catMaybes . go $ classifyList pts where - go :: [(P2, VCategory)] -> [Maybe (P2, P2)] + go :: [(PT, VCategory)] -> [Maybe Segment] go (x:xs) = case snd x of VMerge -> getSeg (belowS . fst $ x) (fst x) : go xs VSplit -> getSeg (aboveS . fst $ x) (fst x) : go xs _ -> [] ++ go xs go [] = [] - getSeg :: [P2] -- all points above/below the current point - -> P2 -- current point - -> Maybe (P2, P2) + getSeg :: [PT] -- all points above/below the current point + -> PT -- current point + -> Maybe Segment getSeg [] _ = Nothing getSeg (z:zs) pt | isInsidePoly pts (z, pt) = Just (z, pt) | otherwise = getSeg zs pt - aboveS :: P2 -> [P2] + aboveS :: PT -> [PT] aboveS pt = tail . dropWhile (/= pt) $ sortedYX pts - belowS :: P2 -> [P2] + belowS :: PT -> [PT] belowS pt = reverse . takeWhile (/= pt) $ sortedYX pts -- |Triangulate a y-monotone polygon. -triangulate :: [P2] -> [[P2]] +triangulate :: [PT] -> [[PT]] triangulate pts = go pts . A.first reverse . splitAt 3 . reverse . sortedYX $ pts where - go :: [P2] -- current polygon - -> ([P2], [P2]) -- (stack of visited vertices, rest) + go :: [PT] -- current polygon + -> ([PT], [PT]) -- (stack of visited vertices, rest) -- sorted by Y-coordinate - -> [[P2]] + -> [[PT]] go xs (p@[_, _], r:rs) = go xs (r:p, rs) go xs (p@(u:vi:vi1:ys), rs) -- case 1 and 3 diff --git a/Algorithms/QuadTree.hs b/Algorithms/QuadTree.hs index 19b5723..7251e0b 100644 --- a/Algorithms/QuadTree.hs +++ b/Algorithms/QuadTree.hs @@ -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. -nwSq, neSq, swSq, seSq :: ((Double, Double), (Double, Double)) -- ^ current square - -> ((Double, Double), (Double, Double)) -- ^ sub-square +nwSq, neSq, swSq, seSq :: Square -> Square 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) 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 -- space into quadrants, so that every leaf-quadrant stores either zero or one -- point. -quadTree :: [P2] -- ^ the points to divide - -> ((Double, Double), (Double, Double)) -- ^ the initial square around the points - -> QuadTree P2 -- ^ the quad tree +quadTree :: [PT] -- ^ the points to divide + -> Square -- ^ the initial square around the points + -> QuadTree PT -- ^ the quad tree quadTree [] _ = TNil quadTree [pt] _ = TLeaf pt 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. -quadTreeSquares :: ((Double, Double), (Double, Double)) -- ^ the initial square around the points - -> QuadTree P2 -- ^ the quad tree - -> [((Double, Double), (Double, Double))] -- ^ all squares of the quad tree +quadTreeSquares :: Square -- ^ the initial square around the points + -> QuadTree PT -- ^ the quad tree + -> [Square] -- ^ all squares of the quad tree quadTreeSquares sq (TNil) = [sq] quadTreeSquares sq (TLeaf _) = [sq] 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 -- square. -getSquareByZipper :: ((Double, Double), (Double, Double)) -- ^ top square - -> QTZipper a - -> ((Double, Double), (Double, Double)) -- ^ current square +getSquareByZipper :: Square -> QTZipper a -> Square getSquareByZipper sq z = go sq (reverse . snd $ z) where go sq' [] = sq' @@ -203,7 +200,7 @@ lookupByNeighbors :: [Orient] -> QTZipper a -> Maybe (QTZipper a) lookupByNeighbors = flip (foldlM (flip findNeighbor)) -quadTreeToRoseTree :: QTZipper P2 -> Tree String +quadTreeToRoseTree :: QTZipper PT -> Tree String quadTreeToRoseTree z' = go (rootNode z') where go z = case z of diff --git a/Graphics/Diagram/AlgoDiags.hs b/Graphics/Diagram/AlgoDiags.hs index 2c6fba2..6e12c73 100644 --- a/Graphics/Diagram/AlgoDiags.hs +++ b/Graphics/Diagram/AlgoDiags.hs @@ -2,6 +2,7 @@ module Graphics.Diagram.AlgoDiags where +import Algebra.Vector(PT,Square) import Algorithms.GrahamScan import Algorithms.QuadTree import Algorithms.KDTree @@ -123,9 +124,7 @@ kdSquares = Diag f where -- Gets all lines that make up the kdSquares. Every line is -- described by two points, start and end respectively. - kdLines :: KDTree P2 - -> ((Double, Double), (Double, Double)) -- ^ square - -> [(P2, P2)] + kdLines :: KDTree PT -> Square -> [(PT, PT)] kdLines (KTNode ln pt Horizontal rn) ((xmin, ymin), (xmax, ymax)) = (\(x, _) -> [(p2 (x, ymin), p2 (x, ymax))]) (unp2 pt) @@ -180,7 +179,7 @@ kdTreeDiag = Diag f -- |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) @@ -193,9 +192,7 @@ quadPathSquare = Diag f (uncurry rectByDiagonal # lw thin # lc red) (getSquare (stringToQuads (quadPath p)) (qt (mconcat vts) p, [])) where - getSquare :: [Either Quad Orient] - -> QTZipper P2 - -> ((Double, Double), (Double, Double)) + getSquare :: [Either Quad Orient] -> QTZipper PT -> Square getSquare [] z = getSquareByZipper (diagDimSquare p) z getSquare (q:qs) z = case q of Right x -> getSquare qs (fromMaybe z (findNeighbor x z)) @@ -211,9 +208,7 @@ gifQuadPath = GifDiag f (uncurry rectByDiagonal # lw thick # lc col) <$> getSquares (stringToQuads (quadPath p)) (qt vt p, []) where - getSquares :: [Either Quad Orient] - -> QTZipper P2 - -> [((Double, Double), (Double, Double))] + getSquares :: [Either Quad Orient] -> QTZipper PT -> [Square] getSquares [] z = [getSquareByZipper (diagDimSquare p) z] getSquares (q:qs) z = case q of Right x -> getSquareByZipper (diagDimSquare p) z : @@ -233,7 +228,7 @@ treePretty = Diag f . quadPath $ p) where - getCurQT :: [Either Quad Orient] -> QTZipper P2 -> QTZipper P2 + getCurQT :: [Either Quad Orient] -> QTZipper PT -> QTZipper PT getCurQT [] z = z getCurQT (q:qs) z = case q of Right x -> getCurQT qs (fromMaybe z (findNeighbor x z)) diff --git a/Graphics/Diagram/Core.hs b/Graphics/Diagram/Core.hs index f072639..c31bfb4 100644 --- a/Graphics/Diagram/Core.hs +++ b/Graphics/Diagram/Core.hs @@ -15,15 +15,15 @@ data Diag = Diag { mkDiag :: DiagProp - -> [[P2]] + -> [[PT]] -> Diagram Cairo R2 } | GifDiag { mkGifDiag :: DiagProp -> Colour Double - -> ([P2] -> [[P2]]) - -> [P2] + -> ([PT] -> [[PT]]) + -> [PT] -> [Diagram Cairo R2] } | EmptyDiag (Diagram Cairo R2) @@ -49,7 +49,7 @@ data DiagProp = MkProp { -- |The path to a quad in the quad tree. quadPath :: String, -- |The square for the kd-tree range search. - rangeSquare :: ((Double, Double), (Double, Double)) + rangeSquare :: Square } @@ -134,19 +134,19 @@ maybeDiag b d | otherwise = mempty -filterValidPT :: DiagProp -> [P2] -> [P2] +filterValidPT :: DiagProp -> [PT] -> [PT] filterValidPT = filter . inRange . diagDimSquare -diagDimSquare :: DiagProp -> ((Double, Double), (Double, Double)) +diagDimSquare :: DiagProp -> Square diagDimSquare p = dimToSquare (xDimension p) $ yDimension p -- |Draw a list of points. -drawP :: [P2] -- ^ the points to draw +drawP :: [PT] -- ^ the points to draw -> Double -- ^ dot size -> Diagram Cairo R2 -- ^ the resulting diagram drawP [] _ = mempty @@ -172,7 +172,7 @@ rectByDiagonal (xmin, ymin) (xmax, ymax) = -- |Creates a Diagram from a point that shows the coordinates -- in text format, such as "(1.0, 2.0)". -pointToTextCoord :: P2 -> Diagram Cairo R2 +pointToTextCoord :: PT -> Diagram Cairo R2 pointToTextCoord pt = text ("(" ++ (show . trim') x ++ ", " ++ (show . trim') y ++ ")") # scale 10 where diff --git a/Graphics/Diagram/Gtk.hs b/Graphics/Diagram/Gtk.hs index b0a9e0c..462d7b2 100644 --- a/Graphics/Diagram/Gtk.hs +++ b/Graphics/Diagram/Gtk.hs @@ -2,6 +2,7 @@ module Graphics.Diagram.Gtk where +import Algebra.Vector(PT) import qualified Data.ByteString.Char8 as B import Data.List(find) import Diagrams.Backend.Cairo @@ -45,7 +46,7 @@ diagTreAlgos = -- |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) $ mconcat -- get the actual [Diag] array diff --git a/Parser/Meshparser.hs b/Parser/Meshparser.hs index 2f4cbec..2e2474d 100644 --- a/Parser/Meshparser.hs +++ b/Parser/Meshparser.hs @@ -2,6 +2,7 @@ module Parser.Meshparser where +import Algebra.Vector(PT) import Control.Applicative import Data.Attoparsec.ByteString.Char8 import Data.Either @@ -11,7 +12,7 @@ import Diagrams.TwoD.Types -- |Convert a text String with multiple vertices and faces into -- 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))) (meshFaces str) @@ -19,7 +20,7 @@ meshFaceVertices str = fmap (fmap (\y -> meshVertices str !! (y - 1))) -- |Convert a text String with multiple vertices into -- an array of float tuples. meshVertices :: B.ByteString -- ^ the string to convert - -> [P2] -- ^ the resulting vertice table + -> [PT] -- ^ the resulting vertice table meshVertices = fmap p2 . rights diff --git a/Test/Vector.hs b/Test/Vector.hs index 358d567..52c1423 100644 --- a/Test/Vector.hs +++ b/Test/Vector.hs @@ -82,40 +82,40 @@ instance Arbitrary P2 where -- the point describing the lower left corner of the square -- must be part of the square -inRangeProp1 :: ((Double, Double), (Double, Double)) -> Bool +inRangeProp1 :: Square -> Bool inRangeProp1 sq@((x1, y1), _) = inRange sq (p2 (x1, y1)) -- the point describing the upper right corner of the square -- must be part of the square -inRangeProp2 :: ((Double, Double), (Double, Double)) -> Bool +inRangeProp2 :: Square -> Bool inRangeProp2 sq@(_, (x2, y2)) = inRange sq (p2 (x2, y2)) -- the point describing the upper left corner of the square -- must be part of the square -inRangeProp3 :: ((Double, Double), (Double, Double)) -> Bool +inRangeProp3 :: Square -> Bool inRangeProp3 sq@((x1, _), (_, y2)) = inRange sq (p2 (x1, y2)) -- the point describing the lower right corner of the square -- must be part of the square -inRangeProp4 :: ((Double, Double), (Double, Double)) -> Bool +inRangeProp4 :: Square -> Bool inRangeProp4 sq@((_, y1), (x2, _)) = inRange sq (p2 (x2, y1)) -- 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) = inRange sq (p2 (x1 + ((x2 - x1) / (a + 1)), y1 + ((y2 - y1) / (b + 1)))) -- 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) = (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 -onPTProp1 :: P2 -> Bool +onPTProp1 :: PT -> Bool onPTProp1 pt = onPT id pt == pt -- add a random value to the point coordinates -onPTProp2 :: P2 -> Positive R2 -> Bool +onPTProp2 :: PT -> Positive R2 -> Bool onPTProp2 pt (Positive (R2 rx ry)) = onPT (\(x, y) -> (x + rx, y + ry)) pt /= pt -- 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 _)) = getAngle (R2 x1 0) (R2 x2 0) == 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)) = getAngle (R2 0 y1) (R2 0 y2) == 0 -- angle between two vectors both on the x-axis but with opposite direction -- must be pi -getAngleProp3 :: Positive R2 -> Positive R2 -> Bool +getAngleProp3 :: Positive Vec -> Positive Vec -> Bool getAngleProp3 (Positive (R2 x1 _)) (Positive (R2 x2 _)) = getAngle (R2 (negate x1) 0) (R2 x2 0) == pi -- angle between two vectors both on the y-axis but with opposite direction -- must be pi -getAngleProp4 :: Positive R2 -> Positive R2 -> Bool +getAngleProp4 :: Positive Vec -> Positive Vec -> Bool getAngleProp4 (Positive (R2 _ y1)) (Positive (R2 _ y2)) = getAngle (R2 0 (negate y1)) (R2 0 y2) == pi -- angle between vector in x-axis direction and y-axis direction must be -- p/2 -getAngleProp5 :: Positive R2 -> Positive R2 -> Bool +getAngleProp5 :: Positive Vec -> Positive Vec -> Bool getAngleProp5 (Positive (R2 x1 _)) (Positive (R2 _ y2)) = getAngle (R2 x1 0) (R2 0 y2) == pi / 2 -- commutative -getAngleProp6 :: Positive R2 -> Positive R2 -> Bool +getAngleProp6 :: Positive Vec -> Positive Vec -> Bool getAngleProp6 (Positive v1) (Positive v2) = getAngle v1 v2 == getAngle v2 v1 @@ -183,7 +183,7 @@ getAngleProp7 (PosRoundR2 v) -- commutative -scalarProdProp1 :: R2 -> R2 -> Bool +scalarProdProp1 :: Vec -> Vec -> Bool scalarProdProp1 v1 v2 = v1 `scalarProd` v2 == v2 `scalarProd` v1 @@ -212,7 +212,7 @@ scalarProdProp4 (RoundDouble s1) (RoundDouble s2) (RoundR2 v1) (RoundR2 v2) -- orthogonal -scalarProdProp5 :: Positive R2 -> Positive R2 -> Bool +scalarProdProp5 :: Positive Vec -> Positive Vec -> Bool scalarProdProp5 (Positive (R2 x1 _)) (Positive (R2 _ y2)) = 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... -- both results must be the same. We can't check against 0 -- because of sqrt in vecLength. -vecLengthProp1 :: PosRoundDouble -> R2 -> Bool +vecLengthProp1 :: PosRoundDouble -> Vec -> Bool vecLengthProp1 (PosRoundDouble r) v = abs (vecLength v * r - vecLength (scalarMul r v)) < 0.0001 -- convert to vector and back again -pt2VecProp1 :: P2 -> Bool +pt2VecProp1 :: PT -> Bool pt2VecProp1 pt = (vec2Pt . pt2Vec $ pt) == pt -- unbox coordinates and check if equal -pt2VecProp2 :: P2 -> Bool +pt2VecProp2 :: PT -> Bool pt2VecProp2 pt = (unr2 . pt2Vec $ pt) == unp2 pt -- convert to point and back again -vec2PtProp1 :: R2 -> Bool +vec2PtProp1 :: Vec -> Bool vec2PtProp1 v = (pt2Vec . vec2Pt $ v) == v -- unbox coordinates and check if equal -vec2PtProp2 :: R2 -> Bool +vec2PtProp2 :: Vec -> Bool vec2PtProp2 v = (unp2 . vec2Pt $ v) == unr2 v -- 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' | p1' == origin && p2' == origin = True | otherwise = vp2 p1' p2' /= vp2 p2' p1' -- 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' | p1' == origin && p2' == origin = True | 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 -detProp1 :: P2 -> Bool +detProp1 :: PT -> Bool detProp1 pt' = det pt' pt' pt' == 0