Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to rotate a canvas at a specific point using android.graphics.Camera.rotateX(angle)

I am trying to use the Camera (android.graphics.Camera not the hardware camera) to rotate a views canvas around a specific point, in this instance the middle of the canvas.

In dispatchDraw(Canvas canvas) -- for brevity I am leaving out all the non important parts.

camera.save();
   camera.rotateX(0);
   camera.rotateY(0);
   camera.rotateZ(angle);
   camera.getMatrix(cameraMatrix);
 camera.restore(); 

 canvas.concat( cameraMatrix );

The canvas rotates, but always from the upper left hand corner.

NOTE: Because the canvas has been constructed to be larger than the display area I also need to translate the final result so that it is centered in the display, I can do this with either

canvas.translate(xOffset,yOffset) PRIOR to calling the camera methods

OR

cameraMatrix.preTranslate(xOffset,yOffset) AFTER the camera methods

Both correctly center the canvas in the display but I can't seem to get the rotation point to be the center for the camera.rotateZ(angle) call, tried using the methods in the 3D android sample but while they seem to work for the X / Y axis them don't seem to affect the Z axis

Any help would be appreciated, the doc's are not exactly verbose.

like image 703
Idistic Avatar asked Jul 07 '11 00:07

Idistic


3 Answers

Solved this, not sure if it's the best way but it works. The solution was to

Translate the canvas first to center the larger canvas in the display

Then apply the camera rotations

Then to use the pre and post translate methods on the matrix to change the rotation point similar to what the android sample did.

The missing bits were to do the canvas translation first, and I was also not using the larger canvas size to calculate the offsets for the pre and post translate methods.

Here is the modified code if it helps anyone else out.

// Center larger canvas in display (was made larger so
// corners will not show when rotated) 
canvas.translate(-translateX, -translateY); 

// Use the camera to rotate a view on any axis
camera.save();
    camera.rotateX(0);
    camera.rotateY(0);
    camera.rotateZ(angle); // Rotate around Z access (similar to canvas.rotate)                                 

    camera.getMatrix(cameraMatrix);

    // This moves the center of the view into the upper left corner (0,0) 
    // which is necessary because Matrix always uses 0,0, as it's transform point 
    cameraMatrix.preTranslate(-centerScaled, -centerScaled);

    // NOTE: Camera Rotations logically happens here when the canvas has the 
    // matrix applied in the canvas.concat method 

    // This happens after the camera rotations are applied, moving the view 
    // back to where it belongs, allowing us to rotate around the center or 
    // any point we choose 
    cameraMatrix.postTranslate(centerScaled, centerScaled);
camera.restore();

canvas.concat(cameraMatrix);

If anyone has a better way or sees a problem please leave a comment.

like image 63
Idistic Avatar answered Nov 02 '22 21:11

Idistic


This worked for me:

@Override
public void drawPixmap3D(Pixmap pixmap, int x, int y, int r) {
    Camera camera = mCamera;
    int cx = pixmap.getWidth()/2;
    camera.save();
    camera.rotateY(r);
    camera.getMatrix(mtx);
    mtx.preTranslate(-cx, 0);
    mtx.postTranslate(x, y);
    camera.restore();
    canvas.drawBitmap(((AndroidPixmap)pixmap).bitmap, mtx, this.paint);
}
like image 3
Erik Avatar answered Nov 02 '22 20:11

Erik


Use this as the transformation in your animation class

protected void applyTransformation(float interpolatedTime, Transformation t) {

    final float fromDegrees = 0;

    float degrees = fromDegrees

    + ((180- fromDegrees) * interpolatedTime);

    final float centerX = mCenterX;

    final float centerY = mCenterY;

    final Camera camera = mCamera;

    final Matrix matrix = t.getMatrix();

    camera.save();

    camera.rotateX(degrees);

    camera.getMatrix(matrix);

    camera.restore();

    matrix.preTranslate(-centerX, -centerY);

    matrix.postTranslate(centerX, centerY);

}
like image 1
Rikki Avatar answered Nov 02 '22 21:11

Rikki