# 5.5. Transformations

Unlike other property nodes, transformation nodes do not replace the current geometric transformation element in the action state. Instead, they have a cumulative effect on the current geometric transformation. In Figure 5.24, “ Cumulative Effect of Transformation Nodes, for example, the transformations in node xfm1 are applied first, followed by the transformations in node xfm2.

The cube is affected by only the transformation in xfm1. The sphere, however, is affected by both xfm1 and xfm2.

### SoTransform Node

An SoTransform SoTransform SoTransform node includes the following fields:

 translation (SoSFVec3f) the translation in x, y, and z. The default value is [0.0 0.0 0.0]. rotation (SoSFRotation) the rotation in terms of an axis and an angle. The default value is [0.0 0.0 1.0], 0.0. scaleFactor (SoSFVec3f) the scaling factor in x, y, and z. The default value for this field is [1.0 1.0 1.0]. scaleOrientation (SoSFRotation) the rotation to apply before the scale is applied. The default value is [0.0 0.0 1.0], 0.0. center (SoSFVec3f) the center point for rotation and scaling. The default value for this field is [0.0 0.0 0.0].

Tip: If you are using only one of the fields in an SoTransform SoTransform SoTransform node, you can substitute the corresponding “lightweight” version. For rotations, useSoRotation SoRotation SoRotation orSoRotationXYZ SoRotationXYZ SoRotationXYZ ; for translations, use SoTranslation SoTranslation SoTranslation ; and for scaling, use SoScale SoScale SoScale .

### Order of Transformations

Within each SoTransform SoTransform SoTransform node, the fields are applied so that the last field in the node (the center) affects the shape object first. The order is first the center, followed by the scale orientation, the scaling factor, the rotation, and the translation.

Figure 5.25, “ Two Groups with Transformations in Different Order and Figure 5.26, “ Effects of Ordering Transformation Fields” show how different ordering of transformations produces different results. At the left of Figure 5.26, “ Effects of Ordering Transformation Fields”, the temple is scaled, rotated, and then translated. The transform node closest to the shape object affects the object first. You thus need to read backward through the code to see how the effects of the transformations are felt. At the right of Figure 5.26, “ Effects of Ordering Transformation Fields”, the temple is rotated, then scaled and translated. Example 5.9, “ Changing the Order of Transformations shows the code for the two sets of transformations.

Example 5.9.  Changing the Order of Transformations

