Получить новые координаты x, y точки во вращающемся изображении

У меня есть значки Google Maps, которые мне нужно вращать под определенным углом, прежде чем рисовать на карте, используя MarkerImage. Я выполняю поворот на лету в Python, используя PIL, и получившееся изображение имеет тот же размер, что и оригинал - 32x32. Например, со следующим по умолчанию Google Maps: icon before rotation , вращение на 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)