Получить новые координаты x, y точки во вращающемся изображении
У меня есть значки Google Maps, которые мне нужно вращать под определенным углом, прежде чем рисовать на карте, используя MarkerImage. Я выполняю поворот на лету в Python, используя PIL, и получившееся изображение имеет тот же размер, что и оригинал - 32x32. Например, со следующим по умолчанию Google Maps:
, вращение на 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)
Полученное изображение ![icon rotated 30 degrees counter-clockwise]()
Сложный бит использует новую опорную точку при создании MarkerImage с использованием нового повернутого изображения. Это должен быть заостренный конец значка. По умолчанию опорная точка представляет собой нижнюю середину [определяемую как (16,32) в координатах x, y, где (0,0) - верхний левый угол]. Может кто-нибудь, пожалуйста, объясните мне, как я могу легко обойти это в JavaScript?
Спасибо.
Обновление 22 июня 2011 года:
Прислал неправильное повернутое изображение (оригинальное было для 330 градусов против часовой стрелки). Я исправил это. Также добавлена передискретизация (Image.BICUBIC), которая делает изображение более четким.
Ответы
Ответ 1
Чтобы вычислить положение повернутой точки, вы можете использовать матрицу поворота .
Преобразованный в 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...]
Ответ 2
Формула для оборотов около 0,0:
x1 = cos(theta) x0 - sin(theta) y0
y1 = sin(theta) x0 + cos(theta) y0
Но это для обычных осей и вращения около 0,0. Вращение PIL по часовой стрелке с "графическими" осями. Кроме того, он находится вокруг центра изображения. Конечная запутанная вещь заключается в том, что размер изображения может измениться, что необходимо учитывать в конечном результате.
Процедура: взять исходную точку, вычесть из центра изображения, применить "графические оси" скорректированное вращение, найти новый размер изображения, добавить заднее центральное положение нового изображения.
Вращение с использованием графических осей:
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. Последним шагом является добавление заднего положения по часовой стрелке.
Ответ 3
В изображении вниз положительный Y, а вправо положительный X. Однако, чтобы применить формулу вращения , нам нужно увеличить как положительный Y Поэтому шаг 1 будет применять f(x,y) = f(x,h-y)
, где 'h' - высота изображения.
Пусть говорят, что изображение повернуто относительно x0, y0. Тогда вам нужно будет преобразовать свое происхождение к этому моменту. Следовательно, шаг 2 будет 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)
Теперь отмените преобразования, сделанные на шаге 2 и на шаге 1 (в указанном порядке).
После отмены шага2: xNew = x1 + x0
и yNew = y1 + y0
После отмены шага 1: 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)