TRTC – Matrix Transformations – Chapter 4

VartsiaSwift, TRTC

Compared to the previous chapter this was easier to deal with. In this chapter we could more like just to use the building blocks to create something useful. More like putting the pieces together rather than creating the actual pieces.

Different transformations are represented using different kind of matrices. Our starting point will be the identity matrix of size 4×4. And based on what kind of transformation we are trying to create we modify that identity matrix according to our needs. In this transformations the difference between our tuple if it’s a point (remember the 4th component the w = 1) or a vector (the 4th component aka the w = 0) will be crucial. Depending on the type of the tuple the matrix will affect the tuple differently.

Like in the previous chapter I won’t paste all the source code here. There is 19 different test cases along with all the implementation code so I try to focus on the turning points here. You will find the source code at gitlab.

Translation

Translation is operation that moves a point from one location to another and does that by shifting the x, y, z values. So first thing to do is to create a test case that checks if our translation works properly. There is three test cases for translation and here is the first one. Two other are quite similar.

The difference between vector and point is important here. We can translate point but we cannot translate vector. Since vector doesn’t know where it is in the first place there is no point to translate it somewhere else πŸ™‚


Transformation matrices are very clear in a visual way and to implement them was very fun. For me it was easier to implement the translation matrix function when I put the skeleton of the matrix in to the comments. It kind of right away shows you what this matrix is all about.

To construct translation matrix we need three different values. One for each coordinate axe. Every value defines how much translation there will be along that coordinate axe. The implementation is simple. I use float3 as an input but I also created an alternative function that takes each value separately as input. That could be found in source code.


Scaling

What scaling matrix does it makes things bigger or smaller. And it does so by multiplying it’s targets coordinates along each coordinate axe. When scaling factor is > 1 then things get bigger and when it’s < 1 things get smaller. Scaling is something that applies to vectors as well as to points. Vectors gets longer or shorter when scaled.

Test case for scaling is as short as it was for translation. First we create a transformation and then a point. Then we multiply that point by the transformation to get a new transformed point. Last step is to check if the result is what it should be and the books tells us what to expect. So here is the test case.


Implementation follows the same form for scaling as it was for translation. Input is three values for scaling like it was for translation. Their position inside the matrix is just different and thats why their effect is also different.


Rotation

Rotation does exactly that. Rotates πŸ™‚ Like the book says we are going to deal with the easier cases here the rotations around coordinate axes. We could also rotate around an arbitrary line but that is not covered here. All the rotations follows the same paradigm so I will put the code only for the first one here.

When rotating an object it has something to do with the angle. The angle defines how much we are rotating the object. The most common unit to define an angle is probably the degree where full circle is 360 degrees.

Specially with computers we often use radians as the unit for angels. Where the full circle is defined as 2Ο€. So the degrees and radians are probably the most known units for angels.

Sidenote about angles

As a land surveyor (which was my first profession) I want to point out that there is other units to define an angle than radians and degrees. In landsureying the unit is often gon where the full circle is 400 gon. In military the milliradians are often used. There is different milliradians which slightly differs from each other. There is a NATO mils, Warsaw Pact mils andSwedish “streck” where the full circle is either 6400, 6000 or 6300 respectively.

Around X

Testin rotation includes two test the full quarter and half quarter. Again the test case code is quite clean and straightforward. The implementation in other hand is, well maybe not complicated but something you must be careful.


The implementation is not complicated but to make it work double check is needed. I missed to put minus sign in the right place and the test returned a red box in Xcode.

/** Generates new RGMatrix4x4 rotation matrix arond X axis. ““ |0|1|2|3| <- Columns ____________ |1| 0| 0|0| |0|cos(r)|-sin(r)|0| |0|sin(r)| cos(r)|0| |0| 0| 0|1| ```` Takes rotation angle as radians. */ public func newRGRotationX(_ rad: Float) -> RGMatrix4x4 { var rotXm = RGMatrix4x4.identity() rotXm[1].y = cos(rad) rotXm[1].z = sin(rad) rotXm[2].y = -sin(rad) rotXm[2].z = cos(rad) return rotXm }

Around Y- and Z-axes

Rotating around Y and Z axes follows the same method as around X axe so those you can find from the source code. The position where the sin and cos values are places inside the matrix changes and here I show the skeletons.


Shearing

A shearing (or skew) transformation has the effect of making straight lines slanted.

Jamis Buck

In a way this is the most complex transformation. Basically because there is six different parameters for the function.



Chaining Transformations

In the previous post I mentioned that we could concatenate all the matrices by multiplying them together and the use that matrix to multiply our tuple to get the desired result at once. The thing we must be aware of is that the order which the multiplication is done is meaningful.

Note that the order of the multiplications is important! Matrix multiplication is associative, but not commutative.

Jamis Buck

So here is the second off the two tests cases what comes to chaining. This is actually the one that chains the transformations. The other calculates those separately. I think it’s fascinating that we could just calculate all our “transformation goals” together and then multiply the source to get the result. Even now when the test case does quite many things the code is short.


Putting it together

In this chapters “Putting it together” is cool. We could use all the building blocks created previously and create something…well not complex, but something that shows how practical our code created so far is. The result in this challenge is the image below. Twelve dots representing the twelve hours of clock face.

To produce the image above there is few steps to take but no too many. This is a good example that shows the power or the code created so far. Basically the code includes a creating a canvas. I made the canvas square since the clock face is usually square πŸ™‚ Then there is the color we need for the dots. I choose green. Next step is to create point that represents the center of the canvas. This is a part that we could easily improve so that the canvas could have a method that returns its center, but I leave it for later.

To create 12 dots sounds like a loop so thats what I created. And in every iteration of the loop there is a new a dot created based on the new calculated position for the “base” point. Point is scaled, rotated and scaled to it’s position. The point is put to the canvas using the colour chosen earlier. At the end the canvas is saved to a file. I put the whole code here.


For me this chapter was fun to do. So thank you Jamis for this journey so far πŸ™‚ Next chapter opening says that “You’re all done with the foundational work,…” so I guess something new and interesting is to come.