Ricksmuseum

Van ellipse naar rechthoek in tien regels!

Category: Multimedia, Processing, Globe4D, Science, School, Tech, Projects, General — Rick Companje — 21 October 2005 @ 03:00

Daar is tie weer met een stukje vroege-ochtend-code…

Stel: We (Danica, Hanco, Nico en ik) hebben een plaatje van een wereldbol. Dat plaatje is getekend als een ellipse. In deze ellipse zie je alle continenten van de aarde zonder dat je er een bol voor nodig hebt. Maar… wij willen juist een een plaatje van de aarde die wel op een bol te leggen is, oftewel een texture. (Een texture is een plaatje die door een 3D pakket of zelfs door je videokaart over (in ons geval) een bol heen gelegd kan worden.)
Natuurlijk zijn er van de aarde honderden kant en klare textures te vinden op internet, vaak zelfs op hoge resolutie. Maar wij hebben net iets andere eisen… Daarover later meer.

Het komt er op neer dat wij perse dat ene plaatje willen gebruiken als texture… Dus moet er gerekend worden. Hoe transformeer je een plaatje in de vorm van een ellipse naar eentje die rechthoekig is.

Het eerste probleem waar je tegenaan loopt is dat er in een rechthoek meer pixels zitten dan in een ellipse… Dat betekent dus dat je plaatje er in kwaliteit op achteruit zal gaan….

Maar stel dat je het dan nog steeds erg graag wil… Dan ga je als volgt te werk.

Je weet hoe je een ellipse tekent:

for (float i=0; i<TWO_PI ; i+=.1) {
   x = centerX + radiusX * sin(i);
   y = centerY + radiusY * cos(i);
   point(x,y)
}

Daar maken we gebruik van, maar nu gaan we niet van 0 naar 2PI maar gaan we de ellipse over de y-as scannen.


