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.
|
|
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 |
| |
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
| 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 |