{-# LANGUAGE MultiWayIf #-} {-| Combinators for drawing various geometric figures. -} module Graphics.Curves.Geometry where import Graphics.Curves.Math import Graphics.Curves.Image import Graphics.Curves.Curve import Graphics.Curves.Attribute import Graphics.Curves.Text -- | Draw an axis-aligned rectangle with the given opposite corners. rectangle :: Point -> Point -> Image rectangle p q = poly [p, Vec (getX q) (getY p), q, Vec (getX p) (getY q)] type Length = Scalar type Angle = Scalar -- | Draw a triangle with the given side lengths. The corner opposite the third -- side is located at the origin and the first side is drawn along the -- x-axis. triangle :: Length -> Length -> Length -> Image triangle a b c | a + b < c || b + c < a || c + a < b = error $ unwords ["not a triangle:", show a, show b, show c] | otherwise = triangleA a b $ acos $ (a^2 + b^2 - c^2) / (2 * a * b) -- | Draw a triangle given by two side lengths and an angle. The corner of the -- angle is drawn at the origin and the first side along the x-axis. triangleA :: Length -> Length -> Angle -> Image triangleA a b α = poly [0, Vec a 0, rotate α $ Vec b 0] -- | Draw a triangle given by two angles and the length of the side shared by -- the angles. The first angle is drawn at the origin and the side along the -- x-axis. triangleAA :: Length -> Angle -> Angle -> Image triangleAA a α β = triangleA a (a * sin β / sin (α + β)) α -- | Draw an n-sided regular polygon centered at the origin and one corner at -- 'unitY'. regularPoly :: Int -> Image regularPoly n | n < 3 = error "regularPoly: n < 3" regularPoly n = poly [ rotate (2 * pi * fromIntegral i / fromIntegral n) unitY | i <- [0..n - 1] ] -- | Draw an angle arc for the counter clockwise angle BAC. angleArc :: Scalar -- ^ Radius of the arc in pixels -> Point -- ^ A -> Point -- ^ B -> Point -- ^ C -> Image angleArc w p0 p1 p2 = curve' 0 1 f g where f _ = (p0, p1, p2) g t (p0, p1, p2) = p0 + diag w * rotate (t * α) (norm (p1 - p0)) where α = angle (p1 - p0) (p2 - p0) -- | Draw an angle arc labelled by the given string. labelledAngle :: String -> Vec -- ^ Position of the text relative to the angle -> Point -> Point -> Point -> Image labelledAngle s d p0 p1 p2 = angleArc 20 p0 p1 p2 <> freezeImageSize p0 (label (p0 + d * norm (v1 + v2)) 14 s) where v1 = norm $ p1 - p0 v2 = norm $ p2 - p0 -- | Draw a line segment with an arrow head. arrow :: Point -> Point -> Image arrow from to = curve' 0 2 f g <> line from to where f = const $ Seg from to g t (Seg from to) = if | t <= 1 -> interpolate fin1 to t | otherwise -> interpolate to fin2 (t - 1) where v = norm (from - to) fin1 = to + 20 * rotate (pi/6) v fin2 = to + 20 * rotate (-pi/6) v