dynobud-1.3.0.0: examples/SofaVisualizer.hs
{-# OPTIONS_GHC -Wall #-}
{-# Language CPP #-}
module Main ( main ) where
import qualified Data.Foldable as F
import Linear.V3 ( V3(..) )
import Linear.Quaternion ( Quaternion(..) )
import Control.Monad ( when, forever )
import Data.ByteString.Char8 ( pack )
import Data.ByteString.Lazy ( fromStrict )
import Data.Binary
import qualified System.ZMQ4 as ZMQ
import qualified Control.Concurrent.STM as STM
import qualified Control.Concurrent as CC
import Text.Printf
import Vis
import Sofa.Common
--type M22 = ((Double,Double),(Double,Double))
--sub :: ((DynCollTraj (Vector Double), CollTrajMeta, [M22], M22) -> IO ()) -> IO ()
--sub writeChan = ZMQ.withContext $ \context ->
-- ZMQ.withSocket context ZMQ.Sub $ \subscriber -> do
-- ZMQ.connect subscriber url
-- ZMQ.subscribe subscriber (pack channelName)
-- forever $ do
-- _ <- ZMQ.receive subscriber
-- mre <- ZMQ.moreToReceive subscriber
-- when mre $ do
sub :: (SofaMessage -> IO ()) -> IO ()
sub writeChan = ZMQ.withContext $ \context ->
ZMQ.withSocket context ZMQ.Sub $ \subscriber -> do
ZMQ.connect subscriber url
ZMQ.subscribe subscriber (pack sofaChannel)
forever $ do
_ <- ZMQ.receive subscriber
mre <- ZMQ.moreToReceive subscriber
when mre $ do
msg <- ZMQ.receive subscriber
let decoded :: SofaMessage
decoded = case decodeOrFail (fromStrict msg) of
Left (_,_,err) -> error $ "decode failure: " ++ err
Right (_,_,t) -> t
writeChan decoded
main :: IO ()
main = do
-- keep reading from tcp and storing results in the queue
trajChan <- STM.atomically STM.newTQueue
_ <- CC.forkIO (sub (STM.atomically . (STM.writeTQueue trajChan)))
-- keep parsing results from the queue into nice form
trajMVar <- CC.newMVar (VisObjects [], [], [])
let getLastValue = do
val <- STM.atomically (STM.readTQueue trajChan)
empty' <- STM.atomically (STM.isEmptyTQueue trajChan)
if empty' then return val else getLastValue
parserThread = do
sofaX <- getLastValue
CC.modifyMVar_ trajMVar $ \(_,_,xs) -> do
let (mainvis, stages) = toVisObjects sofaX
return (mainvis, stages, xs)
parserThread
_ <- CC.forkIO parserThread
animateIO (defaultOpts { optWindowName = "sofa lol" }) (animateFun trajMVar)
multiplyList :: Int -> Int -> [a] -> [a]
multiplyList _ _ [] = []
multiplyList k 0 (_:xs) = multiplyList k k xs
multiplyList k j xs@(x0:_) = x0 : multiplyList k (j-1) xs
animateFun :: CC.MVar (VisObject Double, [VisObject Double], [VisObject Double])
-> Float -> IO (VisObject Double)
animateFun mv = const $ do
(mainvis, stages, plotstages) <- CC.takeMVar mv
case plotstages of
(s0:ss) -> do
CC.putMVar mv (mainvis, stages, ss)
return $ VisObjects [mainvis, s0]
[]-> do
let n = max 1 $ 400 `div` length stages
CC.putMVar mv (mainvis, stages, multiplyList n n stages)
return mainvis
linspace :: Fractional a => a -> a -> Int -> [a]
linspace x0 xf n = xs
where
h = (xf-x0)/(fromIntegral n - 1)
xs = map (\k -> x0 + h*(fromIntegral k)) (take n [(0::Int)..])
qy :: Quaternion Double
qy = Quaternion 0 $ V3 1 0 0
toVisObjects :: SofaMessage -> (VisObject Double, [VisObject Double])
toVisObjects (SofaMessage iters r points stages) =
( RotQuat qy $ VisObjects [walls, txt, shape0
, VisObjects (allPoints (-1))
, Trans (V3 (-2) (-2) 0) axes
]
, map (RotQuat qy . Trans (V3 1 1 0)) (allPoints 0)
)
where
walls = VisObjects
[ Line [ V3 (-4) 1 0
, V3 1 1 0
, V3 1 (-4) 0
] (makeColor 1 1 1 1)
, Line [ V3 (-4) 2 0
, V3 2 2 0
, V3 2 (-4) 0
] (makeColor 1 1 1 1)
, Line [ V3 (-4) 0 0
, V3 0 0 0
, V3 0 (-4) 0
] (makeColor 1 1 1 1)
]
axes = Axes (0.5, 15)
npoints = length points
nsteps = length stages
shape0 = Line' $
zipWith (\(Point x y) c -> ((V3 x y 0) - (V3 2 2 0), c))
(points ++ [head points])
(colors (npoints + 1))
drawOne :: [Point Double] -> Double -> Color -> VisObject Double
drawOne ps@(p0:_) z =
Line
(map (\(Point x y) -> (V3 x y z)) (ps ++ [p0]))
drawOne _ _ = const (VisObjects [])
area = 0.5 * (F.sum $ zipWithNext' cross points)
allPoints :: Double -> [VisObject Double]
allPoints maxheight = zipWith3 (\c so z -> drawOne (stagePoints so) z c)
(colors (nsteps + 1))
stages
(linspace 0 maxheight (nsteps + 1))
colors :: Int -> [Color]
colors k = fmap (\gamma -> makeColor 0 gamma (1 - gamma) 1) (gammas k)
gammas :: Int -> [Float]
gammas k = linspace 0 1 k
stagePoints :: (Point Double, Double) -> [Point Double]
stagePoints (mean, theta) = fmap rot points
where
rot :: Point Double -> Point Double
rot (Point x y) = mean + Point (x*cos(theta) + y*sin(theta)) (-x*sin(theta) + y*cos(theta))
messages = [ show npoints ++ " segments"
, show nsteps ++ " stages"
, printf "segment length: %.4f" r
, printf "area: %.4f" area
, "iteration: " ++ show iters
]
txt = VisObjects $
zipWith (\s k -> Text2d s (30,fromIntegral $ 30*k) TimesRoman24 (makeColor 1 1 1 1))
messages (reverse [1..length messages])
-- trajLine = Line (zipWith (\x y -> V3 x y 0) (concat xs0) (concat ys0)) (makeColor 1 0 0 0.4)
-- trajDots = Points (zipWith (\x y -> V3 x y 0) xsCollPts ysCollPts) (Just 1) red
-- trajDots' = Points (zipWith (\x y -> V3 x y 0) xsBigPts ysBigPts) (Just 2) red