如何在特定的点上使用android.graphics.Camera.rotateX(角度)旋转画布

时间:2023-02-04 17:19:37

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.

我正在尝试使用相机(android.graphics)。照相机不是硬件摄像机)旋转一个视图画布在一个特定的点,在这个实例中画布的中间。

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

在dispatchDraw(Canvas Canvas)中——为了简洁起见,我省略了所有不重要的部分。

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

中心的画布显示正确但我似乎无法得到旋转点的中心camera.rotateZ(角)打电话,试着用3 d android样本的方法虽然他们似乎工作的X / Y轴他们似乎并不影响Z轴

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

任何帮助都是值得赞赏的,医生的建议并不完全是冗长的。

4 个解决方案

#1


8  

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.

然后在矩阵中使用pre和post translate方法来改变旋转点,这与android样本的旋转点相似。

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.

如果有人有更好的方法或看到问题,请留下评论。

#2


3  

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);
}

#3


1  

I like to do things the difficult way and "roll my own". Moreover, if you are doing animations cumulative errors can creep in concat'ing Matrix's.

我喜欢做一些困难的事情,“滚我自己的”。而且,如果你在做动画,累积误差可能会在concat'ing Matrix中出现。

float rotate; // rotation in degrees

float vcx; // center of rotation of view
float vcy;

float gcx; // center of rotation of graphic
float gcy;

float theta = (float) (Math.PI/180.0*rotate);
float sin = (float) Math.sin(theta);
float cos = (float) Math.cos(theta);

float[] a = new float[9];
a[Matrix.MSCALE_X] = cos;
a[Matrix.MSKEW_X] = sin;
a[Matrix.MTRANS_X] = vcx-gcx*cos-gcy*sin;
a[Matrix.MSCALE_Y] = cos;
a[Matrix.MSKEW_Y] = -sin;
a[Matrix.MTRANS_Y] = vcy-gcy*cos+gcx*sin;
a[Matrix.MPERSP_0] = 0.0f;
a[Matrix.MPERSP_1] = 0.0f;
a[Matrix.MPERSP_2] = 1.0f;

Matrix m = new Matrix();
m.setValues(a);
view.setImageMatrix(m); // or setMatrix or whatever you're using.

#4


0  

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);

}

#1


8  

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.

然后在矩阵中使用pre和post translate方法来改变旋转点,这与android样本的旋转点相似。

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.

如果有人有更好的方法或看到问题,请留下评论。

#2


3  

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);
}

#3


1  

I like to do things the difficult way and "roll my own". Moreover, if you are doing animations cumulative errors can creep in concat'ing Matrix's.

我喜欢做一些困难的事情,“滚我自己的”。而且,如果你在做动画,累积误差可能会在concat'ing Matrix中出现。

float rotate; // rotation in degrees

float vcx; // center of rotation of view
float vcy;

float gcx; // center of rotation of graphic
float gcy;

float theta = (float) (Math.PI/180.0*rotate);
float sin = (float) Math.sin(theta);
float cos = (float) Math.cos(theta);

float[] a = new float[9];
a[Matrix.MSCALE_X] = cos;
a[Matrix.MSKEW_X] = sin;
a[Matrix.MTRANS_X] = vcx-gcx*cos-gcy*sin;
a[Matrix.MSCALE_Y] = cos;
a[Matrix.MSKEW_Y] = -sin;
a[Matrix.MTRANS_Y] = vcy-gcy*cos+gcx*sin;
a[Matrix.MPERSP_0] = 0.0f;
a[Matrix.MPERSP_1] = 0.0f;
a[Matrix.MPERSP_2] = 1.0f;

Matrix m = new Matrix();
m.setValues(a);
view.setImageMatrix(m); // or setMatrix or whatever you're using.

#4


0  

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);

}