Document ID: /fineweb-2-swissfilter-quality_10-filterrobots/filtered/03241.jsonl.gz/2486

Mathematik muss nicht langweilig und abstrakt sein. Mit etwas Geschick lassen sich mathematische Formeln in interessante 3D Grafiken verwandeln. Diese können sehr ansprechend aussehen, vor allem, wenn sie durch ein geeignetes Grafikprogramm mit Beleuchtungseffekten versehen werden.
Als Bonus für jene, die Zugriff auf Grafik- oder entsprechende Mathematik-Programme haben, liefere ich eine Formel, ich nenne sie den Herz-Generator, mit der fast jede 2D Funktion zu einer 3D Herz-Kurve wird. Unbedingt ausprobieren!
Diese Bilder habe ich mit dem von mir entwickelten Grafik-Programm JsGraph3D erstellt. Damit lassen sich 3D Kurven mit Beleuchtungseffekten im Browser berechnen und darstellen. Du kannst diesen Berechnungen live zusehen, indem du die Demo-Links unterhalb der Bilder anklickst. Die Bilder oben sind mit einer Auflösung von 1000 mal 1000 Flächen gerendert worden. Die Bilder hinter den Demo-Links werden mit einer Auflösung von 300 mal 300 Flächen gezeichnet.
Die Bilder der Herz-Galerie sind 3D Darstellungen der folgenden Formel:
|(1)||

|mit||

|wobei'||

Die Farbe der Fläche und deren Ausblendung am Rand wird nach folgendem Algorithmus berechnet:
r = sqrt( x^2 - 1.2*abs(x)*y + y^2 ) z = ( sin( 15 * r^0.2 ) )^2 c = 1 - z if r > 9.56 then // Übergang von rot/weiss nach rot/gelb if r > 12 then // Ausblenden a = e^( -( 0.5 * (r - 12) )^4 ) color = { red: 1, green: c, blue: 0, alpha: a } else color = { red: 1, green: c, blue: 0, alpha: 1 } end if else // Farben rot/weiss color = { red: 1, green: c, blue: c, alpha: 1 } end if
Eine Beschreibung dieses Algorithmus findest du unter:
Als 3D Funktionen bezeichne ich mathematische Funktionen, die von zwei Variablen abhängig sind:
|(2)|
f ist eine beliebige Funktion, die aus zwei Werten x und y einen dritten Wert z berechnet. Wenn wir x und y als Koordinaten in einer Ebene und z als dritte Koordinate im Raum betrachten, erhalten wir für jedes Wertepaar x und y und den zugehörigen Wert z einen Punkt im Raum: P( x, y, z ).
Wir können für eine ganze Reihe von XY-Koordinaten die zugehörigen Z-Koordinaten berechnen und erhalten dadurch ein Gitter von Punkten im Raum. Wenn wir benachbarte Punkte durch Linien verbinden, entsteht eine dreidimensionale Fläche wie im Bild gezeigt.
Wir können jedem Flächenelement eine bestimmte Farbe zuweisen, welche z.B. aus den Koordinaten der Fläche berechnet wird. Durch geeignete Grafik-Programme lassen sich zudem Beleuchtungseffekte hinzurechnen. Wenn das Gitter sehr fein gemacht wird, erhalten wir Grafiken wie in der Herz-Galerie.
Für die Grafiken der Herz-Galerie habe ich ein so feines Gitter gewählt, dass 1 002 001 Punkte und 1 000 000 Flächen berechnet worden sind! Dies hat pro Bild auf meinem PC (Intel Core i7 CPU 960 @ 3,2 GHz) im Chrome-Browser (Version 29.0.1547.62 m) 3 Sekunden für alle Berechnungen und 17 Sekunden für das Zeichnen benötigt.
Übrigens ist die Formel (1), auch wenn es auf den ersten Blick nicht so aussieht, dennoch eine Funktion der zwei Variablen x und y. Der Rasius r ist nur ein Zwischenwert. Die Aufsplittung der Formel in zwei Teile macht sie übersichtlicher, weil r zweimal verwendet wird. Als eine Formel geschrieben sieht (1) wiefolgt aus:
|(3)|
Auf dem Weg zur Herz-Kurve müssen wir uns zuerst mit rotations-symmetrischen 3D Kurven befassen. Solche Kurven sind im Grunde 2D Funktionen, welche um die Z-Achse rotiert werden. 2D Funktionen sind Funktionen, die nur von einer Variablen abhängig sind, also die folgende Form haben:
|(4)|
Die blaue Kurve im Bild zeigt eine solche Funktion. Sie stellt den ersten Teil der Herz-Formel (1) dar:
|(5)|
Wie erhalten wir aus dieser 2D Funktion eine rotations-symmetrische 3D Kurve? Wie rotiert man überhaupt eine Funktion um die Z-Achse, sodass daraus eine Fläche entsteht?
In der Formel (5) kommt statt x und y nur die Variable r vor. Wir müssen also irgendwie aus den beiden XY-Werten eines Punktes einen Wert r berechnen:
Eine 3D Rotations-Kurve erhält man, indem für jeden Punkt der XY-Ebene berechnet wird, wie gross sein Abstand r zur Z-Achse ist. Dieser Abstand kann mit dem Satz von Pythagoras berechnet werden:
|(6)|
Mit diesem Verfahren kann aus jeder beliebigen 2D Funktion eine rotations-symmetrische 3D Kurve gezeichnet werden.
Das Geheimnis zum Erzeugen einer herzförmigen 3D Kurve liegt im Anwenden von Koordinaten-Transformationen auf eine rotations-symmetrische 3D Kurve. Durch Transformation von Koordinaten könne beliebige 3D Objekte verzerrt, gedreht und gespiegelt werden.
Zuerst möchte ich zeigen, welche Transformationen man auf eine 3D Rotations-Kurve anwenden muss, um eine Herzform zu erhalten. Dann zeige ich, wie man solche Koordinaten-Transformationen berechnet.
Im Bild ist erkennbar, dass die rote Herzform durch Spiegeln der rechten Hälfte der roten Ellipse an der Y-Achse entsteht. Die rot gestrichelte Ellipse wird erzeugt, indem der blau gestrichelte Kreis in Richtung der X-Achse zur blauen Ellipse gedehnt wird. Diese wird danach um den Winkel β im Gegenuhrzeigersinn um den Nullpunkt gedreht.
Damit sind die Transformationen von einer Rotations-Form in eine Herz-Form schon beschrieben:
Werden alle 3D Punkte einer Rotations-Kurve nacheinander wie oben beschrieben transformiert, wird die Rotations-Kurve zu einer Herz-Kurve verzerrt. Wir müssen nur die XY-Koordinaten aller Punkte transformieren. Die Z-Koordinaten können wir von den ursprünglichen Punkten übernehmen.
Für Transformationen verwendet man Vektoren und Matrizen-Operationen. Für jeden 3D Punkt P( x, y, z ) können wir einen 2D Vektor
|(7)|
Der Vektor
|(8)|
Q ist der mit der Matrix T transformierte Punkt P.
Eine Matrix S, welche einen Kreis in X-Richtung um den Faktor a und in Y-Richtung um den Faktor b zu einer Ellipse deformiert, sieht wiefolgt aus:
|(9)||

