I'm deeply frustrated and intimitated by applying rotations

How can I apply vector rotations around the three axis and how can I extract them later on.

Looking at the API and the matrix structure I feel hopeless - one wants a vector and degree (SUTransformationRotation) and the other a 3x3 matrix.

Do you have a desktop edition? If not install 2017 Make and get ThomThom’s transformation inspector tool from the Extension Warehouse. This will enable you to inspect your C API generated model’s within SketchUp. (Just backsave them as 2017 version.)

And if you’ll be using attribute dictionaries, I’d also recommend Aerilius’ Attribute Inspector extension.

Confused. I’m asking how to apply axis based rotations to an instance.

In the free web-based version that your profile indicates you are using?

You do realize this is the SDK section right?

It doesn’t matter what version of sketchup I have.

Yes I do realize this is the SDK section. :roll_eyes:

Ok ignore everything else currently it is important extracting the rotation as floating point values per axis programmatically.

I think I’ve got the exportion part.

Don’t be. I am basically giving you advice on how to inspect the models you create with the C API.
The desktop editions can have extensions. The extension I told you about, will allow you to inspect the transformation matrices of the instances that you transform. Ie, it’s a self help avenue.

Firstly, again I remind you that SketchUp’s modeling axes are different from game engines.
Z is up, X is to the right (points toward east,) Y runs away from the viewer (and is north 0 degrees.)


A simple single rotation would be done by creating a rotational transform.
SUTransformationRotation

  • The point argument places the rotational axis vector somewhere in 3D space.
    This does not have to be (but can be) within or even near the instance itself.
  • The vector argument is the axis of rotation.
  • The angle argument will be the angle to rotate about the axis defined by the vector argument.

If you wish a compound rotation, then you’ll need to create 2 rotational transforms, and multiply them together, using the SUTransformationMultiply() function, and then apply the resultant transform to the instance.
You can also “mix in” translational and scaling transforms by multiplying them also.

But they are traditionally applied in a particular order. Translational first. Rotational second in (X, Y then Z order.) Then Scaling (X, Y then Z order.) Decomposing a transformation matrix must be done in reverse order. (See Aerilius’ code … link posted below.)

You could try this …

  1. You get the transform of the instance.
  2. from this you get the transform’s 3 axial vectors (X, Y and Z.) SUTransformationGetXAxis, etc.
  3. You get the model’s global Axes object … SUModelGetAxes
  4. from this you get the model’s 3 axial vectors (X, Y and Z.) SUAxesGetXAxis, etc.
  5. You compare each of the 3 corresponding instance transformation axis with the model’s corresponding axis.
    … ie X for X, Y for Y, etc. using SUVector3DAngleBetween

Note that the both (Ruby and C) API’s may have a limitation with the angle between method/function. I think it works using dot product for vectors which always returns a value between 0 and 180. (May not be a problem if the return value is signed.)

There are some ways to use trigonometry on the matrix values to get the axial rotations.
Aerilius posted code in Ruby here …

3 Likes

I still don’t understand where the 3x3 rotation matrix is located inside the transformation matrix - can you specify which indices define it.

Is it 0 - 2, 4 - 6, 8 - 10

If you (again) install a desktop SketchUp and install ThomThom’s Transfromation Inspector (also requires his TT_Lib2 library,) … you’ll be able to visualize transformations, and play around with editing them parametrically.

https://extensions.sketchup.com/en/content/tt_lib²
https://extensions.sketchup.com/en/content/transformation-inspector

In the image below, the 3x3 matrix has a green background.

Well the Ruby API returns a nested array where each row is a subarray.
So it would be ary[0][0..2], ary[1][0..2] and ary[2][0..2]

But I think the C API just returns a flattened 16-element array (the equivalent of the Ruby API’s transformation.to_a method.)

So yes you’d use: ary[0..2], ary[4..6] and ary[8..10]

I’ve made a Ruby library that can help extracting Euler angles. Maybe it can be helpful for implementing something similar using the C API.

I don’t know how experienced you are with transformation matrices but the angles aren’t directly written anywhere in there. Instead you can think of the matrix as the 3 axis vectors for a local coordinate system, as well as a translation (to get really technical the translation mathematically equals to a shearing in a 4th dimension). To extract angles you have to do some trigonometry.

1 Like

OK I used the formula from the wiki page to set translations but now objects are doubled in a weird way:

doubledoor

