Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- module sampling
- open Tracer
- open Interfaces
- open System
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // logic for creating sampleSets //
- //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- let private ran = new System.Random()
- //takes a lower and an upper-bound of a box. Returns a random value within that box
- let private randomInBound value increment =
- let lowerValue = value-increment
- let mutable rnvalue = (ran.NextDouble()*((value-lowerValue))+lowerValue)
- if rnvalue > value then rnvalue <- rnvalue-increment
- if rnvalue < lowerValue then rnvalue <- rnvalue
- rnvalue
- //combines 2 arrays of values into a tupple array
- let private combineXY (listx:array<float>) (listy:array<float>) =
- let mutable tmp = Array.create listx.Length (0.0,0.0)
- for i in [0 .. listx.Length-1]
- do
- tmp.[i] <- (listx.[i],listy.[i])
- tmp
- // Knuth shuffle on array
- let private shuffle inputArray =
- for x in [0 .. (Array.length inputArray)-1]
- do
- let randomValue = ran.Next(0, Array.length inputArray)
- let tmp = inputArray.[x]
- inputArray.[x] <- inputArray.[randomValue]
- inputArray.[randomValue] <- tmp
- // creates x amount of samplemethod
- let private createSetsOfSampleMethod sampleMethod setsAmount n =
- let mutable sampleSets = Array.create setsAmount [||]
- for i in [0 .. (setsAmount-1)]
- do
- sampleSets.[i] <- (sampleMethod n)
- shuffle sampleSets
- sampleSets
- // Given a natural number n produces n^2 regular placed sample points.
- let private mkRegular n =
- if n = 1 then [|0.5,0.5|] else
- let sampleSize = (float n)
- let padding = (1.0-((sampleSize-1.0)/sampleSize))*0.5
- let increment = 1.0/(sampleSize) // Given N produces N^2 -> Solution to get increment is 1/(n+1)
- let mutable cordArray = Array.create (n*n) (0.0,0.0)
- let mutable i = 0
- for x in [padding..increment..1.0]
- do
- for y in [padding..increment..1.0]
- do
- cordArray.[i] <- (x,y)
- i <- i + 1
- shuffle cordArray
- cordArray
- // given a natural number n produces n randomized sample points. This is a bad sampling method!
- let private mkRandom n =
- let sampleSize = (float n)
- let mutable cordArray = Array.create n (0.0,0.0)
- let mutable ii = 0
- for i in [1.0 .. sampleSize]
- do
- let x = ran.NextDouble()
- let y = ran.NextDouble()
- cordArray.[ii] <- (x,y)
- ii <- ii + 1
- shuffle cordArray
- cordArray
- // given n produces n^2 squares in the unit pixel and randomly places one within each.
- let private mkJitter n =
- let sampleSize = (float n)
- let increment = 1.0/(sampleSize)
- let mutable cordArray = Array.create (n*n) (0.0,0.0)
- let mutable i = 0
- for x:float in [increment..increment..1.0]
- do
- for y in [increment..increment..1.0]
- do
- cordArray.[i] <- ((randomInBound x increment),(randomInBound y increment))
- i <- i + 1
- shuffle cordArray
- cordArray
- // produces N points that upholds the nrooks-properties
- let private mkNRook n =
- if n = 2 then [|0.5,0.5|] else
- let sampleSize = (float n)
- let increment = 1.0/(sampleSize) // Solution to get increment is 1/(n+1)
- let mutable xcordArray = Array.create n 0.0
- let mutable ycordArray = Array.create n 0.0
- let mutable i = 0
- for y:float in [increment .. increment .. (1.0-increment)]
- do
- xcordArray.[i] <- y
- ycordArray.[i] <- y
- i <- i + 1
- shuffle xcordArray
- shuffle ycordArray
- let cordArray = combineXY xcordArray ycordArray
- shuffle cordArray
- cordArray
- // given n produces n^2 squares in the unit pixel and places a sample within each that still upholds the N-Rooks properties.
- let private mkMultiJitter n =
- let sampleSize = (float n)
- let increment = 1.0/(sampleSize)
- let inc = 1.0/(sampleSize**2.0)
- let mutable cordArray = Array.create (n*n) (0.0,0.0)
- let mutable count = 0.0
- let mutable y = 0.0
- let mutable i = 0
- while y < (1.0-inc)
- do
- for x:float in [(inc+count) .. increment .. 1.0]
- do
- y <- y + inc
- //randomize cords within a 1/n^2 box
- cordArray.[i] <- ((randomInBound y inc),(randomInBound x inc))
- i <- i+1
- count <- count + inc
- // randomize x and y values (n-rooks)
- for i in [0 .. (n-1)]
- do
- for j in [0 .. (n-1)]
- do
- let rn = ran.Next(0, n)
- let (tmpx,tmpy) = cordArray.[i+(j*n)]
- let (rnx,rny) = cordArray.[i + (rn*n)]
- cordArray.[i+(n*j)] <- (rnx,tmpy)
- cordArray.[(rn*n)+i] <- (tmpx,rny)
- let rn = ran.Next(0, n)
- let (tmpx,tmpy) = cordArray.[j+(i*n)]
- let (rnx,rny) = cordArray.[rn + (i*n)]
- cordArray.[j+(n*i)] <- (rnx,tmpy)
- cordArray.[(i*n)+rn] <- (tmpx,rny)
- shuffle cordArray
- cordArray
- let pibyfour = (System.Math.PI / 4.0)
- let findQuarter (x,y) =
- match (x,y) with
- | (x,y) when (x>=y) && x>=(-y) -> (x,(pibyfour*(y/x))) //quarter 1
- | (x,y) when (x<=y) && x>=(-y) -> (y,(pibyfour*(2.0-(x/y)))) //quarter 2
- | (x,y) when (x<=y) && x<=(-y) -> (-x,(pibyfour*(4.0+(y/x))))// quarter 3
- | (x,y) when (x>=y) && x<=(-y) -> (-y,(pibyfour*(6.0-(x/y)))) // quarter 4
- | (_,_) -> failwith "Should never go here - didn't find a quarter in disc mapping"
- //Transforms a point to a point on a disc
- let private transformToDiscMap (x,y) =
- // map to unitsquare size 2.0
- let x = (x*2.0)-1.0
- let y = (y*2.0)-1.0
- //transform and map to disc
- let transformed = findQuarter (x,y)
- let a =
- match transformed with
- | (r,pehta) -> (System.Math.Cos(pehta)*r) //normalize for debugging: (System.Math.Cos(pehta)*r+1.0)/2
- let b =
- match transformed with
- |(r,pehta) -> (System.Math.Sin(pehta)*r) //normalize for debugging: (System.Math.Cos(pehta)*r+1.0)/2
- (a,b)
- //Transforms a point to a point on a hemisphere
- let private transformToHemiMap (x,y) =
- // close to 0 means closer to Z axis?
- let e = 100.0
- let a = 2.0*System.Math.PI*x
- let b = System.Math.Acos((1.0-y)**(1.0/e+1.0))
- (Math.Sin(b)*Math.Cos(a),Math.Sin(b)*Math.Sin(a),Math.Cos(b))
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // logic for handling threads //
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- open System.Collections.Concurrent
- exception NoMoreJuice of string // no more samples
- let indexMap : ConcurrentDictionary<int,int> = new ConcurrentDictionary<int,int>()
- let setAmountMap : ConcurrentDictionary<int,int> = new ConcurrentDictionary<int,int>()
- let samplerMap : ConcurrentDictionary<ISampler,(float*float)[][]> = new ConcurrentDictionary<ISampler,(float*float)[][]>()
- let rec getNext id sampler samplingMethod n sets =
- if indexMap.IsEmpty || (not (indexMap.ContainsKey(id)))
- then
- if (not (samplerMap.ContainsKey sampler))
- then
- samplerMap.TryAdd (sampler,(createSetsOfSampleMethod samplingMethod sets n)) |> ignore
- indexMap.TryAdd (id, Array.length (samplerMap.Item sampler)-1) |> ignore
- setAmountMap.TryAdd (id,sets) |> ignore
- getNext id sampler samplingMethod n sets
- else
- let nextIndex = indexMap.Item id
- let sampleSetLength = (Array.length (samplerMap.Item sampler))-1
- let setIndex = setAmountMap.Item id
- indexMap.TryAdd (id,nextIndex-1) |> ignore
- if nextIndex <= sampleSetLength // check if there are more samples left (0 if no)
- then
- if(setIndex) = 0 // check if there are more sets available
- then
- indexMap.TryRemove (id) |> ignore
- setAmountMap.TryRemove (id) |> ignore
- raise (NoMoreJuice("All samples were delivered. Should continue"))
- else
- let nextSet = (setIndex)-1 //move to next set
- indexMap.TryAdd (id,sampleSetLength) |> ignore
- setAmountMap.TryAdd(id,nextSet) |> ignore
- samplerMap.Item(sampler).[nextSet].[sampleSetLength]
- else
- samplerMap.Item(sampler).[setIndex].[nextIndex]
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- // types and inheritance //
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- type private baseSampler(n,sets, samplingMethod) =
- interface ISampler with
- member this.n = n
- member this.sets = sets
- member this.samplingMethod i = samplingMethod i
- member this.getNext id = getNext id this samplingMethod n sets
- member this.transformToHemi x = transformToHemiMap x
- member this.transformToDisc x = transformToDiscMap x
- type private RegularSampler(n) =
- inherit baseSampler(n, 0, mkRegular)
- type private RandomSampler(n, sets) =
- inherit baseSampler(n, sets, mkRandom)
- type private JitteredSampler(n, sets) =
- inherit baseSampler(n, sets, mkJitter)
- type private NRookSampler(n, sets) =
- inherit baseSampler(n, sets, mkNRook)
- type private MultiJittered(n, sets) =
- inherit baseSampler(n, sets, mkMultiJitter)
- let mkRegularSampler n = new RegularSampler(n) :> ISampler
- let mkRandomSampler n sets = new RandomSampler(n, sets) :> ISampler
- let mkJitteredSampler n sets = new JitteredSampler(n, sets) :> ISampler
- let mkNRookSampler n sets = new NRookSampler(n, sets) :> ISampler
- let mkMultiJitteredSampler n sets = new MultiJittered(n, sets) :> ISampler
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement