views:

4116

answers:

3

I'm trying to find the best way to rotate a container (or anything for that matter) using the matrix3D features in flash 10 for flex.

I have managed to get a container to rotate around a point that is not its registration point but I’ve only managed this by turning off the clipping on a container then placing the contents somewhere other than (0,0,0). This does work, but it’s not very intuitive and sucks when trying to place several items or even if you need to move the rotation point.

Using the matrix3D class seems to be the way to go, but I'm not sure exactly how.

Cheers

Additional info - If my container is at (0,0,0) on the stage and I wish to rotate around the middle X coord of container then I translate by container.width/2 for the X then rotate and translate back again. This works fine. BUT if my container is say at (10, 0, 0) then if I translate the same as above and add the extra 10 then it doesn't work.

Soloution (which is complete rubbish - please explain if you can) As has been suggested you need to translate, rotate, then -traslate. I knew this but it never worked.
BUT see the soloution below, I don't get it. (panel is the object I'm rotating, I call function both() )

private function rotateOnly() : void {
        panel.transform.matrix3D.appendRotation(36, Vector3D.Y_AXIS);
}

private var valueToMove : Number = 300;
private var translateUpOrDown : Boolean = false;
private function translateOnly() : void {
    if(translateUpOrDown){
            panel.transform.matrix3D.appendTranslation(valueToMove, 0, 0);
    translateUpOrDown = false;
} else {
    panel.transform.matrix3D.appendTranslation(-valueToMove, -0,0);
    translateUpOrDown = true;
}
 }

 //I do not run both chunks of code here at once, this is only to show what I've tried   
 private function both() : void {
     //IF I call this function and call this chunk then the rotation works
        translateOnly();
        rotateOnly();
        translateOnly(); 


     //If I call this chunk which does the exact same as the above it does NOT work!!
        panel.transform.matrix3D.appendTranslation(valueToMove, 0,0);
panel.transform.matrix3D.appendRotation(36, Vector3D.Y_AXIS);
panel.transform.matrix3D.appendTranslation(-valueToMove, 0,0); 
 }
+2  A: 

Rotation matrices always rotate around the origin.

Rotation of an object around an arbitrary point P usually requires:

  1. translation of the object by -P
  2. rotation of the object as required
  3. translation of the object by P
Alnitak
Yip i've tried that. I've taken the matrix3D of the container, done a appendTranslation(-x, -y, -z) then did a appendRotation, then another appendTranslation(x, y, z).i've tried other variations using the matrix3D class but I can't get it quite right.
kenneth
Alnitak's solution is assuming the object is at origin.
Andy Li
A: 

have you considered simply moving the pivot vector ?

var matrix:Matrix3d = new Matrix3d();
matrix.appendRotation(degrees, axis, new Vector3d(container.width/2,container.height/2,0));
Theo.T
I have indeed tried that and it had some unexpected results (not the results I was after anyway). The livedocs really need more info or examples to show the 3D working as you can't get at the source code of the matrix3D class (unless I'm wrong there, but I couldn't).
kenneth
+1  A: 

OK, the solution would be -

1 - create your own component with vars for the original X, Y, Z and width and height. These will be used for convenence to save extra matrix operations. E.G extend the Box class and just add those var to the new class.

2 - add component to app, something like the below. (the orig values are because the actual x,y,z so on will change during rotation but you need to orig values to calculate the correct rotation.

<local:RotationContainer 
  id="movingBox" 
  width="50"
  origWidth="50"
  height="60"
  origHeight="60"
  x="80"
  origX="80"
  y="70"
  origY="70"
  z="0"
  origZ="0"
  enterFrame="rotateObject(event)"
  />

3 - use the following code when rotating, call in the above enterFrame event

private var translateUpOrDown : Boolean = false;
        private function translateOnly(obj : Object, valueToMoveX : Number,  valueToMoveY : Number) : void {

         if(translateUpOrDown){
          obj.transform.matrix3D.appendTranslation(valueToMoveX, valueToMoveY, 0);
          translateUpOrDown = false;
         } else {
          obj.transform.matrix3D.appendTranslation(-valueToMoveX, -valueToMoveY, 0);
          translateUpOrDown = true;
         }
        }

        private function rotateOnly(obj : Object) : void {
         obj.transform.matrix3D.appendRotation(rotationAmount, Vector3D.Y_AXIS);
        }

        private function rotateObject(event : Event) : void {

         var offsetX : Number = (event.currentTarget.origWidth / 2) + event.currentTarget.origX;
         var offsetY : Number = (event.currentTarget.origHeight / 2) + event.currentTarget.origY;

         translateOnly(event.currentTarget, offsetX, offsetY);
         rotateOnly(event.currentTarget);
         translateOnly(event.currentTarget, offsetX, offsetY);
        }

4 - thats it. This will rotate around the center point, on the Y axis. Change the offset values for different points of rotation.

UPDATE As pointed out you do not need to move the calls into separate function, but you will need to use the above so that you can get at the original width, height, x & y (providing your not hard coding all the values)

kenneth