As we will use float-values to do our computations we might run into situations where we get into precision-troubles. It’s because of this problems that we have to consider values the same if they differ by a small amount instead of exactly zero.
To get this out of our way let’s just write a couple of functions and active-patterns to help us in the future. I think it’s almost trivial so I don’t think I have to go over each line and explain – so without further due here is the helper code:
[< AutoOpen >]
module FloatHelpers =
let ZeroThreshold = 0.0000000001
let IsNearZero (f : float) =
abs f <= ZeroThreshold
let IsPositive (f : float) =
f > ZeroThreshold
let IsNegative (f : float) =
f < -ZeroThreshold
let (|NotNearZero|_|) (f : float) =
if IsNearZero f
then None
else Some f
let (|Negative|NearZero|Positive|) (f : float) =
if f |> IsNegative then Negative
elif f |> IsPositive then Positive
else NearZero
You can find a good article on active patterns by Jessica Kerr right here: Pattern Matching in F# Part2.
To give a first simple use of this (and give some hint of why I included the somewhat strange NotNearZero (never make a negative predicate right … well no not “never”):
let Normalize (v : Vector3) =
match Length v with
| NotNearZero l -> (1.0/l)*v
| _ -> Zero
This is a function to normalize a vector – that is finding a vector with the same direction but length 1 so that if the vector is not zero.
We will need this often because many calculations are easier (and need fewer operations) if one (or any) of the participating vectors is a normal-vector.
This is why I will model a ray’s direction to always be a normal vector.
Pingback: FunTracer: hitting a sphere | getting #er