How To Apply an SuTransformation To a SUPoint


#1

Hi
Reading through the documentation for the SUTransformation struct I have put the following function together that applies the transformation to an SUPoint:

void Matrix::Transform(SUPoint3D& point, SUTransformation matrix)
{
	 SUPoint3D transformedPoint = {point.x, point.y, point.z};


	transformedPoint.x = (matrix.values[0]*point.x) + (point.y*matrix.values[4]) + (point.z*matrix.values[8]) + matrix.values[12];
	transformedPoint.y = (matrix.values[1]*point.x) + (point.y*matrix.values[5]) + (point.z*matrix.values[9]) + matrix.values[13];
	transformedPoint.z = (matrix.values[2]*point.x) + (point.y*matrix.values[6]) + (point.z*matrix.values[10]) + matrix.values[14];

	point.x = transformedPoint.x;
	point.y = transformedPoint.y;
	point.z = transformedPoint.z;
}

My question is have I correctly applied the transformation given that the matrix is stored in the array using column-major order.

Thanks


#2

That is correct for most uses of the transformation matrix. You don’t need to include “matrix.values” indices 3, 7 and 11 because they are always zero.

The other thing you might want to consider is including “matrix.values[15]”, which is almost always 1 and won’t need to be included when 1, but it is the reciprocal of a uniform scale factor.

uniform_scale_factor = 1.0 / matrix_values[15];

In order to include it, we can look at the general form of a 4x4 matrix times a 4x1 matrix from URL:
http://www.opengl-tutorial.org/beginners-tutorials/tutorial-3-matrices/

The section “Transformation matrices”;
Paragraph titled “Matrix x Vertex (in this order!!) = TransformationVertex”.
I believe it is fair use to show the equation for education purposes (and it is very common):

I’m not really familiar with the C++ SDK, but in Ruby development, “m”, “n”, and “o” (array indices 3, 7 and 11) are kept at zero and attempts at setting them to anything else is ignored (it requiries a constructor to initialize them. In OpenGL, they can be used for perspective calculations). Matrix element “p” is array element “matrix.values[15]”.

Now the equation above is a generalized form. The alphabetical sequence is "row-major, so matrix element “e” is Sketchup array element “matrix.values[1]”. Observe that the 4x1 matrix includes a fourth array element “w”. Including a fourth value is called “homogeneous coordinates”. The value “w” is set to zero for a vector transformation, with the zero removing any translation and uniform scaling in the fourth column of calculations. Three dimensional points are affected by translation and scaling, so the “w” is set to 1 for points.

Since matrix elements m, n, and p are zero, the four row of the calculations simplifies to “pw”, which is usually one times one. If it isn’t one, then the 4x1 result needs to be normalized by dividing x, y, z and w by “pw”, resulting in [x/pw, y/pw, z/pw, 1]. In the Ruby API, the following two constructors can initialize a transformation that sets the last array element to something other than 1:

transformation#scaling

t = Geom::Transformation.scaling scale
t = Geom::Transformation.scaling point, scale

These can be applied to a group or component so this its transformation includes a non-uniform scaling factor. My testing has shown that Sketchup’s built-in scale tool does not affect the uniform scale factor, even when scaling by the same amount in all directions.

Now in the Ruby API, your function is built-in, and could be accomplished with:

point.transform! matrix

Is there not an equivalent in the C++ SDK?


#3

Thanks for the detailed explanation. As far as I’m aware the c++ sdk only has a struct for the transformation matrix no helpful utility classes.


#4

The more detailed the explanation, the more likely of finding an error.
I have an issue with part of my answer:
> “The value “w” is set to zero for a vector transformation, with the zero removing any translation and uniform scaling in the fourth column of calculations”.

Testing at the Ruby console shows that vectors are scaled by uniform scaling (but not by translation).
One could search the internet for a library that supports 3D geometry operations. (It is possible that Sketchup itself doesn’t build it in, but instead uses OpenGL). The URL I provided includes code to invoke the OpenGL API for your multiplication:

You would have to figure out how to populate myMatrix and myVector with your specific values.


#5

I believe you have it correct. I’m not sure why you initialize the transformedPoint to the input point values, however, since its values get overwritten with the transformed values. Also, having not used the C APIs, I’m not sure, but I’m curious if you can do something like: point = transformedPoint instead of setting each value separately?


#6

You can also use the APIs provided by sketchup itself.
Look into the geometry.h of the sketchup sdk - http://extensions.sketchup.com/developer_center/sketchup_c_api/sketchup/model_2geometry_8h.html

You can use SUTransform to apply it on a 3D point as well.
SUPoint3DTransform( , );