module Print (print, printKey) where import Prelude hiding (print) import Data.Array.Unboxed (UArray, bounds, (!)) import Data.Text (Text, pack, unpack) import Numeric (showFFloat) import System.FilePath (replaceExtension) import Types import Graphics import SVG (fillStyleName) first :: (a -> c) -> (a, b) -> (c, b) first f (a, b) = (f a, b) filled0 :: Graphics -> Either PatternID RGB -> [Text] -> [Text] filled0 gfx c = visual gfx (Just c) Nothing Nothing Nothing print :: Graphics -> Bool -> Bool -> Bool -> Header -> [Double] -> [Double] -> [Text] -> UArray Int Double -> UArray (Int, Int) Double -> [Text] print gfx notitle sepkey patterned header sticks vticks labels times coords = let bands = toPoints (bounds coords) times coords labels' = reverse labels filled = filled0 gfx (colours, defs) | patterned = first (map Left) . unzip $ map (pattern gfx) labels' | otherwise = (map (Right . colour) labels', []) polygons = concat . zipWith (\c ps -> filled c (polygon gfx ps)) colours . map (map p) $ bands key = concat . zipWith3 (keyBox (gW + border * 2.5) (border * 1.5) (gH / 16)) [(0::Int) ..] colours $ labels' keyBox x y0 dy i c l = let y = y0 + fromIntegral i * dy in (filled c $ rect gfx (x, y + 0.1 * dy) (dy * 0.8, dy * 0.8)) ++ text gfx Nothing Start 15 (x + dy, y + dy * 0.6) [l] w = 1280 h = 720 gW = (if sepkey then 1280 else 960) - 2 * border gH = if notitle then 720 - 2 * border else 720 - 3 * border border = 60 textOffset = 10 (xMin, xMax) = hSampleRange header (yMin, yMax) = hValueRange header gRange@((gx0,gy0),(gx1,gy1)) = ((border*1.5, gH + if notitle then border*0.5 else border*1.5), (gW + border*1.5, if notitle then border*0.5 else border*1.5)) p = rescalePoint ((xMin, yMin), (xMax, yMax)) gRange title = text gfx Nothing Middle 25 (w / 2, border * 0.75) [hJob header, pack " (", hDate header, pack ")"] background = filled (Right white) $ rect gfx (0,0) (w,h) box = filled (Right white) $ rect gfx (gx0,gy1) (gW,gH) leftLabel = text gfx (Just (-90)) Middle 20 (border/2, (gy0 + gy1)/2) [hValueUnit header] leftTicks = concatMap (\(y,l) -> let { (x1, y1) = p (xMin, y) ; (x2, y2) = p (xMax, y) } in line gfx (x1 - border/2, y1) (x2, y2) ++ if l then [] else text gfx Nothing End 15 (x1 - textOffset, y1 - textOffset) (showSI y) ) (zip vticks (replicate (length vticks - 1) False ++ [True])) bottomLabel = text gfx Nothing Middle 20 ((gx0 + gx1)/2, gy0 + border) [hSampleUnit header] bottomTicks = concatMap (\(x,l) -> let { (x1, y1) = p (x, yMin) ; (x2, y2) = p (x, yMax) } in line gfx (x1, y1 + border/2) (x2, y2) ++ if l then [] else text gfx Nothing Start 15 (x1 + textOffset, y1+2*textOffset) (showSI x) ) (zip sticks (replicate (length sticks - 1) False ++ [True])) in document gfx (w,h) (concat defs) . concat $ [ background , visual gfx (Just (Right black)) Nothing (Just black) (Just 1) $ concat $ (if notitle then [] else [title]) ++ [ leftLabel , bottomLabel , leftTicks , bottomTicks , visual gfx Nothing (Just 0.7) Nothing Nothing $ concat $ [ box , polygons ] ++ if sepkey then [] else [key] ] ] printKey :: Graphics -> Bool {- ^ patterned -} -> Text -> (FilePath, [Text]) printKey gfx True label = let (pname, pdef) = pattern gfx label in printKey' gfx pdef (Left pname) label printKey gfx False label = let cname = colour label in printKey' gfx [] (Right cname) label printKey' :: Graphics -> [Text] -> Either PatternID RGB -> Text -> (FilePath, [Text]) printKey' gfx defs c label = ( replaceExtension (unpack (fillStyleName c)) "svg" , document gfx (boxSize, boxSize) defs (filled0 gfx c $ rect gfx (0, 0) (boxSize, boxSize)) ) boxSize :: Double boxSize = 27 toPoints :: ((Int,Int),(Int,Int)) -> UArray Int Double -> UArray (Int,Int) Double -> [[(Double,Double)]] toPoints ((b0,s0),(b1,s1)) times coords = [ fwd ++ rwd | b <- [b1, b1 - 1 .. b0 + 1] , let fwd = [ (times ! s, coords ! (b - 1, s)) | s <- up b ] , let rwd = [ (times ! s, coords ! (b, s)) | s <- down b ] ] where -- ugly hack to force recomputation instead of sharing a large list up b = [s0 + b - b .. s1] down b = [s1 + b - b, s1 - 1 .. s0] showSI :: Double -> [Text] showSI x | x < 1e3 = [ showF x "" ] | x < 1e6 = [ showF (x/1e3 ) "k" ] | x < 1e9 = [ showF (x/1e6 ) "M" ] | x < 1e12 = [ showF (x/1e9 ) "G" ] | x < 1e15 = [ showF (x/1e12) "T" ] | otherwise = [ showF (x/1e15) "P" ] where showF y si = let (xs, ys) = break ('.' ==) $ showFFloat (Just 3) y "" zs = reverse . dropWhile ('0' ==) . reverse . drop 1 $ ys in case zs of "" -> pack $ xs ++ si ws -> pack $ xs ++ "." ++ ws ++ si