```#include <Inventor/Xt/SoXt.h>
#include <Inventor/Xt/viewers/SoXtExaminerViewer.h>
#include <Inventor/SoDB.h>
#include <Inventor/nodes/SoMaterial.h>
#include <Inventor/nodes/SoRotationXYZ.h>
#include <Inventor/nodes/SoScale.h>
#include <Inventor/nodes/SoSeparator.h>
#include <Inventor/nodes/SoTranslation.h>

main(int, char **argv)
{
// Initialize Inventor and Xt
Widget myWindow = SoXt::init(argv[0]);
if (myWindow == NULL) exit(1);

SoSeparator *root = new SoSeparator;
root->ref();

// Create two separators, for left and right objects.
SoSeparator *leftSep = new SoSeparator;
SoSeparator *rightSep = new SoSeparator;
// Create the transformation nodes.
SoTranslation *leftTranslation  = new SoTranslation;
SoTranslation *rightTranslation = new SoTranslation;
SoRotationXYZ *myRotation = new SoRotationXYZ;
SoScale *myScale = new SoScale;

// Fill in the values.
leftTranslation->translation.setValue(-1.0, 0.0, 0.0);
rightTranslation->translation.setValue(1.0, 0.0, 0.0);
myRotation->angle = M_PI/2;   // 90 degrees
myRotation->axis = SoRotationXYZ::X;
myScale->scaleFactor.setValue(2., 1., 3.);

// Add transforms to the scene.

// Read an object from file. (as in example 4.2.Lights)
SoInput myInput;
if (!myInput.openFile("temple.iv"))
return (1);
if (fileContents == NULL) return (1);

// Add an instance of the object under each separator.

// Construct a renderArea and display the scene.
SoXtExaminerViewer *myViewer =
new SoXtExaminerViewer(myWindow);
myViewer->setSceneGraph(root);
myViewer->setTitle("Transform Ordering");
myViewer->viewAll();
myViewer->show();

SoXt::show(myWindow);
SoXt::mainLoop();
}
```
```using OIV.Inventor.Nodes;
using OIV.Inventor.Win;
using OIV.Inventor.Win.Viewers;
using OIV.Inventor;

namespace _05_6_TransformOrdering
{
public partial class MainForm : Form
{
SoWinExaminerViewer myViewer;

public MainForm()
{
InitializeComponent();
CreateSample();
}

public void CreateSample()
{
SoSeparator root = new SoSeparator();

// Create two separators, for left and right objects.
SoSeparator leftSep = new SoSeparator();
SoSeparator rightSep = new SoSeparator();

// Create the transformation nodes
SoTranslation leftTranslation = new SoTranslation();
SoTranslation rightTranslation = new SoTranslation();
SoRotationXYZ myRotation = new SoRotationXYZ();
SoScale myScale = new SoScale();

// Fill in the values
leftTranslation.translation.Value = new SbVec3f(-1.0f, 0.0f, 0.0f);
rightTranslation.translation.Value = new SbVec3f(1.0f, 0.0f, 0.0f);
myRotation.angle.Value = (float) (Math.PI / 2.0f);   // 90 degrees
myRotation.axis.Value = SoRotationXYZ.AxisType.X;
myScale.scaleFactor.Value = new SbVec3f(2.0f, 1.0f, 3.0f);

// Add transforms to the scene.

// Read an object from file. (as in example 4.2.Lights)
SoInput myInput = new SoInput();
myInput.OpenFile("../../../../../data/temple.iv");

// Add an instance of the object under each separator.

// Construct a renderArea and display the scene.
myViewer = new SoWinExaminerViewer(this, "", true,
SoWinFullViewer.BuildFlags.BUILD_ALL, SoWinViewer.Types.BROWSER);
myViewer.SetSceneGraph(root);
myViewer.SetTitle("Transform Ordering");
myViewer.ViewAll();
}
}
}
```
```import tools.*;

import com.openinventor.inventor.nodes.*;
import com.openinventor.inventor.*;
import com.openinventor.inventor.awt.*;

import java.awt.*;

public class Main extends DemoInventor
{

public static void main(String[] args)
{
Main applet = new Main();
DemoInventor.isAnApplet = false;
applet.start();
demoMain(applet, "Transform Ordering");
}

public void start()
{
super.start();

// Create two separators, for left and right objects.
SoSeparator leftSep = new SoSeparator();
SoSeparator rightSep = new SoSeparator();

// Create the transformation nodes
SoTranslation leftTranslation = new SoTranslation();
SoTranslation rightTranslation = new SoTranslation();
SoRotationXYZ myRotation = new SoRotationXYZ();
SoScale myScale = new SoScale();

// Fill in the values
leftTranslation.translation.setValue(-1.0f, 0.0f, 0.0f);
rightTranslation.translation.setValue(1.0f, 0.0f, 0.0f);
myRotation.angle.setValue((float) java.lang.Math.PI / 2.0f); // 90 degrees
myRotation.axis.setValue(SoRotationXYZ.X);
myScale.scaleFactor.setValue(2.0f, 1.0f, 3.0f);

// Read an object from file. (as in example 4.2.Lights)
SoInput myInput = new SoInput();
if (!myInput.openFile(m_prefix + "../../../../data/models/temple.iv"))
System.exit(1);
if (fileContents == null)
System.exit(1);

SoSeparator root = new SoSeparator();
{ // Assemble scene graph

// Add transforms to the scene.

// Add an instance of the object under each separator.
}

// Construct a renderArea and display the scene.
SwSimpleViewer myViewer = new SwSimpleViewer();
myViewer.setSceneGraph(root);

setLayout(new BorderLayout());