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.