Skalierungs-Matrix
Eine Matrix R, welche eine beliebige Figur um den Winkel β im Gegenuhrzeigersinn dreht, sieht wiefolgt aus:
|(10)||

Rotations-Matrix
Die beiden Matrizen S und R können durch Matrizenmultiplikation zu einer neuen Matrix T zusammengefasst werden:
|(11)|
Achtung, die Reihenfolge der Matrizenmultiplikation spielt eine Rolle. Die Transformationen werden von rechts nach links angewandt.
Wir müssen dann den Vektor
Mit der oben beschriebenen Koordinaten-Transformation könnten wir eine fertig berechnete rotations-symmetrische Kurve zu einer gedrehten ellipsoiden Kurve transformieren. Wir würden dazu Punkt für Punkt zunächst aus den XY-Koordinaten der Rotations-Kurve den jeweiligen Radius r berechnen, daraus die Z-Koordinate über die 2D Funktion, und schliesslich würden wir die XY-Koordinaten der Rotations-Kurve mit der Matrix T in die XY-Koordinaten der Ellipsen-Kurve transformieren. Die XY-Koordinaten der Ellipsen-Kurve zusammen mit der Z-Koordinate bilden jeweils einen Punkt der Ellipsen-Kurve.
Bei dieser Art der Transformation wird allerdings nicht nur ein Kreis zur Ellipse, sondern auch das zugrundeliegende XY-Koordinaten-Gitter wird zuerst gedehnt und dann gedreht.
Das Problem dabei: Einem Grafik-Programm kann man in der Regel keine Transformations-Matrix übergeben, sondern nur eine Funktion mit zwei Variablen. Das Grafik-Programm generiert ein regelmässiges XY-Koordinaten-Gitter und berechnet über die Funktion die Z-Koordinaten. Das Grafik-Programm gibt somit das Koordinaten-Gitter vor und dieses deckt sich nicht dem transformierten Gitter, in dem die Ellipse liegt.
Wie kommen wir von vorgegebenen XY-Koordinaten der zur berechnenden Ellipsen-Kurve auf die entsprechenden XY-Koordinaten der Rotations-Kurve? Denn wir brauchen für die Berechnung des Z-Wertes der Ellipsen-Kurve den Radius, der aus den entsprechenden XY-Koordinaten der Rotations-Kurve berechnet wird.
Mit der Transformations-Matrix T konnten wir einen Punkt P der Rotations-Kurve in einen entsprechenden Punkt Q der Ellipsen-Kurve transformieren. Wir benötigen aber genau die umgekehrte Transformation.
Dies ist kein Problem, denn wir müssen nur die Inverse Matrix T−1 der Matrix T berechnen, was in unserem Fall besonders einfach ist. Tipp: invertiere die beiden Matrizen S und R separat und multipliziere sie in umgekehrter Reihenfolge miteinander.
|(15)|
|wobei'||

