Canvas 如何确定它的剪辑范围?
How does Canvas determine its clip bounds?
我一直在做一些关于 Android 的 Canvas
的工作,特别是试图确定它的 getClipBounds
结果是如何确定的。我知道 Canvas
内部保留了一个转换 Matrix
,它在我调用 translate
、scale
等时更新,但试图复制 Matrix
的结果有把我弄糊涂了。
@Override
public void onDraw(Canvas canvas) {
Rect clipBounds;
RectF viewport;
canvas.save();
canvas.concat(translationMatrix);
//viewportMatrix.preConcat(canvas.getMatrix());
viewportMatrix.set(canvas.getMatrix());
clipBounds = canvas.getClipBounds();
viewport = GetViewport();
Log.d("clipBounds", clipBounds.toString() + " (" + clipBounds.width() + ", " + clipBounds.height() + ")");
Log.d("viewport", viewport.toString() + " (" + viewport.width() + ", " + viewport.height() + ")");
//drawing is done here
canvas.restore();
}
//viewport code modeled after
private RectF GetViewport() {
RectF viewport = new RectF();
viewportMatrix.mapRect(viewport, originalViewport);
return viewport;
}
private void Translate(float x, float y) {
translationMatrix.postTranslate(x, y);
invalidate();
}
private void Scale(float scaleFactor, PointF focusPoint) {
if (focusPoint == null) {
translationMatrix.postScale(scaleFactor, scaleFactor);
}
//keep the focus point in focus if possible
else {
translationMatrix.postScale(scaleFactor, scaleFactor, focusPoint.x, focusPoint.y);
}
invalidate();
}
private final Matrix translationMatrix = new Matrix();
private final RectF originalViewport = new RectF();
private final Matrix viewportMatrix = new Matrix();
originalViewport
设置为 0, 0, canvas.getWidth(), canvas.getHeight()
。 Translate
和 Scale
是从正确工作的手势事件处理程序调用的。
让我困惑的部分是viewportMatrix
。做不做好像都无所谓
viewportMatrix.set(canvas.getMatrix());
或
viewportMatrix.preConcat(canvas.getMatrix());
甚至一次性调用
viewportMatrix.set(canvas.getMatrix());
开始,然后并排 Translate
/Scale
调用两个矩阵。我什至尝试完全忽略 Canvas
的内置 Matrix
并将 GetViewport
重写为
//viewport code modeled after
private RectF GetViewport() {
RectF viewport = new RectF();
translationMatrix.mapRect(viewport, originalViewport);
return viewport;
}
我似乎永远无法匹配getClipBounds()
,而且差异相当严重:
与 viewportMatrix.set(canvas.getMatrix)
:
clipBounds: Rect(-97, -97 - 602, 452) (699, 549)
viewport: RectF(97.04178, 97.06036, 797.04175, 647.06036) (700.0, 550.0)
和viewportMatrix.preConcat(canvas.getMatrix)
:
clipBounds: Rect(-97, -96 - 602, 453) (699, 549)
viewport: RectF(2708.9663, 2722.2754, 3408.9663, 3272.2754) (700.0, 550.0)
和translationMatrix.mapRect
:
clipBounds: Rect(-96, -96 - 603, 453) (699, 549)
viewport: RectF(96.73213, 96.85794, 796.7321, 646.8579) (700.0, 550.0)
一次性调用 viewportMatrix.preConcat(canvas.getMatrix())
,然后并排 Translate
/Scale
调用:
clipBounds: Rect(-96, -97 - 603, 452) (699, 549)
viewport: RectF(96.57738, 97.78168, 796.5774, 647.7817) (700.0, 550.0)
一次性调用 viewportMatrix.set(canvas.getMatrix())
,然后并排 Translate
/Scale
调用:
clipBounds: Rect(-96, -96 - 603, 453) (699, 549)
viewport: RectF(96.40051, 96.88153, 796.4005, 646.88153) (700.0, 550.0)
我什至无法检查 the Canvas
source,因为所有 Matrix
代码都消失在未显示代码的私有本机调用中。
为什么我的 GetViewport
通话如此严重,getClipBounds
的幕后情况如何?
我通读了 this answer on GameDev SE,它使用矩阵求逆在屏幕和世界坐标系之间交换:
To go from screen to world space simply use Vector2.Transform. This is commonly used to get the location of the mouse in the world for object picking.
Vector2.Transform(mouseLocation, Matrix.Invert(Camera.TransformMatrix));
To go from world to screen space simply do the opposite.
Vector2.Transform(mouseLocation, Camera.TransformMatrix);
受这种方法的启发,我尝试像这样反转变换矩阵:
private RectF GetViewport() {
RectF viewport = new RectF();
Matrix viewportMatrix = new Matrix();
translationMatrix.invert(viewportMatrix);
viewportMatrix.mapRect(viewport, originalViewport);
return viewport;
}
此视口与 getClipBounds
返回的结果正确匹配。
This matrix tutorial 解释了我从 transform
调用的结果中注意到的,但没有应用于我的矩阵的内容:
In a computer program the camera doesn’t move at all and in actuality, the world is just moving in the opposite direction and orientation of how you would want the camera to move in reality.
In order to understand this correctly, we must think in terms of two different things:
- The Camera Transformation Matrix: The transformation that places the camera in the correct position and orientation in world space (this is the transformation that you would apply to a 3D model of the camera if you wanted to represent it in the scene).
- The View Matrix: This matrix will transform vertices from world-space to view-space. This matrix is the inverse of the camera’s transformation matrix described above.
我一直在做一些关于 Android 的 Canvas
的工作,特别是试图确定它的 getClipBounds
结果是如何确定的。我知道 Canvas
内部保留了一个转换 Matrix
,它在我调用 translate
、scale
等时更新,但试图复制 Matrix
的结果有把我弄糊涂了。
@Override
public void onDraw(Canvas canvas) {
Rect clipBounds;
RectF viewport;
canvas.save();
canvas.concat(translationMatrix);
//viewportMatrix.preConcat(canvas.getMatrix());
viewportMatrix.set(canvas.getMatrix());
clipBounds = canvas.getClipBounds();
viewport = GetViewport();
Log.d("clipBounds", clipBounds.toString() + " (" + clipBounds.width() + ", " + clipBounds.height() + ")");
Log.d("viewport", viewport.toString() + " (" + viewport.width() + ", " + viewport.height() + ")");
//drawing is done here
canvas.restore();
}
//viewport code modeled after
private RectF GetViewport() {
RectF viewport = new RectF();
viewportMatrix.mapRect(viewport, originalViewport);
return viewport;
}
private void Translate(float x, float y) {
translationMatrix.postTranslate(x, y);
invalidate();
}
private void Scale(float scaleFactor, PointF focusPoint) {
if (focusPoint == null) {
translationMatrix.postScale(scaleFactor, scaleFactor);
}
//keep the focus point in focus if possible
else {
translationMatrix.postScale(scaleFactor, scaleFactor, focusPoint.x, focusPoint.y);
}
invalidate();
}
private final Matrix translationMatrix = new Matrix();
private final RectF originalViewport = new RectF();
private final Matrix viewportMatrix = new Matrix();
originalViewport
设置为 0, 0, canvas.getWidth(), canvas.getHeight()
。 Translate
和 Scale
是从正确工作的手势事件处理程序调用的。
让我困惑的部分是viewportMatrix
。做不做好像都无所谓
viewportMatrix.set(canvas.getMatrix());
或
viewportMatrix.preConcat(canvas.getMatrix());
甚至一次性调用
viewportMatrix.set(canvas.getMatrix());
开始,然后并排 Translate
/Scale
调用两个矩阵。我什至尝试完全忽略 Canvas
的内置 Matrix
并将 GetViewport
重写为
//viewport code modeled after
private RectF GetViewport() {
RectF viewport = new RectF();
translationMatrix.mapRect(viewport, originalViewport);
return viewport;
}
我似乎永远无法匹配getClipBounds()
,而且差异相当严重:
与 viewportMatrix.set(canvas.getMatrix)
:
clipBounds: Rect(-97, -97 - 602, 452) (699, 549)
viewport: RectF(97.04178, 97.06036, 797.04175, 647.06036) (700.0, 550.0)
和viewportMatrix.preConcat(canvas.getMatrix)
:
clipBounds: Rect(-97, -96 - 602, 453) (699, 549)
viewport: RectF(2708.9663, 2722.2754, 3408.9663, 3272.2754) (700.0, 550.0)
和translationMatrix.mapRect
:
clipBounds: Rect(-96, -96 - 603, 453) (699, 549)
viewport: RectF(96.73213, 96.85794, 796.7321, 646.8579) (700.0, 550.0)
一次性调用 viewportMatrix.preConcat(canvas.getMatrix())
,然后并排 Translate
/Scale
调用:
clipBounds: Rect(-96, -97 - 603, 452) (699, 549)
viewport: RectF(96.57738, 97.78168, 796.5774, 647.7817) (700.0, 550.0)
一次性调用 viewportMatrix.set(canvas.getMatrix())
,然后并排 Translate
/Scale
调用:
clipBounds: Rect(-96, -96 - 603, 453) (699, 549)
viewport: RectF(96.40051, 96.88153, 796.4005, 646.88153) (700.0, 550.0)
我什至无法检查 the Canvas
source,因为所有 Matrix
代码都消失在未显示代码的私有本机调用中。
为什么我的 GetViewport
通话如此严重,getClipBounds
的幕后情况如何?
我通读了 this answer on GameDev SE,它使用矩阵求逆在屏幕和世界坐标系之间交换:
To go from screen to world space simply use Vector2.Transform. This is commonly used to get the location of the mouse in the world for object picking.
Vector2.Transform(mouseLocation, Matrix.Invert(Camera.TransformMatrix));
To go from world to screen space simply do the opposite.
Vector2.Transform(mouseLocation, Camera.TransformMatrix);
受这种方法的启发,我尝试像这样反转变换矩阵:
private RectF GetViewport() {
RectF viewport = new RectF();
Matrix viewportMatrix = new Matrix();
translationMatrix.invert(viewportMatrix);
viewportMatrix.mapRect(viewport, originalViewport);
return viewport;
}
此视口与 getClipBounds
返回的结果正确匹配。
This matrix tutorial 解释了我从 transform
调用的结果中注意到的,但没有应用于我的矩阵的内容:
In a computer program the camera doesn’t move at all and in actuality, the world is just moving in the opposite direction and orientation of how you would want the camera to move in reality.
In order to understand this correctly, we must think in terms of two different things:
- The Camera Transformation Matrix: The transformation that places the camera in the correct position and orientation in world space (this is the transformation that you would apply to a 3D model of the camera if you wanted to represent it in the scene).
- The View Matrix: This matrix will transform vertices from world-space to view-space. This matrix is the inverse of the camera’s transformation matrix described above.