title: How to combine multiple transforms for a 3D model?
body: <p>We are using Helix Toolkit to process 3D models. The scenario is that the object should be translated and rotated in a mixed order using Double up/down value input.</p>
  
  <p>Multiple rotation on different axis works fine. However, when the object is translated on one of the axes, the following rotation moves the object instead of rotating with the existing offsets as it's center of rotation.</p>
  
  <p>Here's the gist of steps-</p>
  
  <ol>
  <li>Remove the existing MatrixTransform3D from the Transform3DGroup.    </li>
  <li>Create a new rotate or translate transform. </li>
  <li>If the model is rotated, prepend the previous translate transform to the new  rotate transform. </li>
  <li>If the model is translated, prepend the previous rotate transform to the new        translate transform. </li>
  <li>Add the new matrixtransform3D to the transform3dgroup which is bound as the models transform in XAML.</li>
  </ol>
  
  <p>I am wondering what is the right way to combine the translate and rotate transforms. Appreciate your help.</p>
  
  <p>Code:</p>
  
  <pre><code>Matrix3D CalculateRotationMatrix()
  {
      Point3D rotationCenter = new Point3D(-1 * MoveX.DataValue, -1 * MoveY.DataValue, -1 * MoveZ.DataValue);
      _rotateMatrix = new Matrix3D();
  
      _rotateMatrix.RotateAt(new Quaternion(_xAxisVector3D, RotateX.DataValue), rotationCenter);
      _rotateMatrix.RotateAt(new Quaternion(_yAxisVector3D * _rotateMatrix, RotateY.DataValue), rotationCenter);
      _rotateMatrix.RotateAt(new Quaternion(_zAxisVector3D * _rotateMatrix, RotateZ.DataValue), rotationCenter);
  
      return _rotateMatrix;
  }
  
  Matrix3D CalculateTranslationMatrix() {
      _translateMatrix = new Matrix3D();
      _translateMatrix.Translate(new Vector3D(MoveX.DataValue, MoveY.DataValue, MoveZ.DataValue));
      return _translateMatrix; }
  
  void UpdateTransform(bool isRotate = false)
  {
      if (ModelTransform.DataValue.Children.Count &gt; 0)
      for (int i = 0; i &lt; ModelTransform.DataValue.Children.Count; i++)
      {
      ModelTransform.DataValue.Children.Remove(ModelTransform.DataValue.Children[i]);
      }
  
      Matrix3D newMatrix3D;
  
      if (isRotate)
      {
          newMatrix3D = CalculateRotationMatrix();
          newMatrix3D.Append(_translateMatrix);
      }
      else
      {
          newMatrix3D = CalculateTranslationMatrix();
          newMatrix3D.Prepend(_rotateMatrix);
      }
  
      ModelTransform.DataValue.Children.Add(new MatrixTransform3D(newMatrix3D));
  }
  </code></pre>
  
  <p>ModelTransform.DataValue is of type Transform3DGroup and is bound to the 3D model in xaml.</p>
  
  <p><em>Updated Code: (Rotate doesn't shift the model but not rotating around the new center point)</em></p>
  
  <pre><code>void UpdateTransform(eMove move)
          {
              if (ModelTransform.DataValue.Children.Count &gt; 0)
                  for (int i = 0; i &lt; ModelTransform.DataValue.Children.Count; i++)
                  {
                      ModelTransform.DataValue.Children.Remove(ModelTransform.DataValue.Children[i]);
                  }
  
              Matrix3D newMatrix3D = new Matrix3D();
  
              switch (move)
              {
                  case eMove.Translate:
                      newMatrix3D = CalculateTranslationMatrix();
                      newMatrix3D.Prepend(_rotateMatrix);
                      break;
                  case eMove.Rotate:
                      // Translate the model
                      newMatrix3D = _translateMatrix;
                      double xAfterRotateTranslate = newMatrix3D.OffsetX;
                      double yAfterRotateTranslate = newMatrix3D.OffsetY;
                      double zAfterRotateTranslate = newMatrix3D.OffsetZ;
  
                      // Rotate the model
                      newMatrix3D.Append(CalculateRotationMatrix());
                      _xAfterRotate = newMatrix3D.OffsetX;
                      _yAfterRotate = newMatrix3D.OffsetY;
                      _zAfterRotate = newMatrix3D.OffsetZ;
  
                      //Translate back the difference after the rotation
                      Matrix3D negativeTranslate = new Matrix3D();
                      negativeTranslate.Translate(new Vector3D(xAfterRotateTranslate - _xAfterRotate,
                      yAfterRotateTranslate - _yAfterRotate, zAfterRotateTranslate * _zAfterRotate));
                      newMatrix3D.Append(negativeTranslate);
                      break;
              }
  
              ModelTransform.DataValue.Children.Add(new MatrixTransform3D(newMatrix3D));
          }
  
  Matrix3D CalculateTranslationMatrix()
          {
              _translateMatrix = new Matrix3D();
              _translateMatrix.Translate(new Vector3D(MoveX.DataValue, MoveY.DataValue, MoveZ.DataValue));
              return _translateMatrix;
          }
  
   Matrix3D CalculateRotationMatrix()
          {
              Point3D rotationCenter = new Point3D(-1 * MoveX.DataValue, -1 * MoveY.DataValue, -1 * MoveZ.DataValue);
              _rotateMatrix = new Matrix3D();
  
              _rotateMatrix.RotateAt(new Quaternion(_xAxisVector3D, RotateX.DataValue), rotationCenter);
              _rotateMatrix.RotateAt(new Quaternion(_yAxisVector3D * _rotateMatrix, RotateY.DataValue), rotationCenter);
              _rotateMatrix.RotateAt(new Quaternion(_zAxisVector3D * _rotateMatrix, RotateZ.DataValue), rotationCenter);
  
              return _rotateMatrix;
          }
  </code></pre>