2011-06-21 6 views
11

Mam ikony w Mapach Google, które muszę obracać pod pewnymi kątami przed rysowaniem mapy za pomocą MarkerImage. Robię rotację "w locie" w Pythonie przy użyciu PIL, a wynikowy obraz ma ten sam rozmiar co oryginał - 32x32. Na przykład, dla następującego domyślnego Google mapy markerów: icon before rotation , 30 ° conter do ruchu wskazówek zegara obrót uzyskuje się z zastosowaniem kodu pytona:Uzyskaj nowe współrzędne x, y punktu na obróconym obrazku

# 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) 

obraz wynikowy icon rotated 30 degrees counter-clockwise

Trudne bit jest uzyskanie nowego punktu kontrolnego do użycia podczas tworzenia MarkerImage za pomocą nowego obróconego obrazu. To musi być spiczasty koniec ikony. Domyślnie punktem kontrolnym jest dolny środek [zdefiniowany jako (16,32) we współrzędnych x, y gdzie (0,0) jest lewym górnym rogiem]. Czy ktoś może mi wyjaśnić, jak mogę to łatwo zrobić w JavaScript?

Dzięki.

Aktualizacja 22 Cze 2011: Opublikował zły obrócony obraz (oryginalny był dla 330 stopni przeciwnie do ruchu wskazówek zegara). Poprawiłem to. Dodano również resampling (Image.BICUBIC), który sprawia, że ​​obrócona ikona jest wyraźniejsza.

+0

@Trufa: Dzięki za radę. –

Odpowiedz

20

Aby obliczyć pozycję obróconego punktu, można użyć rotation matrix.

Przekształcony JavaScript tego oblicza punkt obracany:

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...] 
+0

Dzięki. Dokładnie tego potrzebowałem. –

+0

@Simon Kagwi: Dzięki za poprawienie, nie jestem pewien co się tam stało ... – pimvdb

6

Wzór na obroty około 0,0 to:

x1 = cos(theta) x0 - sin(theta) y0 
y1 = sin(theta) x0 + cos(theta) y0 

Ale to dla stałych osiach, a obrót o 0,0. Obrót PIL jest zgodny z ruchem wskazówek zegara z osiami "grafiki". Dodatkowo znajduje się wokół środka obrazu. Ostatnim mylącym problemem jest to, że rozmiar obrazu może się zmienić, co należy uwzględnić w ostatecznym wyniku.

Procedura: weź oryginalny punkt, odejmij od środka obrazu, zastosuj skorygowaną rotację "osi graficznych", znajdź nowy rozmiar obrazu, dodaj środkową pozycję nowego obrazu.

Rotacja przy użyciu grafiki osiami wynosi:

x1 = cos(theta) x0 + sin(theta) y0 
y1 = -sin(theta) x0 + cos(theta) y0 

16,32 - 16,16 0, 16. Obrót o 30 stopni w prawo, obrót (na podstawie zdjęć) daje COS (-30 punktów) * 0 + sin (-30) * 16, -sin (-30) * 0 + cos (-30) * 16 = -8, 13,86. Ostatnim krokiem jest przywrócenie pozycji środkowej obróconej pozycji.

+0

Czy możesz wyjaśnić różnicę między osią "zwykłą" i "graficzną"? Główną różnicą wydaje się być, która współrzędna ma odejmowanie, ale nie rozumiem dlaczego. – Michael

0

w obrazie, w dół jest dodatni Y i w prawo jest dodatnia X jednak zastosować rotation formula, musimy w górę jako pozytywne Y. Zatem , krok 1 to zastosowanie f(x,y) = f(x,h-y), gdzie "h" jest wysokością obrazu. Powiedzmy, że obraz jest obrócony względem x0, y0. Następnie musisz przekształcić swoje pochodzenie do tego momentu. Dlatego też krok 2 będzie f(x,y) = f(x-x0,y-y0). Na tym etapie (to znaczy po dwóch etapach), twoje nowe współrzędne będą wynosić x-x0, h-y-y0. Możesz teraz zastosować formułę obrotu:

x1 = x*cos(theta) - y*sin(theta) 

y1 = xsin(theta) + ycos(theta) 

Użyj wartości x i y uzyskanych po kroku drugim. Można by dostać

x1 = (x-x0)*cos(theta) - (h-y-y0)*sin(theta) 

y1 = (x-x0)*sin(theta) + (h-y-y0)*cos(theta) 

Teraz cofnąć transformacje wykonywane w kroku 2 i etapu 1 (w tej kolejności).

po odkręceniu Krok 2: xNew = x1 + x0 i yNew = y1 + y0

po odkręceniu Krok 1: xNew = x1 + x0 i yNew = h - (y1 + y0)

To daje:

xNew = (x-x0)*cos(theta) - (h-y-y0)*sin(theta) + x0 

yNew = -(x-x0)*sin(theta) - (h-y-y0)*cos(theta) + (h-y0) 
Powiązane problemy