packages feed

crocodile-0.1.2: app/src/Distribution.hs

-- Module for generating sample patterns for distributed ray tracing
{-# LANGUAGE BangPatterns #-}

module Distribution (generatePointsOnSphere, 
                     generatePointsOnQuad, 
                     generatePointsOnHemisphere,
                     generatePointOnHemisphere,
                     generateRandomUVs,
                     randomUV) where

import PolymorphicNum
import Vector
import System.Random.Mersenne.Pure64
import Control.Monad.State

type GeneratorState = State PureMT

-- Generate a pair of random normalised floats
randomUV :: GeneratorState (Double, Double)
randomUV = do generator <- get
              let !(u, generator') = randomDouble generator
              let !(v, generator'') = randomDouble generator'
              put generator''
              return (u, v)

-- Generate a list of N random UVs
generateRandomUVs :: Int -> GeneratorState [(Double, Double)]
generateRandomUVs n = replicateM n randomUV

uvToSphere :: Double -> (Double, Double) -> Position
uvToSphere r (!u, !v) = Vector (r * x) (r * y) (r * z) 1
    where
      !z = 2 * u - 1
      !t = 2 * pi * v
      !w = sqrt (1 - z * z)
      !x = w * cos t
      !y = w * sin t

uvToHemisphere :: Double -> (Double, Double) -> Position
uvToHemisphere r (!u, !v) = Vector (r * x) (r * y) (r * z) 1
    where
      !z = v
      !t = 2 * pi * u
      !w = sqrt (1 - v * v)
      !x = w * cos t
      !y = w * sin t

-- Generate a list of random points on a sphere
generatePointsOnSphere :: Int -> Double -> Int -> [Position]
generatePointsOnSphere numPoints r seed 
    | numPoints <= 1 = [Vector 0 0 0 1]
    | otherwise = map (uvToSphere r) randomUVs
    where
      randomUVs = evalState (generateRandomUVs numPoints) (pureMT (fromIntegral seed))

-- Generate a list of random points on a hemisphere (z > 0)
generatePointsOnHemisphere :: Int -> Double -> Int -> [Position]
generatePointsOnHemisphere numPoints r seed
    | numPoints <= 1 = [Vector 0 0 0 1]
    | otherwise = map (uvToHemisphere r) randomUVs
    where
      randomUVs = evalState (generateRandomUVs numPoints) (pureMT (fromIntegral seed))

generatePointsOnQuad :: Position -> Direction -> Direction -> Int -> Int -> [Position]
generatePointsOnQuad pos deltaU deltaV numPoints seed 
    | numPoints <= 1 = [Vector 0 0 0 1]
    | otherwise = map (\(u, v) -> pos <+> deltaU <*> u <+> deltaV <*> v) randomUVs
    where
      randomUVs = evalState (generateRandomUVs numPoints) (pureMT (fromIntegral seed))

-- Generate a single random point on a hemisphere
generatePointOnHemisphere :: PureMT -> Double -> (Position, PureMT)
generatePointOnHemisphere rndGen r  = (uvToHemisphere r uv, rndGen')
    where
      (uv, rndGen') = runState randomUV rndGen