for (float y=-radiusY; y<radiusY ; y+=1) {
   x = radiusX * sin(acos(y/radiusY));
   point(centerX-x,y);

De y loopt automatisch op, de x berekenen we met een sinus/cosinus functie.
Dit is wat er precies gebeurt:

  1. We rekenen eerste de verhouding tussen y en de maximale y uit, oftewel y/radiusY. Dit is altijd een getal tussen -1 en 1
  2. Dat getal is precies het getal wat we nodig hebben om de inverse cosinus functie aan te roepen. Want we willen zoiets als een hoek hebben waar we dan vervolgens weer een sinus van willen gaan trekken.
  3. De uitkomst van die sinus is weer heel fijn een getal tussen -1 en 1. Heel fijn want die kunnen we dan mooi vermenigvuldigen met de radius. Bij 1 en -1 is de radius maximaal, ligt de uitkomst er tussenin dan krijg je altijd een deel van de radius terug.
  4. Voor iedere Y berekenen we maar een X dus zou je maar een halve ellipse krijgen. Stel dat je nou heel graag een hele ellipse wilt (niet nodig wat mij betreft) maar dan zet je gewoon twee points: eentje (centerX-x,y) en eentje op (centerX+x,y)

Maar goed… nu kun je nog maar een ellipse tekenen… Wat het eerstvolgende is wat je wilt weten is hoeveel pixels er per Y positie binnen je ellipse liggen. Dat is heel erg makkelijk te berekenen! Je weet je x positie. Je weet dus het aantal pixels tot het nulpunt, dat is je x positie. Doe je die keer twee dan weet je precies hoeveel pixels er op de X-as liggen voor die speciefieke Y.

Eigenlijk wil je niet perse weten hoeveel pixels het zijn maar wil je ze gewoon een voor een langs lopen. Niet zelf, een computer kan dat beter.

for (float x=-xOnEllipse; x<xOnEllipse ; x++)

De xOnEllipse is het puntje dat nog net op de rand van je ellipse zit, oftewel de outline of de stroke. Je loopt lekker van -xOnEllipse tot xOnEllipse en dan ben je voor die Y alle pixels binnen je ellipse langs geweest op de X-as.

Wat wij graag wilden is die ellipse precies over een plaatje heenleggen (eigenlijk stiekum een filmpje maar ik zeg nu maar even plaatje.) Wij wilden dus onze zelfgemaakte ellipse langslopen pixel voor pixel maar stiekum een kleurcode uitlezen uit het plaatje waar de ellipse precies overheen ligt. Dat deden we in Processing met het volgende commando:

img.get(int(centerX-x),int(centerY-y));

Maar dat is nou typisch iets wat per taal verschillend is, als het uberhaupt al kan in alle talen (Flash MX 2004 kon het bijvoorbeeld niet eens.)

Wat we nu willen weten is hoe breed onze nieuwe pixels moeten zijn! Ik had al verteld dat de kwaliteit van ons plaatje er op achteruit zou gaan en nu zul je zien hoe dat komt.

pixelWidth = radiusX / xOnEllipse;

We berekenen de verhouding tussen de maximale radius en het aantal pixels binnen onze ellipse (is hetzelfde als de x positie op de rand van de ellipse bij een speciefieke y positie). Deze verhouding levert niet een getal tussen -1 en 1 op en dat komt omdat ik ‘de grootste door de kleinste deel’ ipv andersom. Ik wil namelijk een factor hebben waar ik m’n pixeltjes mee uit kan rekken. Er zou bijvoorbeeld een getal van zes uit kunnen komen. Dat betekent dan dat het aantal pixels binnen mijn ellipse 6 keer zo klein is als het aantal pixels binnen de rechthoek. Dus: moet ik of een lege ruimte van 6 pixels aanbrengen bij iedere getekende pixel of moet ik de pixels die ik teken gaan uitrekken. Hieronder zie je het verschil.

1 = Originele ellipse gevuld met een regenboog verloopje
2 = Ellips omgecat naar een rechthoek. Regelboog pixels zijn niet uitgerekt. Dus er is lege ruimte tussen de pixels.
3 = Ellips omgecat naar een rechthoek. Maar nu zijn de regenboog pixels wel uitgerekt.



Pixels niet uitrekken doe je zo:

point(centerX-xOnSquare,centerY-y);

Wil je ze wel uitrekken zodat de hele rechthoek gevuld is dan kun je lijnen gebruiken met een lengte zo groot als pixelWidth.

line(centerX-xOnSquare,centerY-y,centerX-xOnSquare-pixelWidth,centerY-y);

That’s all! De volgende stap voor ons is een filmpje op te hakken in frames en het bovenste truukje op alle losse frames toepassen en vervolgens opslaan als aparte afbeeldingen. Stiekum moet ik toegeven dat dat scriptje al lang af is… Maar nu moet ik slapen want het is al half 4.





De complete sourcecode kun je hier bekijken:/mediatech/mms/EllipseToSquare/

3 Comments »

  1. Goed bezig geweest Rick!!

    Comment by Nikos — 21 October 2005 @ 08:54

  2. Daar kom ik weer met kommentaar…..

    Ik zou het andersom hebben gedaan. Jij pakt een pixel in je elipse en kijkt waar die uit gaat komen op de rechthoek. Ik zou een pixel op de rechthoek pakken en dan een interpolatie doen op de pixels in de elipse om zijn kleur te bepalen. Maar deze manier werkt zo te zien ook goed :)

    Overgens erg leuk om te zien wat jij allemaal progt in 1 week :-)

    Comment by Michiel — 21 October 2005 @ 11:32

  3. […] Dit is het vervolg op het EllipseToSquare script. Verder heb ik er eventjes niks over te zeggen. […]

    Pingback by Ricksmuseum » Vervolg op EllipseToSquare — 26 October 2005 @ 03:31

RSS feed for comments on this post. TrackBack URI

Leave a comment

You must be logged in to post a comment.