Created
July 12, 2013 02:47
-
-
Save maddenpj/5981047 to your computer and use it in GitHub Desktop.
Graham Scan algorithm for finding convex hull
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Data.List | |
data Point = Point Float Float deriving (Show, Eq) | |
data Direction = LeftDirection | |
| RightDirection | |
| StraightDirection deriving (Show) | |
dot :: Point -> Point -> Float | |
dot (Point x1 y1) (Point x2 y2) = x1*x2 + y1*y2 | |
plength :: Point -> Float | |
plength (Point x y) = sqrt (x*x + y*y) | |
angle :: Point -> Point -> Float | |
angle a b = acos ((dot a b)/(plength a * plength b)) | |
add :: Point -> Point -> Point | |
add (Point x2 y2) (Point x1 y1) = Point (x2+x1) (y2+y1) | |
diff :: Point -> Point -> Point | |
diff (Point x2 y2) (Point x1 y1) = Point (x2-x1) (y2-y1) | |
ccw :: Point -> Point -> Point -> Float | |
ccw (Point x1 y1) (Point x2 y2) (Point x3 y3) = (x2-x1)*(y3-y1) - (x3-x1)*(y2-y1) | |
drive :: Point -> Point -> Point -> Direction | |
drive a b c | |
| x < 0 = RightDirection | |
| x > 0 = LeftDirection | |
| x == 0 = StraightDirection | |
where x = ccw a b c | |
driveList :: [Point] -> [Direction] | |
driveList (a:b:c:xs) = drive a b c :driveList (b:c:xs) | |
driveList _ = [] | |
sortFindLowest :: Point -> Point -> Ordering | |
sortFindLowest (Point x1 y1) (Point x2 y2) | |
| y1 > y2 = GT | |
| y1 < y2 = LT | |
| y1 == y2 = if x1 > x2 then GT | |
else if x1 < x2 then LT | |
else EQ | |
sortWithLowest :: Point -> Point -> Point -> Ordering | |
sortWithLowest p a b | |
| angleA > angleB = GT | |
| angleA < angleB = LT | |
| angleA == angleB = EQ | |
where angleA = angle px a | |
angleB = angle px b | |
px = (Point 1 0) `diff` p | |
-- Takes unordered points, returns ordered list in shape of convex hull | |
grahamScan :: [Point] -> [Point] | |
grahamScan points = p:(foldl cullRight [] possible) | |
where possible = zip angularSort $ driveList (p:angularSort ++ [p]) | |
angularSort = sortBy (sortWithLowest p) $ tail geographicSort | |
p = head geographicSort | |
geographicSort = sortBy sortFindLowest points | |
cullRight :: [Point] -> (Point, Direction) -> [Point] | |
cullRight xs (_, RightDirection) = xs | |
cullRight xs (p, _) = xs ++ [p] | |
a = Point 0 0 | |
b = Point 1 0 | |
list = [a, b, (Point 1 1), (Point 2 1), (Point 2 2), (Point 1 3), (Point 0 2)] | |
grahamScan list |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment