如何在放大时找到点击的绝对位置
请参阅下面的每个部分,以三种不同的方式描述我的问题。希望能帮助人们解答。
问题:当您只有以缩放图像表示的坐标时,如何找到在画布/用户空间中表示的一对坐标,给定原始缩放点和缩放点?比例因子?
实践中的问题:
我目前正在尝试复制图库/地图等应用程序中使用的缩放功能,此时您可以通过捏合来缩放/缩小,并且缩放会向捏合的中点移动。
向下保存缩放的中心点(基于当前屏幕的 X、Y 坐标)。然后,当检测到“缩放”手势时,我让此函数起作用:
class ImageScaleGestureDetector extends SimpleOnScaleGestureListener {
@Override
public boolean onScale(ScaleGestureDetector detector) {
if(mScaleAllowed)
mCustomImageView.scale(detector.getScaleFactor(), mCenterX, mCenterY);
return true;
}
}
CustomImageView 的缩放函数如下所示:
public boolean scale(float scaleFactor, float focusX, float focusY) {
mScaleFactor *= scaleFactor;
// Don't let the object get too small or too large.
mScaleFactor = Math.max(MINIMUM_SCALE_VALUE, Math.min(mScaleFactor, 5.0f));
mCenterScaleX = focusX;
mCenterScaleY = focusY;
invalidate();
return true;
}
缩放图像的绘制是通过重写 onDraw 方法来实现的,该方法将围绕中心缩放画布并将图像绘制为它。
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.save();
canvas.translate(mCenterScaleX, mCenterScaleY);
canvas.scale(mScaleFactor, mScaleFactor);
canvas.translate(-mCenterScaleX, -mCenterScaleY);
mIcon.draw(canvas);
canvas.restore();
}
当从 ScaleFactor 1 缩放时,这一切都工作正常,这是因为初始 mCenterX 和 mCenterY 是基于设备屏幕的坐标。设备上的 10, 10 就是画布上的 10, 10。
然而,在您已经缩放之后,下次您单击位置 10, 10 时,由于缩放和缩放,它将不再对应于画布中的 10, 10。已经执行的转换。
抽象问题:
下图是围绕中心点 A 进行缩放操作的示例。每个框代表视图在该比例因子(1、2、3、4、 5)。
在示例中,如果您围绕 A 缩放 2 倍,然后单击位置 B,则会报告 X、Y因为 B 将基于屏幕位置 - 而不是相对于初始画布 0,0 的位置。
我需要找到一种方法来获取 B 的绝对位置。
Please see each section below for a description of my problem described in three separate ways. Hopefully should help people to answer.
Problem: How do you find a pair of coordinate expressed in canvas/userspace when you only have the coordinate expressed in terms of a zoomed image, given the original scale point & scale factor?
Problem in practice:
I'm currently trying to replicate the zoom functionality used in apps such as the gallery / maps, when you can pinch to zoom/zoom out with the zoom moving towards the midpoint of the pinch.
On down I save the centre point of the zoom (which is in X,Y coordinates based on the current screen). I then have this function act when a "scale" gesture is detected:
class ImageScaleGestureDetector extends SimpleOnScaleGestureListener {
@Override
public boolean onScale(ScaleGestureDetector detector) {
if(mScaleAllowed)
mCustomImageView.scale(detector.getScaleFactor(), mCenterX, mCenterY);
return true;
}
}
The scale function of the CustomImageView look like this:
public boolean scale(float scaleFactor, float focusX, float focusY) {
mScaleFactor *= scaleFactor;
// Don't let the object get too small or too large.
mScaleFactor = Math.max(MINIMUM_SCALE_VALUE, Math.min(mScaleFactor, 5.0f));
mCenterScaleX = focusX;
mCenterScaleY = focusY;
invalidate();
return true;
}
The drawing of the scaled image is achieved by overriding the onDraw method which scales the canvas around the centre ands draw's the image to it.
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.save();
canvas.translate(mCenterScaleX, mCenterScaleY);
canvas.scale(mScaleFactor, mScaleFactor);
canvas.translate(-mCenterScaleX, -mCenterScaleY);
mIcon.draw(canvas);
canvas.restore();
}
This all works fine when scaling from ScaleFactor 1, this is because the initial mCenterX and mCenterY are coordinates which are based on the device screen. 10, 10 on the device is 10, 10 on the canvas.
After you have already zoomed however, then next time you click position 10, 10 it will no longer correspond to 10, 10 in the canvas because of the scaling & transforming that has already been performed.
Problem in abstraction:
The image below is an example of a zoom operation around centre point A. Each box represents the position and size of the view when at that scale factor (1, 2, 3, 4, 5).
In the example if you scaled by a factor of 2 around A then you clicked on position B, the X, Y reported as B would be based on the screen position - not on the position relative to 0,0 of the initial canvas.
I need to find a way of getting the absolute position of B.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
因此,在重新绘制问题后,我找到了我正在寻找的解决方案。它经历了几次迭代,但我是这样解决的:
您知道
Bx
和By
的值,因为无论比例因子是多少,它们总是恒定的(您知道画布空间和用户空间中的该值)。你知道
Axe
&用户空间中的Ay
,以便您可以找到Ax
到Bx
以及Ay
到By 之间的距离
。该测量是在用户空间中进行的,要将其转换为画布空间测量,只需将其除以比例因子即可。 (一旦转换为画布空间,您可以看到这些线条为红色、橙色和黄色)。由于点 B 是恒定的,因此它与边缘之间的距离也是恒定的(这些由蓝线表示)。该值在用户空间和画布空间中相等。
您知道画布空间中画布的宽度,因此通过减去这两个画布空间测量值(
Ax
到Bx
和Bx
到Edge
)从总宽度中留下画布空间中 A 点的坐标:上面的代码和图像描述了当您单击原始中心的左上角时。我使用相同的逻辑找到 A,无论它位于哪个象限,并重构为以下内容:
So, after redrawing the problem I've found the solution I was looking for. It's gone through a few iteration's but here's how I worked it out:
You know the values for
Bx
andBy
because they are always constant no matter what the scale factor (You know this value in both canvas-space and in user-space).You know
Ax
&Ay
in user-space so you can find the distance betweenAx
toBx
andAy
toBy
. This measurement is in user-space, to convert it to a canvas-space measurement simply divide it by the scale factor. (Once converted to canvas-space, you can see these lines in red, orange and yellow).As point
B
is constant, the distance between it and the edges are constant (These are represented by Blue Lines). This value is equal in user-space and canvas-space.You know the width of the Canvas in canvas-space so by subtracting these two canvas space measurements (
Ax
toBx
andBx
toEdge
) from the total width you are left with the coordinates for point A in canvas-space:The above code and image describe when you're clicking to the top left of the original centre. I used the same logic to find A no matter which quadrant it was located in and refactored to the following:
这是我基于 Graeme 的答案的解决方案:
参数 Ax 和 Ay 是用户通过 onTouch() 触摸的点,我在 MatrixContext 类中拥有静态矩阵实例来保存以前的缩放/转换值。
Here is my solution based on Graeme's answer:
the parameters Ax and Ay are the points which user touch via onTouch(), I owned my static matrix instance in MatrixContext class to hold the previous scaled/translated values.
真的很抱歉,这是一个简短的回答,仓促。但我最近也一直在关注这个 - 我发现 http://code.google .com/p/android-multitouch-controller/ 来做你想做的事(我想 - 我不得不浏览你的帖子)。希望这有帮助。如果这没有帮助,我今晚会好好看看,看看是否可以提供进一步的帮助。
Really sorry this is a brief answer, in a rush. But I've been looking at this recently too - I found http://code.google.com/p/android-multitouch-controller/ to do what you want (I think - I had to skim read your post). Hope this helps. I'll have a proper look tonight if this doesn't help and see if I can help further.