SOE ex.2.4


{-
 http://mathworld.wolfram.com/ConvexPolygon.html
 |a x b| = |a| * |b| * sin(theta)
  a . b  = |a| * |b| * cos(theta)
 aL . b  = |a| * |b| * sin(theta)  — perp dot product

 Since all vectors have Z’s scalar equals zero (all in x-y plane),
 we can easily to determine convex polygon in this case by 
 testing all cross products’ Z scalar; they must have the same sign.
-}

type Vector = (Float, Float)

convex :: Shape -> Bool
convex (Polygon vs) = all (>=0) zScalars || all (<=0) zScalars
  where
  toPair :: [a] -> [(a,a)]
  toPair ns = zip ns (tail (cycle ns))
  vector :: (Vertex, Vertex) -> Vector
  vector ((x1, y1), (x2, y2)) = (x2-x1, y2-y1)
  vectors = map vector (toPair vs)
  crossProductZscalar :: (Vector, Vector) -> Float
  crossProductZscalar ((x1, y1), (x2, y2)) = x1 * y2 - x2 * y1
  zScalars = map crossProductZscalar (toPair vectors)

convex _ = True

{-
Notes:

1. This calculates all cross product vectors’ z scale and checking their sign.
   We can speed up by recursion; once find different sign than 
   returns Flase immediately without calculate them all.

2. The type Vector only uses inside "convex" function.
   I would like to definie it only "inside" the "convex" function.
   (example, under "where" of "convex")
   But this seems not allowed. (syntax error)  :-( 
-}

data Shape
  = Rectangle Side Side
  | Ellipse Radius Radius
  | RtTriangle Side Side
  | Polygon [Vertex]
  deriving Show

type Radius = Float
type Side   = Float
type Vertex = (Float, Float)

Leave a Reply