packages feed

reanimate-0.3.2.0: examples/morphology_linebend_intro.hs

#!/usr/bin/env stack
-- stack runghc --package reanimate
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ParallelListComp  #-}
module Main(main) where

import           Codec.Picture
import           Control.Monad
import           Data.List                (transpose)
import qualified Data.Vector              as V
import           Graphics.SvgTree         (LineJoin (..))
import           Linear.V2
import           Reanimate
import           Reanimate.Math.Polygon
import           Reanimate.Morph.Common
import           Reanimate.Morph.Linear
import           Reanimate.Morph.LineBend

bgColor :: PixelRGBA8
bgColor = PixelRGBA8 252 252 252 0xFF

spike1 :: Polygon
spike1 = pScale 2.5 $ mkPolygon $ V.map (\x -> x - V2 1 1) $ V.fromList
  [ V2 0 0, V2 2 0
  , V2 2 1 ]

spike2 :: Polygon
spike2 = pScale 2.5 $ mkPolygon $ V.map (\x -> x - V2 1 1) $ V.fromList
  [ V2 0 0, V2 2 0
  , V2 0 1 ]

spike3 :: Polygon
spike3 = pScale 2.5 $ mkPolygon $ V.map (\x -> x - V2 1 1) $ V.fromList
  [ V2 0.5 0, V2 1.5 0
  , V2 1 2 ]

polygonShape :: Polygon -> SVG
polygonShape p = mkLinePathClosed
  [ (x,y) | V2 x y <- map (fmap realToFrac) $ V.toList (polygonPoints p) ]


main :: IO ()
main = reanimate $
  addStatic (mkBackgroundPixel bgColor) $
  mapA (withStrokeWidth defaultStrokeWidth) $
  mapA (withStrokeColor "black") $
  mapA (withStrokeLineJoin JoinRound) $
  mapA (withFillOpacity 1) $
    sceneAnimation $ do
      _ <- newSpriteSVG $
        withStrokeWidth 0 $ translate (-4) 4 $
        center $ latex "linear"
      _ <- newSpriteSVG $
        withStrokeWidth 0 $ translate (4) 4 $
        center $ latex "line bend"
      showTrails
      forM_ pairs $ uncurry showPair
  where
    showTrails = do
      _ <- newSpriteSVG $
            translate (-4) (-0.5) $
            genTrails (map linearTrajectory pairs)
      _ <- newSpriteSVG $
            translate (4) (-0.5) $
            genTrails (map lineBend pairs)
      return ()
    showPair from to =
      waitOn $ do
        fork $ play $ mkAnimation 4 (morph linear (polygonShape from) (polygonShape to))
          # mapA (translate (-4) (-0.5))
          # mapA (withFillColor "lightgreen")
          # signalA (curveS 4)
        fork $ play $ mkAnimation 4 (morph myMorph (polygonShape from) (polygonShape to))
          # mapA (translate (4) (-0.5))
          # mapA (withFillColor "cyan")
          # signalA (curveS 4)
    myMorph = linear{morphTrajectory = lineBend }
    pairs = zip stages (tail stages ++ [head stages])
    stages =
      [ spike1
      , spike2
      , spike3
      ]

genTrails :: [(Double -> Polygon)] -> SVG
genTrails plotters =
    withFillOpacity 0 $
    withStrokeWidth (defaultStrokeWidth*0.5) $
    withStrokeColor "black" $
    withStrokeDashArray [0.1,0.05] $
    mkGroup $ map mkTrail $ transpose $ concat
      [
        [ V.toList $ V.map (fmap realToFrac) (polygonPoints poly)
        | n <- [0..steps]
        , let poly = plotter (fromIntegral n / fromIntegral steps)
        ]
      | plotter <- plotters ]
  where
    steps = 100 :: Int
    mkTrail lst = mkLinePath [ (x,y) | V2 x y <- lst ]