Atom Nieuws jaargang 2000 nummer 1
../../../images/back.gif ../../../images/exit.gif ../../../images/forward.gif
pagina 11
Afbeeldingen in de derde dimensie

U voelt natuurlijk al aan uw water: dit gaat geen gezellig verhaal worden. We gaan het hebben over afbeeldingen met ruimtelijke voorstelling. Dus dat wordt mouwen opstropen en aan de slag.

Waarom nu

Inmiddels is de Atom zodanig opgevoerd, zowel in de Roland als de Wouter variant, dat ook de als langzaam bekend staande floating point berekeningen nu soepeltjes uitgevoerd kunnen worden. Dat is de aanleiding om dit stuk te schrijven.

De achtergrond

Zo wel voor de hele jonge programmeurs als de wat oudere, waar inmiddels (net als bij mij) de wiskunde of afwezig is, of ver weggezakt, is dit stuk bedoeld. Uiteraard gaan we niets uit de weg, daar waar het om de Atom gaat, maar zodra er formules over het papier vliegen, haakt menige mede atomist af, althans dat is wat ik om mij heen hoor. Dit stukje is nou net voor die mensen bedoeld. Een beetje oefenen en misschien het stukje meer dan eens lezen en: welkom in onze 3d show!

De uitgangspunten

Waarom is het nou allemaal zo lastig? Wel, het grote probleem is dat een stuk papier en ook het beeldscherm van nature geen diepte heeft. Het is een plat vlak. Maar met wat schuine lijntjes erbij, lijkt het plotseling allemaal wel wat diepte te hebben. Maar hoe bereken je de punten die feitelijk ruimtelijk zo, dat je ze in een plat vlak weer kunt geven.
In nevenstaande afbeelding is een poging tot ruimtelijke weergave gedaan.
sv10610603.gif

Op basis van deze afbeelding, valt af te leiden dat het gaat om een punt op 3 assen: een X, Y en Z as, wat staat voor, zeg maar, lengte, breedte en diepte. Met andere woorden: een punt kun je aangeven als (2,3,3). En u hoeft geen fanatieke atomist te zijn dat het MOVE en DRAW (en ook het PLOT) statement alleen een X en Y ondersteunen. Hoe nu dit van een letterlijke extra dimensie te voorzien?
Wel, het begint allemaal met de kijkhoek, dus hoe schuin ligt het perspectief. Hiervoor wordt voor zowel X als Y een extra variabele in het leven geroepen. Waarom twee? Wel als u naar een willekeurig voorwerp kijkt en u gaat staan, dan betekent dat een verandering in de Y richting en dus ook een verandering in het perspectief. Datzelfde geldt ook voor als u naar links danwel rechts schuift, ook hier veranderd het perspectief. In het voorbeeld worden deze waarden op Xan en Yan gesteld. Voor de berekening van de diepte is ook een variabele gedefinieerd: Zan, die feitelijk de richting van het zogeheten ‘verdwijnpunt’, daar waar de lijnen elkaar zouden raken.

Kijk, en hier komt nou een klein stukje wiskunde om de hoek. Om de plaats te gaan bepalen waar op een plat vlak (2 dimensionaal) een 3 dimensionaal verantwoord puntje zou moeten komen, laat zich als volgt berekenen:

Yt = Y * COS(Xan) - Z * SIN(Xan)
Zt = Y * SIN(Xan) + Z * COS(Xan)
Y = Yt

Z = Zt
Xt = X * COS(Yan) - Z * SIN(Yan)
Zt = X * SIN(Yan) + Z * COS(Yan)
X = Xt

Z = Zt
Xt = X * COS(Zan) - Y * SIN(Zan)
Yt = X * SIN(Zan) + Y * COS(Zan)
X = Xt ßDeze X gaan we gebruiken
Y = Yt ßDeze Y gaan we gebruiken

