Today I want to give some information on the dot-product and provide it’s implementation for out Vector-type in F# (this will be trivial).
The dot-product will be very important for our Raytracer-project because of it’s many uses in analytic-geometry. You can for example decide very easy (see below) if two vectors are perpendicular, you can project vectors on others, give a nice representation of affine-subspaces (planes in 3D space) and a lot more with it.
Indeed if you only remember it’s basic-properties you can easily derive all mentioned above by yourself in case you forgot.
But before looking at those we have to give the definition: The dot-product of two vectors will be a scalar-value (a float-value). You compute it by summing the product of coordinates:
For vectors and
we will define the dot-product to be
this translate directly to the following F#-operation for our Vector3-struct:
static member (<*>) (a : Vector3, b : Vector3) = a.X*b.X + a.Y*b.Y + a.Z*b.Z
Basic properties of the dot-product
1 – it’s Commutative
this just states that for vectors and
we have
Proof
There is not much to say – both multiplication and addition (for real numbers) are commutative so the sum of the products will be too.
Test case
[< Test >] member test.``dot-product is symmetric``() = // ARRANGE let a = Vector.Create (-3.22, 2.25, -0.13) let b = Vector.Create (0.0, -6.7, 10.0) // ACT let prod1 = a <*> b let prod2 = b <*> a // ASSERT prod1 |> should equal prod2
2 – it’s linear in the first factor
For vectors ,
and
and a scalar
this says that
Remark:
Because of the first property the same is true for the second component – so we can call it bilinear.
Proof:
A simple exercise in “algebra”:
Test case
[< Test >] member test.``dot-product is linear for the first factor``() = // ARRANGE let a = Vector.Create (-3.22, 2.25, -0.13) let b = Vector.Create (0.0, -6.7, 10.0) let c = Vector.Create (12.4, -1.7, 3.15) let r = 0.22 // ACT let prod1 = a <*> (r*b + c) let prod2 = r * (a <*> b) + (a <*> c) // ASSERT prod1 |> should equal prod2
Some Corollaries
Is one of the factors zero will the dot-product be zero
So is a vector then
(note: the zeroes left and right are vectors – the zero in the middle is a scalar
)
Test case
[< Test >] member test.``dot-product by a zero-vector will always be 0``() = // ARRANGE let v = Vector.Create (-3.22, 2.25, -0.13) let zero = Vector.Zero // ACT let prod1 = v <*> zero let prod2 = zero <*> v // ASSERT prod1 |> should equal 0.0 prod2 |> should equal 0.0
Proof
Is almost to easy to bother writing down if we use the definition:
but it follows from the properties above as well (I will put the arrows on top of vectors for now to make it more clear):
As we have:
by the second property – using the first we see that this holds for zero as the first factor as well.
The dot-product of different base-vectors is zero
As a proof just use the definition of the dot-product
Test case
[< Test >] member test.``dot-product of different base-vectors is zero``() = // Helper let pairs ls = let rec pairs' ls acc = let pairOne l ls = ls |> List.map (fun l' -> (l, l')) match ls with | [] -> acc | l::ls' -> let acc' = acc@(pairOne l ls') pairs' ls' acc' pairs' ls [] // ARRANGE let baseV = [Vector.E1; Vector.E2; Vector.E3] // ACT let pairProds = baseV |> pairs |> List.map (fun (a,b) -> a <*> b) // ASSERT let check v = v |> should equal 0.0 pairProds |> List.iter check
The Dot-product of a Vector with itself is the square of it’s length
Proof
for proof just use the definition (very easy) or
and using the bilinearity and the fact just seen
as (using the definition again) the dot-product of a base-vector with itself is just 1 this yields the result.
Test case
[< Test >] member test.``dot-product of a vector by itself is the square of it's length``() = // ARRANGE let v = Vector.Create (-3.22, 2.25, -0.13) let len2 = Vector.Len2 v // ACT let prod = v <*> v // ASSERT prod |> should equal len2
Two vectors are perpendicular iFF their dot-product is zero
Ok – this only holds if none of the vectors is zero so please note this!
Test case
[< Test >] member test.``dot-product of perpendicular vectors is zero``() = // ARRANGE let a = Vector.Create (2.0, 1.0, 4.0) let b = Vector.Create (1.0, -1.0, -0.25) // ACT let prod1 = a <*> b let prod2 = b <*> a // ASSERT prod1 |> should equal 0.0 prod2 |> should equal 0.0
Proof
Depending on what you take as given this is hard or rather easy. I will take the same approach as the Wikipedia article and invoke the power of the law of cosines – of course you should know why this holds. Well I aside from the proofs mentioned in the wiki-article I immediate think of one using complex analysis (well it’s getting worse ) and one using the dot-product (doh – this one would use just what we want to proof) – so be beware of this.
You can get away with our approach if you look at the geometric definition of perpendicular and use the fact that the base-vectors are. Then you can find similar vectors on the axis (for which the dot-product will be zero) and you can use the fact that there is a matrix transforming your vectors to those similar. Using the definition of matrix-multiplication by forming the dot-product of it’s columns with your vector as the components of the final result will finally yield a proof that does not need the law of cosines but a lot of linear algebra …)
Having vectors and
we are interested in the angle
between them. Together with the vector
those form a triangle like this:
The law of cosines states that (using the square of length law we’ve seen right now):
.
As the left side is
and cosine-law reduces to
Now as both vectors have length greater 0 the left side will be zero IFF the cosine on the right is zero and this holds IFF the angle is 90° or 270° so the vectors are perpendicular.
Nice one huh?
Ok I think this is enough for now – next time we will start etching out a very simple ray-tracer by explaining the algorithm and rendering the shape of a 3D-sphere…