module Diagrams.TwoD.Grid (
gridWithHalves
, gridWithHalves'
, annotate
, gridLine
, gridLine'
, gridLines
, placeDiagramOnGrid
, GridOpts(..)
, gridLineWidth, gridYColour, gridXColour, gridLL, gridLR, gridUL
, HighlightLineOpts(..)
, highLightLineColour, highLightLineWidth
, highLightLineDashingOnOff, highLightLineDashingOffset
) where
import Diagrams.Prelude
import Data.List
import Data.List.Split
import Data.Typeable
data GridOpts n
= GridOpts
{ _gridLineWidth :: Measure n
, _gridYColour :: Colour Double
, _gridXColour :: Colour Double
, _gridLL :: V2 n
, _gridLR :: V2 n
, _gridUL :: V2 n
}
instance (Floating n, Ord n) => Default (GridOpts n) where
def = GridOpts
{ _gridLineWidth = thin
, _gridXColour = red
, _gridYColour = blue
, _gridLL = r2 (1.0, 1.0)
, _gridLR = r2 (2.0, 1.0)
, _gridUL = r2 (1.0, 2.0)
}
data HighlightLineOpts n
= HighlightLineOpts
{ _highLightLineColour :: Colour Double
, _highLightLineWidth :: Measure n
, _highLightLineDashingOnOff :: [Measure n]
, _highLightLineDashingOffset :: Measure n
}
instance (Floating n, Ord n) => Default (HighlightLineOpts n) where
def = HighlightLineOpts
{ _highLightLineColour = black
, _highLightLineWidth = medium
, _highLightLineDashingOnOff = [normalized 0.03, normalized 0.03]
, _highLightLineDashingOffset = output 0
}
makeLenses ''GridOpts
makeLenses ''HighlightLineOpts
tick :: (Floating n, Ord n)
=> (Int, Int) -> QDiagram b V2 n Any
tick (n, m) = pointDiagram origin # named (n, m)
gridWithHalves :: (Renderable (Path V2 n) b, TypeableFloat n)
=> Int -> Int -> QDiagram b V2 n Any
gridWithHalves = gridWithHalves' def
gridWithHalves' :: (Renderable (Path V2 n) b, TypeableFloat n)
=> GridOpts n -> Int -> Int -> QDiagram b V2 n Any
gridWithHalves' opts n m =
(mconcat lineXs # translate (r2 (llx, lly))) <>
(mconcat lineYs # translate (r2 (llx, lly))) <>
(intersections # translate (r2 (llx delta2X, luy + delta2Y)))
where
llx :& lly = coords (opts^.gridLL)
lrx :& _ = coords (opts^.gridLR)
_ :& luy = coords (opts^.gridUL)
deltaX = (lrx llx) / fromIntegral n
deltaY = (luy lly) / fromIntegral m
delta2X = (lrx llx) / fromIntegral (2 * n)
delta2Y = (luy lly) / fromIntegral (2 * m)
ns = [0..n]
ms = [0..m]
n2s = [0..2 * n + 2]
m2s = [0..2 * m + 2]
xs = map ((* deltaX) . fromIntegral) ns
ys = map ((* deltaY) . fromIntegral) ms
lineXs = Prelude.map lineX ys
lineYs = Prelude.map lineY xs
lineX y = fromOffsets [(opts^.gridLR) ^-^ (opts^.gridLL)] #
translate (r2 (0.0, y)) #
lc (opts^.gridXColour) #
lw (opts^.gridLineWidth)
lineY x = fromOffsets [(opts^.gridUL) ^-^ (opts^.gridLL)] #
translate (r2 (x, 0.0)) #
lc (opts^.gridYColour) #
lw (opts^.gridLineWidth)
intersections = hcat $
intersperse (strutX delta2X) $
map vcat $
map (intersperse (strutY delta2Y)) $
chunksOf (2 * m + 1 + 2) [ tick (n, m) | n <- n2s, m <- m2s ]
placeDiagramOnGrid :: (IsName nm, Floating n, Ord n) =>
QDiagram b V2 n Any -> [nm] -> QDiagram b V2 n Any -> QDiagram b V2 n Any
placeDiagramOnGrid d = flip $ foldr (\n -> withName n (atop . place d . location))
annotate :: (Floating n, Ord n, Typeable n) =>
String ->
(String -> QDiagram b V2 n Any) ->
Colour Double ->
Int ->
Int ->
QDiagram b V2 n Any ->
QDiagram b V2 n Any
annotate s txtPt h n m =
withName (n, m) (atop . place (addText s h) . location)
where
addText s h = txtPt s # fc h
gridLine :: (IsName a, IsName b,
Renderable (Path V2 n) c, TypeableFloat n) =>
a -> b -> QDiagram c V2 n Any -> QDiagram c V2 n Any
gridLine = gridLine' def
gridLine' :: (IsName a, IsName b,
Renderable (Path V2 n) c, TypeableFloat n) =>
HighlightLineOpts n -> a -> b -> QDiagram c V2 n Any -> QDiagram c V2 n Any
gridLine' opts u v =
withName u $ \x ->
withName v $ \y ->
atop ((location x ~~ location y) #
lc (opts^.highLightLineColour) #
lw (opts^.highLightLineWidth) #
dashing (opts^.highLightLineDashingOnOff) (opts^.highLightLineDashingOffset))
gridLines :: (Renderable (Path V2 n) c, TypeableFloat n,
IsName a, IsName b) =>
[(a, b)] -> QDiagram c V2 n Any -> QDiagram c V2 n Any
gridLines xs = foldr (.) id [ gridLine x y | (x, y) <- xs ]