Nu moeten we kenbaar maken, wat de waarde van Xan, Yan en Zan is! In principe zijn dit de waardes die overeenkomen met de snelheid van de rotatie. Voor de juiste beeldverhouding, geldt dat Xan=Yan, anders wordt de zaak wat opgerekt en verliest het zijn juiste perspectief. De waarde voor Zan mag allerlei leuke waardes aannemen.

Wat mooie waardes? Hier zijn ze:

Zan = .3
Yan = .1
Xan = .1

Ik ben me bewust dat het al wat lastig is, dus waarom geen voorbeeldje. Neem in gedachten een kubus. Als je deze in een 3d assenstelsel zou tekenen, kan je dat doen met de volgende coördinaten:

  X         Y         Z      
1:          40 40 40
2:         -40 40 40
3:         -40-40 40
4:          40-40 40
5:          40 40-40
6:         -40 40-40
7:         -40-40-40
8:          40-40-40
sv10610604.gif
Overbodige opmerking natuurlijk: een kubus bestaat uit 8 coördinaten, en als je daar een lijntje tussen tekent, zie je de kubus!

Wat we willen doen, is deze voorstelling van de kubus in 3 dimensies, terug brengen naar een voorstelling die we in 2 dimensies gaan tekenen, zodat het gaat lijken op de kubus zoals weergegeven. Dus we laten de formule zoals eerder beschreven er op los. In pseudo taal ziet dat er dan ongeveer als volgt uit. Een kleine opmerking vooraf: eerst wordt de array PUNT gevuld met de gegevens van de coördinaten, dus het tabelletje van 1-8 uit het vorig genoemde.

For Punt = 1 to 8
REM Punt heeft in deze 3 componenten: X, Y en Z

Yt = KUBUS[Punt[Y]] * COS(Xan) - KUBUS[Punt[x]] * SIN(Xan)

REM een kleine opmerking: wat we doen: we vervangen de Y en de Z component met de coördinaten van het huidige punt. Het originele, de Yt = Y * COS(Xan) - Z * SIN(Xan), worden vervangen door de punten uit de array.

Zt = KUBUS[Punt[Y]] * SIN(Xan) + KUBUS[Punt[Z]] * COS(Xan)
REM Net als de vorige berekening

KUBUS[Punt[Y]] = Yt Rem Waarde in tabel wordt aangepast
KUBUS[Punt[Z]] = Zt

Xt = KUBUS[Punt[X]] * COS(Yan) - KUBUS[Punt[Z]] * SIN(Xan)
Zt = KUBUS[Punt[X]] * SIN(Yan) + KUBUS[Punt[Z]] * COS(Xan)

KUBUS[Punt[X]] = Xt
KUBUS[Punt[Z]] = Zt

Xt = KUBUS[Punt[X]] * COS(Zan) - KUBUS[Punt[Y]] * SIN(Zan)
Yt = KUBUS[Punt[X]] * SIN(Zan) + KUBUS[Punt[Y]] * COS(Zan)
KUBUS[Punt[X]] = Xt Deze zouden we kunnen tekenen.
KUBUS[Punt[Y]] = Yt Deze zouden we kunnen tekenen.

Next

Tot zover het harde werk in de lus. Er wordt driftig gerekend in de lus, en het is dus niet toegestaan om voortijds al conclusies te trekken uit berekende waardes. Dat mag pas net voor de next lus. De Z component is na de berekening niet meer van belang, deze wordt toch niet meer gebruikt. Het is nu een koud kunstje om het geheel te tekenen.

Nu in Atom code

Onze atom is niet supersterk daar waar het gaat om variabele namen. Maar met de pseudo code van hierboven, en de onvolprezen Pcharme moet het lukken.

En hoe nu verder

Dit was de eerste aanzet in 3d denken. In het voorbeeld worden alleen de hoekpunten van de kubus getekend. Aan u de eer om er wat lijntjes van te maken, dus met de juiste combinatie van MOVE (X,Y) en DRAW (X,Y). Roland is zo vriendelijk geweest om mijn programma wat in GW-Basic gemaakt is, te vertalen naar Atom basic. Heeft trouwens dit verhaal op voorhand al gelezen en waardevolle opmerkingen en toevoegingen aangereikt. Dat is nog eens synergie!

