An dem nebenstehend zu sehenden Bild soll demonstriert werden,
Die Realisierung all dieser Punkte ist nicht annähernd so schwierig, wie man erwarten könnte. Allerdings scheidet die Möglichkeit aus, nacheinander Transformationen für die einzelnen Körper zu setzen und dann mit Funktionen zu zeichnen, die die Transformationen auswerten. Prinzipiell ist das zwar auch bei mehreren Körpern möglich, aber wenn man korrekte Darstellung der Überdeckung erzielen möchte, muss zunächst aus mehreren Körpern ein einziges Modell erzeugt werden.
Folgende Strategie wird verfolgt: Die auf der Seite "3D-Flächenmodelle in geeigneter Reihenfolge zeichnen" vorgestellte und ausführlich erläuterte Funktion draw, die ein mit den beiden Arrays xyz und area beschriebenes Modell zeichnet, wird unverändert auch hier genutzt, indem vorab die Arrays, die die einzelnen Körper beschreiben, zu einem Array xyz und einem Array area zusammengeführt werden. Dafür wird ein Array models definiert, das die Beschreibungen der zu verwendenden Körper mit zusätzlichen Parametern enthält, und die Funktion mergemodels führt die Modellbeschreibungen zu einem Modell zusammen:
var models = [[cubexyz , cubearea , -6 , -4 , 0 , 1.8 , 2] , // Fuer jedes Modell:
[dodekaxyz , dodekaarea , 8 , 0 , 0 , 1.5 , 2] , // Koordinaten-Array,
[buckyxyz , buckyarea , 0 , 0 , 0 , 3 , 0] , // Flaechen-Array,
[oktaxyz , oktaarea , 2 , -8 , 0 , 2 , 0] , // x-, y- und z-Offset,
[ikosaxyz , ikosaarea , 2 , 8 , 0 , 1 , 1] , // Skalierungsfaktor,
[tetraxyz , tetraarea , -6 , 4 , 0 , 2 , 1]] ; // Achse der Eigendrehung
function mergemodels () {
var jjx = 0 , jja = 0 , ptoffs = 0 ;
for (var i = 0 ; i < models.length ; i++) { // ... ueber alle Modelle
for (var j = 0 ; j < models[i][0].length ; j++) { // ... ueber alle Punkte eines Modells
xyz[jjx] = models[i][0][j].concat() ; // ... ein Punkt wird kopiert
gi.w2wtransform (xyz[jjx] , models[i][2] , models[i][3] , models[i][4] ,
psi , models[i][6] , models[i][5]) ;
jjx++ ;
}
for (var j = 0 ; j < models[i][1].length ; j++) { // ... ueber alle Flaechen eines Modells
area[jja] = models[i][1][j].concat() ; // ... eine Flaeche wird kopiert
for (var k = 0 ; k < area[jja].length - 1 ; k++) {
area[jja][k] += ptoffs ; // ... + Offset der Punktnummern
} // (Punkte haben neue Nummern)
jja++ ;
}
ptoffs += models[i][0].length ; // ... += "Anzahl der Punkte des Modells"
}
psi += dPhi ; // ... Winkel fuer Eigendrehung
}
w2wtransform (xyzw , tx , ty , tz , phi , axis , s)
wird ein Koordinaten-Tripel xyzw ("World coordinates") einer Transformation unterworfen, die durch die nachfolgenden Parameter definiert wird. Dies geschieht in folgender Reihenfolge:Mit dem Aufbau der beiden Arrays xyz und area, die nun ein einziges Modell beschreiben, gilt alles, was auf den Seiten "3D-Drahtmodelle zeichnen und animieren" und "3D-Flächenmodelle in geeigneter Reihenfolge zeichnen" ausführlich beschrieben wird. Deshalb kann der nachfolgende Überblick über den Rest der hier beschriebenen Grafik kurz ausfallen:
<body onLoad="init();">
gestartet:
function init () {
gi = new canvasGI ("canvas") ; // Ein "CanvasGI-Objekt" wird erzeugt
mergemodels () ; // ... merged die Modelle
var limits = gi.ptlimits (xyz) ; // ... berechnet "User coorniates"-Limits
gi.setusercoordsi (limits.xumin , limits.yumin , limits.xumax , limits.yumax , 10) ;
phiplus (gi.AXIS_Z) ; // ... startet Animation (Rotation um vertikale Achse)
}
function phiplus (axis) {
rotax = axis ;
if (anim == 1) {
window.clearInterval (aktiv) ;
}
anim = 1 ;
aktiv = window.setInterval("rotation ()" , dT);
}
function rotation () {
gi.t3rotation (dPhi , rotax) ;
draw () ;
}
function draw () {
mergemodels () ; // ... merged die Modelle
var points = new Array () ; // ... fuer die Koordinaten eines Polygons
gi.clearcanvas ("silver" , "black") ; // ... fuellt Canvas-Bereich mit Hintergrundfarbe
// ("silver") und zeichnet schwarzen Rahmen
for (var i = 0 ; i < area.length ; i++) {
var np = area[i].length - 1 ; // ... weil letztes Element die Farbe ist
for (var j = 0 ; j < np ; j++) {
points[j] = xyz[area[i][j]] ; // ... sammelt Punktkoordinaten eines Polygons
}
area[i].unshift (gi.wtsymbdist (points , np)) ; // ... berechnet symbolischen Abstand vom Betrachter
} // und fuegt diesen Wert an der Array-Spitze an
gi.sortbyindex (area , 0) ; // ... sortiert nach den Werten an der Array-Spitze
for (var i = 0 ; i < area.length ; i++) { // ... zeichnet alles in der korrekten Reihenfolge
area[i].shift() ; // ... entfernt den Wert an der Array-Spitze wieder
var np = area[i].length - 1 ;
for (var j = 0 ; j < np ; j++) {
points[j] = xyz[area[i][j]] ; // ... sammelt Punktkoordinaten eines Polygons
}
gi.wtdrawfarea (points , np , area[i][np] , "black") ; // ... zeichnet ein einzelnes Polygon
}
}
Die oben zu sehende Grafik kann auch als eigenständige Seite "Platonische Körper und Buckyball" aufgerufen werden.