ALGO: improve readability

This commit is contained in:
hasufell 2014-10-12 02:11:47 +02:00
parent 24810e5970
commit 6dc4fae415
No known key found for this signature in database
GPG Key ID: 220CD1C5BDEED020

View File

@ -14,14 +14,14 @@ grahamGetCH :: [PT] -> [PT]
grahamGetCH vs = grahamGetCH vs =
-- merge upper hull with lower hull while discarding -- merge upper hull with lower hull while discarding
-- the duplicated points from the lower hull -- the duplicated points from the lower hull
f (reverse uH) uHRest ++ tailInit (f (reverse lH) lHRest) scan uH uHRest ++ tailInit (scan lH lHRest)
where where
-- sort lexicographically by x values (ties are resolved by y values) -- sort lexicographically by x values (ties are resolved by y values)
sortedVs = fmap p2 . sortLex . fmap unp2 $ vs sortedXY = fmap p2 . sortLex . fmap unp2 $ vs
-- lists for lower hull -- lists for lower hull
(lH, lHRest) = splitAt 2 sortedVs (lH, lHRest) = first reverse . splitAt 2 $ sortedXY
-- lists for upper hull -- lists for upper hull
(uH, uHRest) = splitAt 2 . reverse $ sortedVs (uH, uHRest) = first reverse . splitAt 2 . reverse $ sortedXY
-- This is the actual algorithm. -- This is the actual algorithm.
-- If we have a list say: -- If we have a list say:
-- [(100, 100), (200, 450), (250, 250), (300, 400), (400, 200)] -- [(100, 100), (200, 450), (250, 250), (300, 400), (400, 200)]
@ -31,42 +31,45 @@ grahamGetCH vs =
-- --
-- The first list is reversed since we only care about the last -- The first list is reversed since we only care about the last
-- 3 elements and want to stay efficient. -- 3 elements and want to stay efficient.
f (y:z:xs) (x:ys) scan :: [PT] -- ^ the starting convex hull points
-> [PT] -- ^ the rest of the points
-> [PT] -- ^ all convex hull points
scan (y:z:xs) (x:ys)
-- last 3 elements are ccw, but there are elements left to check -- last 3 elements are ccw, but there are elements left to check
| ccw z y x = f (x:y:z:xs) ys | ccw z y x = scan (x:y:z:xs) ys
-- not ccw, pop one out -- not ccw, pop one out
| otherwise = f (x:z:xs) ys | otherwise = scan (x:z:xs) ys
f (x:y:z:xs) [] scan (x:y:z:xs) []
-- nothing left and last 3 elements are ccw, so return -- nothing left and last 3 elements are ccw, so return
| ccw z y x = x:y:z:xs | ccw z y x = x:y:z:xs
-- not ccw, pop one out -- not ccw, pop one out
| otherwise = f (x:z:xs) [] | otherwise = scan (x:z:xs) []
f xs _ = xs scan xs _ = xs
-- |Compute all steps of the graham scan algorithm to allow -- |Compute all steps of the graham scan algorithm to allow
-- visualizing it. -- visualizing it.
grahamGetCHSteps :: [PT] -> [[PT]] grahamGetCHSteps :: [PT] -> [[PT]]
grahamGetCHSteps vs = grahamGetCHSteps vs =
(++) (reverse . g (length vs) (reverse lH) $ lHRest) . (++) (reverse . g (length vs) lH $ lHRest) .
fmap (\x -> (last . reverse . g (length vs) (reverse lH) $ lHRest) fmap (\x -> (last . reverse . g (length vs) lH $ lHRest)
++ x) $ ++ x) $
(init . reverse . g (length vs) (reverse uH) $ uHRest) (init . reverse . g (length vs) uH $ uHRest)
where where
sortedVs = fmap p2 . sortLex . fmap unp2 $ vs sortedXY = fmap p2 . sortLex . fmap unp2 $ vs
(lH, lHRest) = splitAt 2 sortedVs (lH, lHRest) = first reverse . splitAt 2 $ sortedXY
(uH, uHRest) = splitAt 2 . reverse $ sortedVs (uH, uHRest) = first reverse . splitAt 2 . reverse $ sortedXY
g c xs' ys' g c xs' ys'
| c >= 0 = f 0 xs' ys' : g (c - 1) xs' ys' | c >= 0 = scan 0 xs' ys' : g (c - 1) xs' ys'
| otherwise = [] | otherwise = []
where where
f c' (y:z:xs) (x:ys) scan c' (y:z:xs) (x:ys)
| c' >= c = reverse (y:z:xs) | c' >= c = reverse (y:z:xs)
| ccw z y x = f (c' + 1) (x:y:z:xs) ys | ccw z y x = scan (c' + 1) (x:y:z:xs) ys
| otherwise = f (c' + 1) (x:z:xs) ys | otherwise = scan (c' + 1) (x:z:xs) ys
f _ [x,y] [] = [y,x] scan _ [x,y] [] = [y,x]
f c' (x:y:z:xs) [] scan c' (x:y:z:xs) []
| c' >= c = reverse (x:y:z:xs) | c' >= c = reverse (x:y:z:xs)
| ccw z y x = x:y:z:xs | ccw z y x = x:y:z:xs
| otherwise = f (c' + 1) (x:z:xs) [] | otherwise = scan (c' + 1) (x:z:xs) []
f _ xs _ = reverse xs scan _ xs _ = reverse xs