10 PROGRAM KUBUS-3D
20
30 FDIM %KK(3,8)
40 FDIM %XX0,%YY0,%ZZ0
50 PRINT $12"HOEKPUNTEN:"''
60 FOR Y=1 TO 8
70 FOR X=1 TO 3
80 READ N
90 %KK(X,Y)=N+95
95 PRINT %(%KK(X,Y))
100 NEXT X
110 PRINT '
120 NEXT Y
130 %XX0=0.1 ; REM Xan
140 %YY0=0.1 ; REM Yan
150 %ZZ0=0.3 ; REM Zan
160 X=1;Y=2;Z=3
165 PRINT ''"BEREKENDE X EN Y COORDINATEN:"'
170 FOR N=1 TO 8
180 %Y=%KK(Y,N)*COS%XX0-%KK(Z,N)*SIN%XX0
190 %Z=%KK(Y,N)*SIN%XX0+%KK(Z,N)*COS%XX0
200 %KK(Y,N)=%Y
210 %KK(Z,N)=%Z
220 %X=%KK(X,N)*COS%YY0-%KK(Z,N)*SIN%YY0
230 %Z=%KK(X,N)*SIN%YY0+%KK(Z,N)*COS%YY0
240 %KK(X,N)=%X
250 %KK(Z,N)=%Z
260 %X=%KK(X,N)*COS%ZZ0-%KK(Y,N)*SIN%ZZ0
270 %Y=%KK(X,N)*SIN%ZZ0+%KK(Y,N)*COS%ZZ0
280 %KK(X,N)=%X
290 %KK(Y,N)=%Y
300 PRINT N":"%(%X),%(%Y)'
310 NEXT N
320 PRINT "DRUK OP EEN TOETS"'
330 PRINT "VOOR EEN GRAFISCHE AFBEELDING."
340 LINK #FFE3
400 CLEAR 4
410 MOVE %(%KK(X,1)),%(%KK(Y,1))
420 DRAW %(%KK(X,2)),%(%KK(Y,2))
430 DRAW %(%KK(X,6)),%(%KK(Y,6))
440 DRAW %(%KK(X,5)),%(%KK(Y,5))
450 DRAW %(%KK(X,1)),%(%KK(Y,1))
460 DRAW %(%KK(X,4)),%(%KK(Y,4))
470 DRAW %(%KK(X,3)),%(%KK(Y,3))
480 DRAW %(%KK(X,7)),%(%KK(Y,7))
490 DRAW %(%KK(X,8)),%(%KK(Y,8))
500 DRAW %(%KK(X,4)),%(%KK(Y,4))
510 MOVE %(%KK(X,5)),%(%KK(Y,5));DRAW %(%KK(X,8)),%(%KK(Y,8))
520 MOVE %(%KK(X,6)),%(%KK(Y,6));DRAW %(%KK(X,7)),%(%KK(Y,7))
530 MOVE %(%KK(X,2)),%(%KK(Y,2));DRAW %(%KK(X,3)),%(%KK(Y,3))
540 END
2000 DATA 40,40,40,-40,40,40,-40,-40,40 ; REM 1, 2 EN 3
2010 DATA 40,-40,40,40,40,-40,-40,40,-40 ; REM 4, 5 EN 6
2020 DATA -40,-40,-40,40,-40,-40 ; REM 7 EN 8

sv605.gif Experimenten

De kubus, u ziet hem hiernaast, is (nog) niet zo mooi als in de schets eerder in het verhaal. U kunt naar hartelust experimenteren met waardes van Xan en Yan en Zan op regel 130-150.

Leendert Bijnagte
../../../images/back.gif ../../../images/exit.gif ../../../images/forward.gif