A type synonym is a name for an existing type expression, introduced with type, for example type Name = String. It improves documentation and makes type signatures easier to maintain. It creates no new distinct type: a synonym and its expansion remain interchangeable. An algebraic data type declared with data or newtype has a different role.
Use
type Point = (Double,Double)
type Polygon = [Point]
A valid polygon is a finite list of at least three vertices in boundary order, with the final vertex connected back to the first. The first vertex is not repeated at the end. A simple polygon also has no intersecting nonadjacent edges. Numerical routines below use finite coordinates; NaN and infinite coordinates are outside this representation's intended domain.
The Euclidean distance is
distBetween :: Point -> Point -> Double
distBetween (x,y) (u,v) = sqrt ((x-u)^2 + (y-v)^2)
Thus . The type synonym expands to pairs of floating-point coordinates.
First include the closing edge exactly once:
edges :: Polygon -> [(Point,Point)]
edges [] = []
edges ps = zip ps (tail ps ++ [head ps])

perimeter :: Polygon -> Double
perimeter = total . edges
  where total [] = 0
        total ((p,q):es) = distBetween p q + total es

perimeterFold :: Polygon -> Double
perimeterFold = foldr (\(p,q) s -> distBetween p q + s) 0 . edges
The recursive version and right fold both sum the Euclidean distances between consecutive vertices, including the last-to-first pair. They take linear time. The empty-list convention gives zero, although an empty list is not a valid polygon.
Equal side lengths alone are insufficient: a nonsquare rhombus is not a regular polygon. Use the regular polygon edge rotation criterion: for , successive nonzero edge vectors must be related by the same rotation through either or .
regular :: Polygon -> Bool
regular ps
  | length ps < 3 = False
  | otherwise = norm2 (head es) > 0 && (fits 1 || fits (-1))
  where
    es = [ (u-x,v-y) | ((x,y),(u,v)) <- edges ps ]
    angle = 2*pi / fromIntegral (length ps)
    norm2 (x,y) = x*x+y*y
    close x y = abs (x-y) <= 1e-10 * max 1 (max (abs x) (abs y))
    same (x,y) (u,v) = close x u && close y v
    turn s (x,y) = (cos angle*x - s*sin angle*y,
                    s*sin angle*x + cos angle*y)
    fits s = and (zipWith (\a b -> same (turn s a) b)
                          es (tail es ++ [head es]))
With exact real coordinates and exact equality in same, this is an if-and-only-if test for an ordinary convex regular polygon, in either boundary orientation. The displayed Double implementation tests that condition to the stated tolerance; it cannot promise exact geometric classification near the tolerance boundary. Both orientations are needed, and using the fundamental turn excludes regular star traversals. A repeated zero-length side fails the exact criterion.
Here “centroid” means the vertex centroid, the arithmetic mean of the listed vertices, rather than the uniform-area centroid of the polygon's interior:
centroid :: Polygon -> Point
centroid [] = error "centroid: empty vertex list"
centroid ps = (sx/n,sy/n)
  where
    (sx,sy) = foldr (\(x,y) (u,v) -> (x+u,y+v)) (0,0) ps
    n = fromIntegral (length ps)
The nonempty input restriction prevents division by zero; computing both sums and the length takes linear time.
Apply the same translation to every vertex:
translate :: Point -> Polygon -> Polygon
translate (u,v) = map (\(x,y) -> (x+u,y+v))
Every edge vector is unchanged because the added displacement cancels on subtraction. Hence lengths, angles, orientation and shape are preserved.
Translate the vertex centroid to the origin, rotate, and translate back:
rotatePoly :: Polygon -> Double -> Polygon
rotatePoly ps theta =
  (translate c . map turn . translate (-cx,-cy)) ps
  where
    c@(cx,cy) = centroid ps
    turn (x,y) = (cos theta*x + sin theta*y,
                 -sin theta*x + cos theta*y)
This follows the supplied rotation matrix, so positive rotates clockwise in the usual Cartesian axes. The opposite signs give the conventional counterclockwise matrix. Since the vertex centroid of the centered vertices is zero and a linear map commutes with their average, the final centroid remains c.

Articles by others on the same topic (0)

There are currently no matching articles.