wumpus-drawing-0.3.0: src/Wumpus/Drawing/Dots/Marks.hs
{-# OPTIONS -Wall #-}
--------------------------------------------------------------------------------
-- |
-- Module : Wumpus.Drawing.Dots.Marks
-- Copyright : (c) Stephen Tetley 2010-2011
-- License : BSD3
--
-- Maintainer : Stephen Tetley <stephen.tetley@gmail.com>
-- Stability : highly unstable
-- Portability : GHC
--
-- Marks - dots without anchor handles.
--
-- The text and char marks need loaded glyph metrics for proper
-- centering.
--
-- \*\* WARNING \*\* - names are expected to change - filled and
-- background-filled marks need a naming convention.
--
--------------------------------------------------------------------------------
module Wumpus.Drawing.Dots.Marks
(
-- * Marks
markChar
, markText
, markHLine
, markVLine
, markX
, markPlus
, markCross
, markDiamond
, markFDiamond
, markBDiamond
, markDisk
, markSquare
, markCircle
, markPentagon
, markStar
, markAsterisk
, markOPlus
, markOCross
, markFOCross
, markTriangle
) where
import Wumpus.Drawing.Text.Base.RotTextZero
import Wumpus.Basic.Geometry.Paths -- package: wumpus-basic
import Wumpus.Basic.Kernel
import Wumpus.Core -- package: wumpus-core
import Data.AffineSpace -- package: vector-space
import Data.VectorSpace
-- Marks should be the height of a lower-case letter...
-- NOTES
--
-- TikZ has both stroked and bordered (filled and outline-stroked)
-- marks e.g. square and square*
--
infixr 9 `renderPathWith`
renderPathWith :: LocQuery u PrimPath
-> (PrimPath -> Graphic u)
-> LocGraphic u
renderPathWith qy mk = promoteR1 $ \pt -> apply1R1 qy pt >>= mk
markChar :: (Real u, Floating u, InterpretUnit u) => Char -> LocGraphic u
markChar ch = markText [ch]
markText :: (Real u, Floating u, InterpretUnit u) => String -> LocGraphic u
markText ss = pushR1 ignoreAns $ ccTextline ss
-- | Supplied point is the center.
--
axialLine :: (Fractional u, InterpretUnit u) => Vec2 u -> LocGraphic u
axialLine v = moveStart (\ctr -> ctr .-^ (0.5 *^ v)) (locStraightLine v)
markHLine :: (Fractional u, InterpretUnit u) => LocGraphic u
markHLine = markHeight >>= \h -> axialLine (hvec h)
markVLine :: (Fractional u, InterpretUnit u) => LocGraphic u
markVLine = markHeight >>= \h -> axialLine (vvec h)
markX :: (Fractional u, InterpretUnit u) => LocGraphic u
markX = markHeight >>= mkX
where
mkX h = let w = 0.75 * h
in axialLine (vec w h) `oplus` axialLine (vec (-w) h)
markPlus :: (Fractional u, InterpretUnit u) => LocGraphic u
markPlus = markVLine `oplus` markHLine
markCross :: (Floating u, InterpretUnit u) => LocGraphic u
markCross = markHeight >>= mkCross
where
mkCross h = axialLine (avec ang h) `oplus` axialLine (avec (-ang) h)
ang = pi*0.25
-- Note - height is extended slightly to look good...
pathDiamond :: (Fractional u, InterpretUnit u)
=> LocQuery u PrimPath
pathDiamond = promoteR1 $ \pt ->
markHeight >>= \h -> let cp = diamondCoordPath (0.5*h) (0.66*h)
in coordinatePrimPath cp pt
-- closedStroke :: (a -> ctx -> prim)
-- pathDiamond :: (ctx -> pt -> a)
-- ans :: (ctx -> pt -> prim)
markDiamond :: (Fractional u, InterpretUnit u) => LocGraphic u
markDiamond = pathDiamond `renderPathWith` closedStroke
markFDiamond :: (Fractional u, InterpretUnit u) => LocGraphic u
markFDiamond = pathDiamond `renderPathWith` filledPath
-- Note - the (const . fn) composition doesn\'t /tell/ much about
-- what is going on - though obviously it can be decoded - make
-- the function obvious to the second argument.
--
-- A named combinator might be better.
--
markBDiamond :: (Fractional u, InterpretUnit u) => LocGraphic u
markBDiamond = pathDiamond `renderPathWith` borderedPath
-- | Note disk is filled.
--
markDisk :: (Fractional u, InterpretUnit u) => LocGraphic u
markDisk = markHalfHeight >>= filledDisk
markSquare :: (Fractional u, InterpretUnit u) => LocGraphic u
markSquare =
markHeight >>= \h ->
let d = 0.5*(-h) in moveStart (displace d d) $ strokedRectangle h h
markCircle :: (Fractional u, InterpretUnit u) => LocGraphic u
markCircle = markHalfHeight >>= strokedDisk
markBCircle :: (Fractional u, InterpretUnit u) => LocGraphic u
markBCircle = markHalfHeight >>= borderedDisk
markPentagon :: (Floating u, InterpretUnit u) => LocGraphic u
markPentagon = promoteR1 $ \pt ->
pentagonPath pt >>= closedStroke
where
pentagonPath pt = markHalfHeight >>= \hh ->
coordinatePrimPath (polygonCoordPath 5 hh) pt
markStar :: (Floating u, InterpretUnit u) => LocGraphic u
markStar = markHeight >>= \h -> starLines (0.5*h)
starLines :: (Floating u, InterpretUnit u) => u -> LocGraphic u
starLines hh = promoteR1 $ \ctr ->
let cp = polygonCoordPath 5 hh
in step $ map (fn ctr) $ cp ctr
where
fn p0 p1 = straightLine p0 p1
step (x:xs) = oconcat x xs
step _ = error "starLines - unreachable"
markAsterisk :: (Floating u, InterpretUnit u) => LocGraphic u
markAsterisk = markHeight >>= asteriskLines
asteriskLines :: (Floating u, InterpretUnit u) => u -> LocGraphic u
asteriskLines h = lineF1 `oplus` lineF2 `oplus` lineF3
where
ang = (pi*2) / 6
lineF1 = axialLine (vvec h)
lineF2 = axialLine (avec ((pi*0.5) + ang) h)
lineF3 = axialLine (avec ((pi*0.5) + ang + ang) h)
markOPlus :: (Fractional u, InterpretUnit u) => LocGraphic u
markOPlus = markCircle `oplus` markPlus
markOCross :: (Floating u, InterpretUnit u) => LocGraphic u
markOCross = markCircle `oplus` markCross
markFOCross :: (Floating u, InterpretUnit u) => LocGraphic u
markFOCross = markCross `oplus` markBCircle
-- bkCircle :: (Fractional u, InterpretUnit u) => LocGraphic u
-- bkCircle = disk (fillAttr attr) (0.5*markHeight attr)
markTriangle :: (Floating u, InterpretUnit u) => LocGraphic u
markTriangle = tripath `renderPathWith` closedStroke
where
tripath = promoteR1 $ \pt ->
markHeight >>= \h ->
let cp = equilateralTriangleCoordPath h
in coordinatePrimPath cp pt