Damit können wir einen Vektor
|(16)|
Ausmultipliziert erhalten wir die Transformations-Formeln für die beiden Koordinaten:
|(17)|
|und|
|mit|
|wobei'||

Jetzt können wir den Kreisradius r für die Kreis-Koordinaten ( x', y' ) nach Pythagoras berechnen:
|(18)||

|mit|
|wobei'||

Dieser Radius wird in die 2D Herz-Funktion eingesetzt welche uns den Z-Wert liefert.
Wenn wir mit verschiedenen Winkeln β und Streckungen a und b experimentieren wollen, müssen wir obige Formel (18) zum Berechnen des Radius r verwenden. In den Herz-Kurven auf dieser Seite habe ich mich auf die folgenden Werte festgelegt:
Setze ich diese Vorgaben in die Formel (18) ein, so erhalte ich:
|(20)|
Bis auf den Faktor √5/8 ist dies schon fast der zweite Teil der Herz-Formel (1). Der Faktor √5/8 spielt für unsere Herz-Formel keine Rolle, denn er beeinflusst lediglich die Grösse der Herzen und diese kann ich jederzeit durch Zoomen des Bildes verändern. Ich lasse diesen Faktor deshalb bei der Herz-Formel weg.
Wenn ich mit obiger Formel die 3D Kurve berechnen würde, würde jedoch noch kein Herz, sondern erst eine gedrehte Ellipse gezeichnet. Wir müssen also die rechte Hälfte der Ellispe noch an der Y-Achse spiegeln.
Um die rechte Hälfte einer beliebige 3D Kurve an der Y-Achse zu spiegeln, müssen wir einfach alle x in der Formel durch den Absolutbetrag |x| ersetzten. So werden alle Punkte mit negativen X-Koordinaten zu Punkten mit positiven X-Koordinaten. Für alle links von der Y-Achse liegenden Punkte werden damit dieselben Z-Werte wie für die entsprechenden Punkte rechts der Y-Achse errechnet. Dies resultiert in einer spiegel-symmetrischen Grafik.
In der Herz-Formel (1) kommen nur im zweiten Teil bei der Berechnung des Radius r X-Werte vor. Bei X-Werten, welche im Quadrat stehen, muss nicht der Absolutbetrag berechnet werden, weil durch die Quadrierung sowieso nur positive Werte entstehen.
Die Formel (20) für den Radius r ändert sich durch die Spiegelung also zu:
|(21)||

|(22)||

beliebige 2D Funktion
|mit||

