Taisin viimeksi sanoakin, etten ole koskaan koettanut tehdä mitään kovin graafista, jollei opiskeluaikojen nelikulmioita tai palloja ruudulle oksentelevaa TurboC++ -tekelettä lasketa mukaan (ei, ei sitä lasketa). Ykkösongelmani iski siis silmille jo tässä vaiheessa. Nelikärkisen polygonini piirtäminen keskelle piirtoaluetta oli simppeliä, mutta sen siirtely...
Mutisen tässä omista oivallusaskeleistani kutakuinkin niin kuin niitä muistan ja missä on olevinaan edes jonkunlaista tolkkua. Laatua en takaa, kuten en yleensäkään ;)
Sijainti, kierto, siirto, piirto
Ensimmäinen yritykseni oli siis kovakoodattuja koordinaattipisteitä käyttävä roipe. Kuvittelin, että siitä olisi hyvä lähteä mutta voi voi, miten väärässä olinkaan. Ehkä vika oli omissa ensimmäisissä kiertometodeissani ja toimivilla olisi toiminutkin, mutta ehkä ei. Alkutilanne piirtyi ruudulle kauniisti, mutta yksikin kiertoliike hajoitti koko muodon ihan miten sattuu.
Nollapisteen kautta
Keksin jostain (ja työkaverin kanssa puhuttuani oletukseni osoittautui oikeanlaiseksi), että jospa kaikkien piirrettävien kuvioiden kulmapisteet asetettaisiin aina (0,0):n suhteen. Tällöin polygonin kierto toimisi aina samalla tavalla, kun ei tarvitsisi arpoa sijainnin kanssa pätkääkään. Ensin siis napataan polygonille kulmat aina samaan paikkaan, sitten niiden arvot siirretään kohdalleen, tässä tapauksessa keskelle piirtoaluetta ja piirretään näkyviin. Yksinkertaista ja varmaan lapsellisen alkeellistakin, mutta kukas tuon olisi minulle käynyt kertomassa?
Kaksiulotteisen koordinaatiston kierto
Minun matemattiset opintoni ovat vuosien takana ja olin ehdottomasti niitä rasittavia kakaroita jo peruskoulussa, jotka julistivat, etteivät ikinä tarvitse matematiikkaa, saati sitten trigonometriaa koulun jälkeen. Näin se taas nähtiin, ettei se ihan noin mene :)
Muutaman omituisen ja hölmön "
teen itse"-henkisen yrityksen jälkeen törmäsin
affiiniin kuvaukseen ja sehän olikin näppärä ja toteutus kutakuinkin suoraan kirjoitettava. Sille nakataan kunkin piirrettävän polygonin jokaisen kulman koordinaatit vuorollaan ja haluttu kiertokulma (luonnollisesti se on kaikille sama), paluuarvona saadaan uudet koordinaatit.
def rotate(self, angle):
rotated_points = []
for point in self._points:
new_point = self.affine_transform(Vector(point.x, point.y), angle)
rotated_points.append(new_point)
return rotated_points
def affine_transform(self, point, angle):
temp_x = ((point.x * math.cos(angle)) + (point.y * math.sin(angle)))
temp_y = ((-point.x * math.sin(angle)) + (point.y * math.cos(angle)))
return Vector(temp_x, temp_y )
Hah! Seuraavat kannot kaskessani olivatkin tuo kulma (kohelsin asteiden ja radiaanien kanssa, omaa pohjatonta tyhmyyttäni siis). Suurin ja melkoista päänvaivaa aiheuttanut ongelma oli siis polygonini liikuttelu piirtopinnalla. Kääntely toimi, mutta kun koetin saada sitä liikkumaan kolmion kärjen suuntaan, se lähti liitämään kiinteästi toiseen yläkulmaan ja sen ohi. Jos yritin kääntää liikkuvaa kolmiota, se liikkui edelleen oikeaa yläkulmaa kohti, mutta kuin syöksykierteessä... gnaah.
Miten lasken, mihin suuntaan polygonini katsoo?
Typeränä virheenä numero 74 olin unohtanut paikalleen kovakoodatut "piirrä tuo keskelle kuvaruutua"-arvot ja toisena jäätyneenä käpynä oli aina sama kulma. Olin jostain saanut aikaan kuvion kiertokulman (eli mihin sen "nokka" osoittaa) laskentaan toteutuksen, joka oli vähän väärä. Laskin nimittäin jotain eri kylkien pituuksien ja niiden välisten kulmien perusteella - muuten kai ihan hienoa toimintaa, muttei se tässä auttanut.
Pienen googlettelun ja kevyen pään pöytään hakkaamisen perusteella ratkaisu olikin helpompi kuin mitä sopisi olettaa. Tai ainakin näin tyhmälle. Kun tiedetään kärkipisteen koordinaatit ja keskipisteen koordinaatit, voidaan niiden x- ja y-suuntaisten välimatkojen (Δx, Δy) perusteella laskea arctanilla koko roskan kulma radiaaneina.
 |
Kai se jotain selventää, vaikka vähän epäilenkin :p |
def calculate_angle(self, center, nose):
dx = center.x - nose.x
dy = center.y - nose.y
radian_angle = math.atan2(dy, dx)
return radian_angle
Nerokkaan yksinkertaista, sanon minä. Tähän väliin näyttää tosin siltä, että
kukaan ei jaksa lukea tästä enää enempää yhdellä istumalla, joten jatkan taas seuraavalla rundilla.