{- | Simple geometric functions. Polygon variables: n = degree, a = side length, r,ir = inradius, R,cr = circumradius, A,ar = area, s = sagitta -} module Data.CG.Minus.Geometry where import Data.Complex {- base -} -- * Math two_pi :: Floating n => n two_pi = 2 * pi -- | Square, inverse of 'sqrt'. -- -- > sqrt (sqr 3) == 3 sqr :: Num a => a -> a sqr n = n * n -- | Secant. sec :: Floating a => a -> a sec z = 1 / cos z -- | Cotangent. cot :: Floating a => a -> a cot z = 1 / tan z -- | Degrees to radians. -- -- > degrees_to_radians 60 == (pi/3) degrees_to_radians :: Floating n => n -> n degrees_to_radians = (* pi) . (/ 180) -- > radians_to_degrees (pi/3) == 60 radians_to_degrees :: Floating n => n -> n radians_to_degrees = (* 180) . (/ pi) polar_to_rectangular :: Floating t => (t,t) -> (t,t) polar_to_rectangular (mg,ph) = let c = mkPolar mg ph in (realPart c,imagPart c) rectangular_to_polar :: RealFloat a => (a, a) -> (a,a) rectangular_to_polar (x,y) = polar (x :+ y) -- * Triangle -- > triangle_semiperimeter_sss 1 1 1 == 1.5 triangle_semiperimeter_sss :: Fractional a => a -> a -> a -> a triangle_semiperimeter_sss a b c = (1/2) * (a + b + c) -- > triangle_area_herons_sss 1 1 1 triangle_area_herons_sss :: Floating a => a -> a -> a -> a triangle_area_herons_sss a b c = let s = triangle_semiperimeter_sss a b c in sqrt (s * (s - a) * (s - b) * (s - c)) -- > triangle_area_aas (radians 120) (radians 30) 1 triangle_area_aas :: Floating a => a -> a -> a -> a triangle_area_aas alpha beta a = let gamma = pi - alpha - beta n = sqr a * sin beta * sin gamma d = 2 * sin alpha in n / d -- > triangle_area_asa (radians 30) 1 (radians 30) triangle_area_asa :: Floating a => a -> a -> a -> a triangle_area_asa alpha c beta = let n = sqr c d = 2 * (cot alpha + cot beta) in n / d -- > triangle_side_asa (radians 30) 1 (radians 30) triangle_side_asa :: Floating a => a -> a -> a -> a triangle_side_asa alpha c beta = let gamma = pi - alpha - beta in (sin alpha / sin gamma) * c -- | law_of_cosines :: Floating a => a -> a -> a -> a law_of_cosines s a s' = sqrt (sqr s + sqr s' - 2 * s * s' * cos a) -- > triangle_side_sas 0.5 (radians 120) 0.5 triangle_side_sas :: Floating a => a -> a -> a -> a triangle_side_sas = law_of_cosines triangle_centroid :: Fractional t => (t,t) -> (t,t) -> (t,t) -> (t,t) triangle_centroid (x1,y1) (x2,y2) (x3,y3) = let x = (x1 + x2 + x3) / 3 y = (y1 + y2 + y3) / 3 in (x,y) -- * Pentagon -- > pentagon_circumradius_a 1 pentagon_circumradius_a :: Floating a => a -> a pentagon_circumradius_a a = 0.1 * sqrt (50 + 10 * sqrt 5) * a -- > pentagon_inradius_a 1 pentagon_inradius_a :: Floating a => a -> a pentagon_inradius_a a = 0.1 * sqrt (25 + 10 * sqrt 5) * a -- > pentagon_sagitta_a 1 pentagon_sagitta_a :: Floating a => a -> a pentagon_sagitta_a a = 0.1 * sqrt (25 - 10 * sqrt 5) * a -- > pentagon_area_a 1 pentagon_area_a :: Floating a => a -> a pentagon_area_a a = 0.25 * sqrt (25 + 10 * sqrt 5) * a * a -- * Hexagon -- > hexagon_inradius_a 1 == 0.8660254037844386 hexagon_inradius_a :: Floating a => a -> a hexagon_inradius_a a = 0.5 * sqrt 3 * a -- | For hexagons, the side length (a) and the circumradius (R) are equal. -- -- > hexagon_circumradius_a 1 == 1 hexagon_circumradius_a :: a -> a hexagon_circumradius_a = id -- > hexagon_sagitta_a 1 == 0.1339745962155614 hexagon_sagitta_a :: Floating a => a -> a hexagon_sagitta_a a = 0.5 * (2 - sqrt 3) * a -- > hexagon_area_a 1 == 2.598076211353316 hexagon_area_a :: Floating a => a -> a hexagon_area_a a = 1.5 * sqrt 3 * sqr a -- * Polygon {- | Note that the area of a convex polygon is defined to be positive if the points are arranged in a counterclockwise order, and negative if they are in clockwise order (Beyer 1987). > let u = [(0,0),(1,0),(1,1),(0,1)] > polygon_signed_area u == 1 > polygon_signed_area (reverse u) == -1 -} polygon_signed_area :: Fractional t => [(t,t)] -> t polygon_signed_area p = let q = zip p (tail (cycle p)) f ((x1,y1),(x2,y2)) = x1 * y2 - x2 * y1 in sum (map f q) / 2 -- > regular_polygon_side_length 5 1 regular_polygon_side_length :: Floating a => a -> a -> a regular_polygon_side_length n cr = 2 * cr * sin (pi / n) -- > map (\n -> regular_polygon_inradius n 1) [3,4,5,6] regular_polygon_inradius :: Floating a => a -> a -> a regular_polygon_inradius n cr = cr * cos (pi / n) -- > regular_polygon_circumradius 5 1 regular_polygon_circumradius :: Floating a => a -> a -> a regular_polygon_circumradius n r = r * sec (pi / n) -- > regular_polygon_area 6 1 regular_polygon_area :: Floating a => a -> a -> a regular_polygon_area n cr = 0.5 * n * sqr cr * sin (two_pi / n) -- > regular_polygon_sagitta 6 1 regular_polygon_sagitta :: Floating a => a -> a -> a regular_polygon_sagitta n cr = 2 * cr * sqr (sin (pi / (2 * n)))