Herz-Generator
Damit die Herz-Form in der so erzeugten 3D Kurve erkennbar wird, muss man entweder eine 2D Funktion mit Wellen nehmen, z.B. eine periodische Funktion wie Sinus oder Cosinus, oder die Kurve muss entsprechend eingefärbt werden, z.B. so, dass der Z-Wert die Farbe bestimmt.
Bisher habe ich gezeigt, wie wir aus einer 2D Funktion herzförmige 3D Kurven erzeugen können. Was jetzt noch fehlt, ist eine schöne 2D Funktion z = f(r), wie sie das folgende Bild zeigt, und ein Algorithmus für die Färbung der Fläche.
Die dicke rot/weiss/gelbe Kurve ist meine fertige 2D Herz-Funktion mit der entsprechenden Färbung und Ausblendung. Die grüne Hüllkurve beschränkt die 2D Herz-Funktion nach oben. Die blaue Kurve bestimmt ab der vertikalen blauen Linie den Wert des Alpha-Kanals. Der Alpha-Kanal steuert die Durchsichtigkeit der Fläche: 1 für sichtbar bis 0 für unsichtbar. Von r = 0 bis zur vertikalen roten Linie wechselt die Farbe der Herz-Kurve zwischen rot und weiss. Ab der Linie wechselt dann die Farbe zwischen rot und gelb.
Im Skelett-Bild sehen wir die 2D Herz-Funktion blau an der Schnittkante. Gelb ist auch noch die Hüllkurve eingezeichnet.
Aber nun zur Herleitung der Herz-Funktion:
Ich wollte mehrere ineinander verschachtelte Herzen haben. Da bietet sich als periodische Grundfunktion ein Sinus oder Cosinus an. Ich wählte den Sinus und setzte ihn zusätzlich ins Quadrat (also sin(r)2). Dadurch schwingt die Funktion zwischen Null und 1, statt zwischen −1 und +1. So erreiche ich, dass bei der Multiplikation der Grundfunktion mit der Hüllkurve die 2D Funktion zwischen einem positiven Wert und Null pendelt.
Bis jetzt sieht die 2D Herz-Funktion so aus:
|(23)|
Diese 3D Herz-Kurve sieht mir zu langweilig aus; die Abstände zwischen den einzelnen Herzen sind zu regelmässig (klicke auf den Demo-Link um die zugehörige Grafik berechnen zu lassen).
Wenn ich den Radius mit einem Wert kleiner 1 potenziere (0,2 schien mir ein passender Wert), wird der Sinus bei Radien kleiner 1 gestaucht und bei Radien grösser 1 gedehnt. Damit erreiche ich, dass die Herzen im Zentrum näher beieinander liegen als weiter draussen. Damit der Sinus nicht allzusehr gestreckt wird, multipliziere ich noch mit 15. So erhalte ich 3 Wellen innerhalb eines Radius von 1 und 6 Wellen bis zu einem Radius von ca. 13:
|(24)|
Jetzt sieht das Ganze noch etwas flach aus. Ich verpasse daher der Herz-Funktion noch eine Hüllkurve. Diese soll die bisherige Funktion bei r kleiner 1 verkleinern und bei r grösser 1 vergrössern. Die naheliegendste Lösung wäre, die ganze Formel mit r zu multiplizieren. Diese einfache Hüllkurve steigt mir aber viel zu stark an. Wenn ich aber r mit einem Wert kleiner 1 potenziere, steigt die Hüllkurve wesentlich moderater an (grüne bzw. gelbe Kurve). Als Exponent schien mir 0,6 passend (0,5 würde der Quadratwurzel entsprechen).
Damit ist meine 2D Herz-Funktion vollständig:
|(25)|
Das Einfärben ist relativ einfach. Ich verwende einfach die Funktion (24) um einen Farb-Parameter c zu berechnen:
|(26)|
Der Parameter c entspricht der 2D Herz-Funktion ohne Hüllkurve, hat also denselben Verlauf, jedoch einen Wertebereich der immer zwischen 0 und 1 wechselt. Mit diesem Wert kann ich die Farb-Kanäle rot, grün und blau so steuern, dass die Herz-Kurve zwischen rot und weiss, bzw. ab einem Radius von 9,56 zwischen rot und gelb wechselt.
Technisch funktioniert das Einfärben mit Hilfe meines Grafikprogrammes wiefolgt:
Es lässt sich eine Funktion installieren, die aufgerufen wird, bevor ein Flächenelement gezeichnet wird. Diese Funktion erhält als Argumente das Flächenelement und ein Objekt, welches u.a. die Farbe und den Alphakanal für dieses Flächenelement enthält. In dieser Funktion kann ich nun mit der Formel (26) einen Farbparameter c berechnen und damit die Farbe und den Alphakanal für dieses Flächenelement verändern. Diese Daten werden vom Grafikprogramm, nach eventueller Beleuchtungs-Berechnung, auf das Flächenelement beim Zeichnen angewandt.
Zum Ausblenden der Herz-Kurve über den Alpha-Kanal brauche ich eine Funktion, welche von einem Wert 1 mit grösser werdendem Radius langsam auf den Wert 0 verläuft.
Es gibt eine Reihe von Funktionen, die teilweise dieser Anforderung entsprechen (siehe Bild). Wenn ich eine dieser Funktionen an die Stelle r = 12 verschiebe und etwas dehne, kann ich die rechte Hälfte der Funktion für die Steuerung des Alpha-Kanals brauchen.
Als Grundfunktion für das Ausblenden wähle ich:
|(27)|
|wobei'||

In dieser Form ist die Kurve aber noch zu schmal und liegt bei Null statt an der Position 12. Indem ich in der Formel (27) den Radius mit 0,5 multipliziere, dehne ich die Funktion um den Faktor 2:
|(28)|
Indem ich in der Formel (28) r durch r−12 ersetze, verschiebe ich die Funktion an die Stelle r = 12:
|(29)||

Dies ist endlich die letzt Formel für unsere 3D Herz-Kurven!