Получить новые координаты x, y точки на повернутом изображении - PullRequest
11 голосов
/ 21 июня 2011

У меня есть значки Google Maps, которые мне нужно повернуть на определенные углы, прежде чем рисовать на карте, используя MarkerImage . Я делаю вращение на лету в Python, используя PIL, и получающееся изображение имеет тот же размер, что и оригинал - 32x32. Например, со следующим маркером Google Maps по умолчанию: icon before rotation вращение на 30 градусов против часовой стрелки достигается с помощью следующего кода Python:

# 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), которая делает вращаемый значок более четким.

Ответы [ 3 ]

19 голосов
/ 21 июня 2011

Для вычисления положения повернутой точки вы можете использовать матрицу вращения .

При преобразовании в 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...]
6 голосов
/ 21 июня 2011

Формула для вращений около 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. Последний шаг - добавление назад центральной позиции повернутой позиции.

0 голосов
/ 16 марта 2016

На изображении вниз положительный 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)
...