Advertisement
Guest User

Untitled

a guest
Jun 26th, 2017
48
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. module GrahamScan where
  2. import Test.QuickCheck
  3. import Data.List
  4.  
  5. type Point           = (Double, Double)
  6. data Direction       = LeftDir
  7.                      | RightDir
  8.                      | Straight
  9.                      deriving (Eq, Show)
  10.  
  11. -- sample values
  12. ---------------------------
  13. pa = (2.0, 2.0)
  14. pb = (6.0, 3.0)
  15. pc = (3.0, 4.0)
  16. pd = (4.0, 5.0)
  17. pe = (1.0, 5.0)
  18. pf = (3.0, 3.0)
  19. pg = (4.0, 7.0)
  20. ph = (6.0, 7.0)
  21. pj = (5.0, 2.0)
  22. givenList  = [pa,pb,pc,pd,pe,pf]
  23. givenList2 = [pa,pb,pc,pd,pe,pf,pg]
  24. givenList3 = [pa,pb,pc,pd,pe,pf,pg,ph]
  25. givenList4 = [pa,pb,pc,pd,pe,pf,pg,ph,pj]
  26.  
  27. signToDir             :: Double -> Direction
  28. signToDir n | n >  0  =  RightDir
  29.             | n <  0  =  LeftDir
  30.             | n == 0  =  Straight
  31.  
  32. direction             :: (Point, Point, Point) -> Direction
  33. direction ((x1,y1),(x2,y2),(x3,y3)) = signToDir ((x2-x1)*(y3-y1) - (y2-y1)*(x3-x1))
  34.  
  35. group3                :: [a] -> [(a,a,a)]
  36. group3  xs | length xs < 3 = []
  37.            | otherwise     = zip3 xs (tail xs) (tail $ tail xs)      
  38.  
  39. dirList               :: [Point] -> [Direction]
  40. dirList ps | length ps < 3 = []
  41.            | otherwise     = map direction (group3 ps)
  42.  
  43. -- order of Point
  44. ordPoint              :: Point -> Point -> Ordering
  45. ordPoint (x1,y1) (x2,y2) | x1 == x2 && y1 == y2 = EQ
  46.                          | y1 < y2              = LT
  47.                          | y1 == y2 && x1 <  x2 = LT
  48.                          | otherwise            = GT
  49.  
  50. getPivot              :: [Point] -> Point
  51. getPivot              =  minimumBy ordPoint
  52.  
  53. -- cosin of two Points
  54. mycos                 :: Point -> Point -> Double
  55. mycos (x1,y1) (x2,y2) =  (x2 - x1)/sqrt((x2-x1)^2+(y2-y1)^2)
  56.  
  57. -- order of p1 p2 based on p
  58. ordCosPoint           :: Point -> Point -> Point -> Ordering
  59. ordCosPoint p p1 p2 | mycos p p1 == mycos p p2  = EQ
  60.                     | mycos p p1 >  mycos p p2  = GT
  61.                     | otherwise                 = LT
  62.  
  63. -- sort given List of Points by cosin based on pivot
  64. -- result begins with pivot
  65. sortedList              :: [Point] -> [Point]
  66. sortedList ps           =  p:(sortBy (ordCosPoint p) (filter (/= p) ps))
  67.                            where p = getPivot ps
  68.  
  69. -- utility function for graham scan
  70. -- add means
  71. ---- 'adding a point (x) from sortedList
  72. ----  to the candidates list of convex hull (xs)
  73. ----  as far as this adding does not violate the condition given by p (ifNotRight),
  74. ----  otherwise, regenerate the candidates list of convex hull.'
  75. add                    :: ((a,a,a) -> Bool) -> [a] -> a -> [a]
  76. add p xs x
  77.        | length xs < 2 =  (x:xs)
  78. add p (x1:x0:[]) x
  79.        | p (x, x0, x1) =  [x, x1, x0]
  80.        | otherwise     =  [x, x0]
  81. add p (x1:x0:xs) x
  82.        | p (x, x0, x1) =  (x:x1:x0:xs)
  83.        | otherwise     =  add p (x0:xs) x
  84.  
  85. ifNotRight            :: (Point, Point, Point) -> Bool
  86. ifNotRight ps         =  direction ps /= RightDir
  87.  
  88. -- graham scan
  89. gS                    :: [Point] -> [Point]
  90. gS                    =  foldl' (add ifNotRight) []
  91.  
  92. gScan                        :: [Point] -> [Point]
  93. gScan ps | length ps <= 3    = ps
  94.         | otherwise         = gS $ sortedList ps
  95.  
  96. -- result check
  97. isConvex                     :: [Point] -> Bool
  98. isConvex ps | length ps <= 3 =  True
  99.            | otherwise      =  all (/= LeftDir) (dirList ps)
  100.  
  101. prop_gScan ps = isConvex $ gScan ps
  102.       where types = ps::[Point]
  103.  
  104. {-
  105. exec check like this:
  106.  
  107. GHCi> quickCheck prop_gScan
  108.  
  109. then, you will get a result like below ;-)
  110. +++ OK, passed 100 tests.
  111.  
  112. -}
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement