{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeSynonymInstances #-} {-# OPTIONS -Wall #-} -------------------------------------------------------------------------------- -- | -- Module : Wumpus.Basic.Kernel.Objects.Graphic -- Copyright : (c) Stephen Tetley 2010 -- License : BSD3 -- -- Maintainer : stephen.tetley@gmail.com -- Stability : highly unstable -- Portability : GHC -- -- Graphic type - this is largely equivalent to Primitive in -- Wumpus-Core, but drawing attributes are implicitly supplied -- by the DrawingContext. -- -- API in @Wumpus.Core@, but here they exploit the implicit -- @DrawingContext@. -- -------------------------------------------------------------------------------- module Wumpus.Basic.Kernel.Objects.Graphic ( Graphic , DGraphic -- * LocGraphic , LocGraphic , DLocGraphic , LocThetaGraphic , DLocThetaGraphic -- * Functions , intoImage , intoLocImage , intoLocThetaImage , moveStartPoint , moveStartPointTheta , locPath , emptyLocPath , emptyLocGraphic , openStroke , closedStroke , filledPath , borderedPath , textline , rtextline , escapedline , rescapedline , hkernline , vkernline , strokedEllipse , rstrokedEllipse , filledEllipse , rfilledEllipse , borderedEllipse , rborderedEllipse , straightLine , straightLineBetween , curveBetween , strokedRectangle , filledRectangle , borderedRectangle , strokedCircle , filledCircle , borderedCircle , strokedDisk , filledDisk , borderedDisk ) where import Wumpus.Basic.Kernel.Base.ContextFun import Wumpus.Basic.Kernel.Base.BaseDefs import Wumpus.Basic.Kernel.Base.QueryDC import Wumpus.Basic.Kernel.Base.WrappedPrimitive import Wumpus.Basic.Kernel.Geometry.Paths import Wumpus.Basic.Kernel.Objects.BaseObjects import Wumpus.Core -- package: wumpus-core import Data.AffineSpace -- package: vector-space import Control.Applicative -------------------------------------------------------------------------------- -- Graphic -- | Simple drawing - produce a primitive, access the DrawingContext -- as required, e.g for fill colour, stroke colur, line width, etc. -- type Graphic u = Image u (UNil u) -- | Alias of 'Graphic' where the unit type is specialized to -- Double. -- type DGraphic = Graphic Double -- | /Originated/ drawing - produce a primitive respective to the -- supplied start-point, access the DrawingContext as required. -- type LocGraphic u = LocImage u (UNil u) -- | Alias of 'LocGraphic' where the unit type is specialized to -- Double. -- type DLocGraphic = LocGraphic Double -- | /Originated/ drawing - produce a primitive respective to the -- supplied start-point, access the DrawingContext as required. -- type LocThetaGraphic u = LocThetaImage u (UNil u) -- | Alias of 'LocThetaGraphic' where the unit type is specialized -- to Double. -- type DLocThetaGraphic = LocThetaGraphic Double -------------------------------------------------------------------------------- -- Functions -- | Build an Image... -- intoImage :: CF a -> Graphic u -> Image u a intoImage = liftA2 (\a (_,b) -> (a,b)) -- | Build a LocImage... -- intoLocImage :: LocCF u a -> LocGraphic u -> LocImage u a intoLocImage = liftA2 (\a (_,b) -> (a,b)) -- | Build a LocThetaImage... -- intoLocThetaImage :: LocThetaCF u a -> LocThetaGraphic u -> LocThetaImage u a intoLocThetaImage = liftA2 (\a (_,b) -> (a,b)) -- | Move the start-point of a LocImage with the supplied -- displacement function. -- moveStartPoint :: PointDisplace u -> LocCF u a -> LocCF u a moveStartPoint f ma = promoteR1 $ \pt -> apply1R1 ma (f pt) -- | Move the start-point of a LocImage with the supplied -- displacement function. -- moveStartPointTheta :: PointDisplace u -> LocThetaCF u a -> LocThetaCF u a moveStartPointTheta f ma = promoteR2 $ \pt theta -> apply2R2 ma (f pt) theta -------------------------------------------------------------------------------- graphicBody :: Primitive u -> (UNil u, PrimGraphic u) graphicBody p = (uNil, primGraphic p) -- | This is the analogue to 'vectorPath' in @Wumpus-core@. -- locPath :: Num u => [Vec2 u] -> LocCF u (PrimPath u) locPath vs = promoteR1 $ \pt -> pure $ vectorPath pt vs -- | This is the analogue to 'emptyPath' in @Wumpus-core@. -- emptyLocPath :: Num u => LocCF u (PrimPath u) emptyLocPath = locPath [] -- | Build an empty LocGraphic - this is a path with a start -- point but no path segments. -- -- The 'emptyLocGraphic' It is treated as a /null primitive/ by -- @Wumpus-Core@ and is not drawn, although it does generate a -- minimum bounding box at the implicit start point. -- emptyLocGraphic :: Num u => LocGraphic u emptyLocGraphic = emptyLocPath >>= (lift0R1 . openStroke) -- | 'openStroke' : @ path -> Graphic @ -- -- This is the analogue to 'ostroke' in @Wumpus-core@, but the -- drawing properties (colour, line width, etc.) are taken from -- the implicit 'DrawingContext'. -- openStroke :: Num u => PrimPath u -> Graphic u openStroke pp = withStrokeAttr $ \rgb attr -> graphicBody $ ostroke rgb attr pp -- | 'closedStroke' : @ path -> Graphic @ -- -- This is the analogue to 'cstroke' in @Wumpus-core@, but the -- drawing properties (colour, line width, etc.) are taken from -- the implicit 'DrawingContext'. -- closedStroke :: Num u => PrimPath u -> Graphic u closedStroke pp = withStrokeAttr $ \rgb attr -> graphicBody $ cstroke rgb attr pp -- | 'filledPath' : @ path -> Graphic @ -- -- This is the analogue to 'fill' in @Wumpus-core@, but the -- fill colour is taken from the implicit 'DrawingContext'. -- -- filledPath :: Num u => PrimPath u -> Graphic u filledPath pp = withFillAttr $ \rgb -> graphicBody $ fill rgb pp -- | 'borderedPath' : @ path -> Graphic @ -- -- This is the analogue to 'fillStroke' in @Wumpus-core@, but the -- drawing properties (fill colour, border colour, line width, -- etc.) are taken from the implicit 'DrawingContext'. -- -- borderedPath :: Num u => PrimPath u -> Graphic u borderedPath pp = withBorderedAttr $ \frgb attr srgb -> graphicBody $ fillStroke frgb attr srgb pp -- | This is the analogue to 'textlabel' in @Wumpus-core@. -- textline :: Num u => String -> LocGraphic u textline ss = promoteR1 $ \pt -> withTextAttr $ \rgb attr -> graphicBody (textlabel rgb attr ss pt) -- | This is the analogue to 'rtextlabel' in @Wumpus-core@. -- rtextline :: Num u => String -> LocThetaGraphic u rtextline ss = promoteR2 $ \pt theta -> withTextAttr $ \rgb attr -> graphicBody (rtextlabel rgb attr ss theta pt) -- | This is the analogue to 'escapedlabel' in @Wumpus-core@. -- escapedline :: Num u => EscapedText -> LocGraphic u escapedline ss = promoteR1 $ \pt -> withTextAttr $ \rgb attr -> graphicBody (escapedlabel rgb attr ss pt) -- | This is the analogue to 'rescapedlabel' in @Wumpus-core@. -- rescapedline :: Num u => EscapedText -> LocThetaGraphic u rescapedline ss = promoteR2 $ \pt theta -> withTextAttr $ \rgb attr -> graphicBody (rescapedlabel rgb attr ss theta pt) -- | This is the analogue to 'hkernlabel' in @Wumpus-core@. -- hkernline :: Num u => [KerningChar u] -> LocGraphic u hkernline xs = promoteR1 $ \pt -> withTextAttr $ \rgb attr -> graphicBody (hkernlabel rgb attr xs pt) -- | This is the analogue to 'vkernlabel' in @Wumpus-core@. -- vkernline :: Num u => [KerningChar u] -> LocGraphic u vkernline xs = promoteR1 $ \pt -> withTextAttr $ \rgb attr -> graphicBody (vkernlabel rgb attr xs pt) -------------------------------------------------------------------------------- -- | This is the analogue to 'strokeEllipse' in @Wumpus-core@. -- strokedEllipse :: Num u => u -> u -> LocGraphic u strokedEllipse hw hh = promoteR1 $ \pt -> withStrokeAttr $ \rgb attr -> graphicBody (strokeEllipse rgb attr hw hh pt) -- | This is the analogue to 'rstrokeEllispe' in @Wumpus-core@. -- rstrokedEllipse :: Num u => u -> u -> LocThetaGraphic u rstrokedEllipse hw hh = promoteR2 $ \ pt theta -> withStrokeAttr $ \rgb attr -> graphicBody (rstrokeEllipse rgb attr hw hh theta pt) -- | This is the analogue to 'fillEllispe' in @Wumpus-core@. -- filledEllipse :: Num u => u -> u -> LocGraphic u filledEllipse hw hh = promoteR1 $ \pt -> withFillAttr $ \rgb -> graphicBody (fillEllipse rgb hw hh pt) -- | This is the analogue to 'rfillEllispe' in @Wumpus-core@. -- rfilledEllipse :: Num u => u -> u -> LocThetaGraphic u rfilledEllipse hw hh = promoteR2 $ \pt theta -> withFillAttr $ \rgb -> graphicBody (rfillEllipse rgb hw hh theta pt) -- | This is the analogue to 'fillStrokeEllispe' in @Wumpus-core@. -- borderedEllipse :: Num u => u -> u -> LocGraphic u borderedEllipse hw hh = promoteR1 $ \pt -> withBorderedAttr $ \frgb attr srgb -> graphicBody (fillStrokeEllipse frgb attr srgb hw hh pt) -- | This is the analogue to 'rfillStrokeEllispe' in @Wumpus-core@. -- rborderedEllipse :: Num u => u -> u -> LocThetaGraphic u rborderedEllipse hw hh = promoteR2 $ \pt theta -> withBorderedAttr $ \frgb attr srgb -> graphicBody (rfillStrokeEllipse frgb attr srgb hw hh theta pt) -- Note - clipping needs a picture as well as a path, so there is -- no analogous @clippedPath@ function. -------------------------------------------------------------------------------- -- | Draw a straight line formed from displacing the implicit -- start point with the supplied vector. -- straightLine :: Fractional u => Vec2 u -> LocGraphic u straightLine v = mf >>= (lift0R1 . openStroke) where mf = promoteR1 $ \pt -> pure $ primPath pt [lineTo $ pt .+^ v] -- | Draw a straight line - start and end point are supplied -- explicitly. -- straightLineBetween :: Fractional u => Point2 u -> Point2 u -> Graphic u straightLineBetween p1 p2 = openStroke $ primPath p1 [lineTo p2] -- | Draw a Bezier curve - all points are supplied explicitly. -- curveBetween :: Fractional u => Point2 u -> Point2 u -> Point2 u -> Point2 u -> Graphic u curveBetween sp cp1 cp2 ep = openStroke $ primPath sp [curveTo cp1 cp2 ep] -- This is a permuted version of the cardinal-prime combinator... -- -- > (r2 -> a) -> (a -> r1 -> ans) -> (r1 -> r2 -> ans) -- drawWith :: (Point2 u -> PrimPath u) -> (PrimPath u -> Graphic u) -> LocGraphic u drawWith g mf = promoteR1 $ \pt -> mf (g pt) -- | Supplied point is /bottom left/. -- strokedRectangle :: Fractional u => u -> u -> LocGraphic u strokedRectangle w h = rectanglePath w h `drawWith` closedStroke -- | Supplied point is /bottom left/. -- filledRectangle :: Fractional u => u -> u -> LocGraphic u filledRectangle w h = rectanglePath w h `drawWith` filledPath -- | Supplied point is /bottom left/. -- borderedRectangle :: Fractional u => u -> u -> LocGraphic u borderedRectangle w h = rectanglePath w h `drawWith` borderedPath -- | Supplied point is center. Circle is drawn with Bezier -- curves. -- strokedCircle :: Floating u => Int -> u -> LocGraphic u strokedCircle n r = (curvedPath . bezierCircle n r) `drawWith` closedStroke -- | Supplied point is center. Circle is drawn with Bezier -- curves. -- filledCircle :: Floating u => Int -> u -> LocGraphic u filledCircle n r = (curvedPath . bezierCircle n r) `drawWith` filledPath -- | Supplied point is center. Circle is drawn with Bezier -- curves. -- borderedCircle :: Floating u => Int -> u -> LocGraphic u borderedCircle n r = (curvedPath . bezierCircle n r) `drawWith` borderedPath -- | 'disk' is drawn with Wumpus-Core\'s @ellipse@ primitive. -- -- This is a efficient representation of circles using -- PostScript\'s @arc@ or SVG\'s @circle@ in the generated -- output. However, stroked-circles do not draw well after -- non-uniform scaling - the line width is scaled as well as -- the shape. -- -- For stroked circles that can be adequately scaled, use -- 'strokedCircle' instead. -- strokedDisk :: Num u => u -> LocGraphic u strokedDisk radius = strokedEllipse radius radius -- | Filled disk... -- filledDisk :: Num u => u -> LocGraphic u filledDisk radius = filledEllipse radius radius -- | bordered disk... -- borderedDisk :: Num u => u -> LocGraphic u borderedDisk radius = borderedEllipse radius radius