The above is supposed to be a single door. Here is my code:

	static struct SUTransformation matrixtransform, matrixrotationX, matrixrotationY, matrixrotationZ;

	SUTransformationTranslation(&matrixrotationX, (struct SUVector3D[]) { 0, 0, 0 });
	SUTransformationTranslation(&matrixrotationY, (struct SUVector3D[]) { 0, 0, 0 });
	SUTransformationTranslation(&matrixrotationZ, (struct SUVector3D[]) { 0, 0, 0 });

	0[matrixrotationZ.values] = cos(rotation.z),
	1[matrixrotationZ.values] = -sin(rotation.z),
	2[matrixrotationZ.values] = 0,

	4[matrixrotationZ.values] = sin(rotation.z),
	5[matrixrotationZ.values] = cos(rotation.z),
	6[matrixrotationZ.values] = 0,

	8[matrixrotationZ.values] = 0,
	9[matrixrotationZ.values] = 0,
	10[matrixrotationZ.values] = 1,

	0[matrixrotationY.values] = cos(rotation.y),
	1[matrixrotationY.values] = 0,
	2[matrixrotationY.values] = sin(rotation.y),

	4[matrixrotationY.values] = 0,
	5[matrixrotationY.values] = 1,
	6[matrixrotationY.values] = 0,

	8[matrixrotationY.values] = -sin(rotation.y),
	9[matrixrotationY.values] = 0,
	10[matrixrotationY.values] = cos(rotation.y),

	0[matrixrotationX.values] = 1,
	1[matrixrotationX.values] = 0,
	2[matrixrotationX.values] = 0,

	4[matrixrotationX.values] = 0,
	5[matrixrotationX.values] = cos(rotation.x),
	6[matrixrotationX.values] = -sin(rotation.x),

	8[matrixrotationX.values] = 0,
	9[matrixrotationX.values] = sin(rotation.x),
	10[matrixrotationX.values] = cos(rotation.x);

	SUTransformationTranslation(&matrixtransform, &translation);
	
	SUTransformationMultiply(&matrixtransform, &matrixrotationX, &matrixtransform);
	SUTransformationMultiply(&matrixtransform, &matrixrotationY, &matrixtransform);
	SUTransformationMultiply(&matrixtransform, &matrixrotationZ, &matrixtransform);

	SUComponentInstanceSetTransform(instance, &matrixtransform);

Is this your door component?

If not, take extra care with door and window components. Actually any “snap_to” component. If they are snap_to components then they are drawn lying flat on the XY ground plane (which is the cutting plane if their “cuts_opening” flag is set,) facing up (the door’s outside face’s normal vector is perpendicular to the blue Z axis.)
In the GUI when the user is placing one of these type of components, the core automatically reorients the instance attached to the cursor when it nears a snapable face (which depends upon what the definition’s “snap_to”/“glue to” setting is, ie, vertical, horizontal, sloped, or any.)

I haven’t assigned any special properties to this specific component instance. In fact I draw everything equally dumb - by using 3d faces.

My original idea was doing something like:

	SUTransformationRotation(&matrixrotationX, &translation, (struct SUVector3D[]) { 1, 0, 0 }, rotation.x * M_PI / 180.0),
	SUTransformationRotation(&matrixrotationY, &translation, (struct SUVector3D[]) { 0, 1, 0 }, rotation.y * M_PI / 180.0),
	SUTransformationRotation(&matrixrotationZ, &translation, (struct SUVector3D[]) { 0, 0, 1 }, rotation.z * M_PI / 180.0);

	SUTransformationTranslation(&matrixtransform, &translation);

	SUTransformationMultiply(&matrixtransform, &matrixrotationX, &matrixtransform);

	SUTransformationMultiply(&matrixtransform, &matrixrotationY, &matrixtransform);

	SUTransformationMultiply(&matrixtransform, &matrixrotationZ, &matrixtransform);

	SUComponentInstanceSetTransform(instance, &matrixtransform);

But obviously this doesn’t work since the resulting transformations are way off the original models in the game engine.

Never mind I got it to work - excluding duplicates that is and I haven’t even started exportion yet.

I’m actually working on an update to better visualize the matrix. My current released version indicate row-major order. But SketchUp uses column-major order.

New version is currently looking like this:

Color coding for the rotation axes, along with their angles described in degrees.
Note that the translation values are now located to the right, not the bottom. Hovering over a matrix will display what index it relates to.

WIP is is the dev/column-major branch:

3 Likes

FR: When hovering a field there could be a tooltip saying “X component of Y axis” and the like. I never really got transformation matrices until I noticed how the rows (or is it teh columns) of the 3x3 rotation matrix are the vectors of the axes.

1 Like

Wow. Never noticed this either, until now. Thanks.

1 Like

That was a key aha moment for me too, and I’ve gone to using this idea in my extensions when placing complicated groups such as angular dimensions, slope markers, etc. I draw the group at the origin in the model (which makes it easier to place all the parts) and then use unit vectors at the desired destination to create the Transformation from an Array without ever knowing or caring about the angles involved.

1 Like