获取旋转图像中点的新x,y坐标
我有一些谷歌地图的图标,想在绘制到地图上之前,先把它们旋转一定的角度。我是在Python中用PIL库实时进行旋转的,旋转后的图片和原来的大小一样,都是32x32。例如,下面这个默认的谷歌地图标记:

我用以下的Python代码实现了逆时针旋转30度:
# full_src is a variable holding the full path to image
# rotated is a variable holding the full path to where the rotated image is saved
image = Image.open(full_src)
png_info = image.info
image = image.copy()
image = image.rotate(30, resample=Image.BICUBIC)
image.save(rotated, **png_info)
旋转后的图片是
这里有个难点,就是在用新的旋转图像创建MarkerImage时,如何设置新的锚点。这个锚点需要是图标的尖端。默认情况下,锚点是在图标的底部中间位置,坐标是(16,32),其中(0,0)是左上角。有人能告诉我在JavaScript中怎么简单实现这一点吗?
谢谢。
更新 2011年6月22日: 之前发错了旋转后的图片(原来的图是逆时针旋转330度的)。我已经修正了。此外,还添加了重采样(Image.BICUBIC),让旋转后的图标更清晰。
3 个回答
在一张图片中,向下是正Y方向,向右是正X方向。不过,为了使用旋转公式,我们需要把向上作为正Y方向。因此,第一步是应用这个公式:f(x,y) = f(x,h-y)
,其中'h'是图片的高度。
假设图片是围绕某个点x0,y0旋转的。接下来,你需要把坐标原点移动到这个点。因此,第二步是f(x,y) = f(x-x0,y-y0)
。经过这两步后,你的新坐标会变成x-x0
和h-y-y0
。现在你就可以使用旋转公式了。
x1 = x*cos(theta) - y*sin(theta)
y1 = xsin(theta) + ycos(theta)
使用第二步得到的x和y的值。你会得到:
x1 = (x-x0)*cos(theta) - (h-y-y0)*sin(theta)
y1 = (x-x0)*sin(theta) + (h-y-y0)*cos(theta)
现在,按照顺序撤销第二步和第一步的变换。
撤销第二步后:xNew = x1 + x0
和 yNew = y1 + y0
撤销第一步后:xNew = x1 + x0
和 yNew = h - (y1 + y0)
这样你就得到了:
xNew = (x-x0)*cos(theta) - (h-y-y0)*sin(theta) + x0
yNew = -(x-x0)*sin(theta) - (h-y-y0)*cos(theta) + (h-y0)
关于坐标原点(0,0)的旋转公式是:
x1 = cos(theta) x0 - sin(theta) y0
y1 = sin(theta) x0 + cos(theta) y0
不过这个公式是针对普通坐标轴和围绕(0,0)旋转的情况。而PIL(Python Imaging Library)中的旋转是顺时针的,使用的是“图形”坐标轴。而且,旋转是围绕图像的中心进行的。最后一个让人困惑的地方是,图像的大小可能会变化,这一点在最终结果中需要考虑到。
操作步骤是:先取原始点,减去图像的中心点,应用“图形坐标轴”修正后的旋转,找出新图像的大小,然后再把新图像的中心位置加回来。
使用图形坐标轴的旋转公式是:
x1 = cos(theta) x0 + sin(theta) y0
y1 = -sin(theta) x0 + cos(theta) y0
比如,点(16,32)减去中心点(16,16)得到(0,16)。顺时针旋转30度(根据你的图像)会得到一个新点,计算方式是:cos(-30)*0 + sin(-30)*16, -sin(-30)*0 + cos(-30)*16 = -8, 13.86。最后一步是把旋转后的位置的中心点加回来。
要计算一个旋转后的点的位置,你可以使用一种叫做旋转矩阵的东西。
下面是用JavaScript写的代码,可以用来计算旋转后的点:
function rotate(x, y, xm, ym, a) {
var cos = Math.cos,
sin = Math.sin,
a = a * Math.PI / 180, // Convert to radians because that is what
// JavaScript likes
// Subtract midpoints, so that midpoint is translated to origin
// and add it in the end again
xr = (x - xm) * cos(a) - (y - ym) * sin(a) + xm,
yr = (x - xm) * sin(a) + (y - ym) * cos(a) + ym;
return [xr, yr];
}
rotate(16, 32, 16, 16, 30); // [8, 29.856...]