After introducing the ideas of tuples, vectors, and points, the book goes on to say:
But looking at (4, -4, 3) and (-4, 4, -3) , it’s impossible to know that one is a point
and the other is a vector. Let’s add a fourth component to these (x, y, z) tuples,
called w , to help us tell them apart. Set w to 1 for points, and 0 for vectors.
Thus, your point becomes (4, -4, 3, 1) , and your vector becomes (-4, 4, -3, 0) .
Now, the choice of 0 or 1 for w probably seems arbitrary just now, but sit
tight! It’ll make more sense when you get to Chapter 3, Matrices, on page 25,
where it turns out to be rather important for multiplying matrices and tuples.
This advice seems misguided to me, as it amounts to using the fourth component as a type code, and not even a symbolic one–you just have to remember that 1.0 in the fourth component means a vector and 0.0 indicates a point. Especially given that this book appears to be aimed towards fairly junior developers, that’s not a practice we should be encouraging.
I agree that it’s necessary to differentiate between vectors and points, and the best way to do it depends largely on the language you’re using. That said, every mainstream language that I know of has a better way to do that than what is suggested here.
I feel this. But let me give my two cents. I’m coding in Java.
I’ve just started the book today and got stuck when it came to implementation of the different operations on Tuples, Points and Vectors.
TL;DR: in the end, the current description in the book allows for two main points:
it has me thinking really hard on what the best approach is. And in the spirit of TDD, I came to the realisation that the stage I’m in now needs me to not overthink all of that too early and go with the flow and trust the process.
the loose description gives you the full freedom. Sticking to only point and vector is a too narrow view. Using Tuple with the convenient “w” component allows for a broader understanding of the underlying mechanisms
Here’s a more detailed description of what happened to me:
I’ve started immediately with a type system, Tuple, Point and Vector. Now, may it be to language restrictions or inherently complex design, implementing the different rules per Type seemed to create an enormous mess. I.e. is Tuple allowed to add two “points” but the Point type isn’t? Does each type need an extra implementation to return the correct type, depending on the operation (e.g. returning a vector when adding point+vector)?
Does every type have to implement this? The inheritence tree looks like garbage after a few tries.
From my point of view: using narrow types requires much more design skill from a beginner developer and is more prone to end up in a mess that is really hard to refactor your way out of.
Using a “flag” on a single type is way easier for the initial design.
My current solution is to just stick to the Tuple type with some convenience methods. This is clean and I expect most flexibility with this approach.
I’d just like to point out that according to ProgPrag, this book is aimed at expert level programmers, and not beginners.
I thought of implementing Tuple as a sealed class and then Point and Vector as its implementations, but in the end, I figured I didn’t see what might be forthcoming and it made more sense to not do so only to have to go back and substantially rewrite my implementation.
@srmo, the interactions between points and vectors should be fairly easy to handle:
Point - Point gives Vector.
Point + Point is an illegal operation.
Point + Vector gives Point.
Point - Vector gives Point.
Vector + Vector gives Vector.
Vector - Vector gives Vector.
Vector - Point is an illegal operation.
Vector + Point is an illegal operation.
scalar * Point is an illegal operation.
scalar * Vector gives Vector.
Dot product and cross product only work for Vector and Vector and give scalar and Vector respectively.
It does end up messy if you’re not careful.
As it stands now, I have some exception handling which would be rendered unnecessary if I switched to 3D Tuples. I may go back and try to rework the code now that I’m done the book to see if I can get it to function with the sealed Tuple class. It might speed things up somewhat as well.
The concept used here is called “Homogenous coordinates”. Homogeneous coordinates are a fundamental concept in computer graphics that allows all transformations (including translations) to be represented as matrix multiplications.
In 3D graphics, using regular 3D vectors and 3×3 matrices isn’t sufficient to represent translations through matrix multiplication. The solution is to add a fourth component ‘w’ to create homogeneous coordinates.
For example, a 3D point P is represented as (x, y, z, 1) in homogeneous coordinates. When combined with a 4×4 translation matrix, this allows translations to be performed using standard matrix multiplication. Given a translation matrix
the point P can now be also translated by applying a matrix multiplication P’ = M*P = (x+tx, y+ty, z+tz, 1). On the other hand, a vector V=(x, y, z, 0) will not be affected by this transformation.
While the book uses simple tuples for practicality (i suppose), a more type-safe (but also language dependent) approach could be built upon this foundation. This would involve creating specific types and operations for vectors, points, colors and normals, all based on the general tuple concept. By that we for example could force correct types for all operations and having these checked during compile-time. For example, invalid operations like point + point, point + color etc., would result in compile-time errors.