Bernhard Häussner
Tags: Artikel mit dem Tag «Codesnippets» durchstöbern

Ein paar Code-Schnipsel

15.06.2009, 19:30
Javascript

Javascript

In diesem Post nur ein paar kleine Code-Auszüge und Techniken für Webanwendungen. Inhalt:

  • Data URI scheme für Favicons & CSS-Farbverläufe
  • HTML-Attribut contenteditable zum einfachen Editieren
  • Javascript: Globale Variablen einfach vermeiden
  • JSON in Script-Tags
  • JSON-Parser bei Bedarf laden
  • jQuery nach hinten verlegen
  • jQuery mouserest-Plugin

Data URI scheme für Favicons & CSS-Farbverläufe

Eine mir bisher unbekannte Funkion moderner Browser (ab IE8) sind data: URLs. Anders als normale http:// oder file:// URLs repräsentieren sie keinen Link, sondern die Daten sind komplett in der URL enthalten. Damit man auch Binärdaten verwenden kann (oder sich das escapen von HTML-Tags, „"“ etc. sparen), ist es möglich optional mit Base64 zu encodieren. Für ein Favicon sieht das dann so aus:

<link rel="shortcut icon" href="data:image/png;base64,iVBORw[...]RK5CYII="/>

Und für eine Graphik im CSS:

body {background:url(data:image/png;base64,iVBORw[...]ElFTkSuQmCC);}

Das lohnt sich bei kleinen Farbverläufen oder Symbolen, da ein zusätzliches Request zum Server mehr Bytes brauchen würde, als die Base64-Codierung produziert. Da bei base64 jeweils 3 Bytes zu 4 werden, sieht die Rechnung für die maximale PNG-Größe so aus:

PNG*(4/3) + 55 B = HTTP-HADER
mit HTTP-HADER:=600B PNG=1635 B

Da man im CSS mittels Sprites sowieso Requests sparen kann und durch Kombination größere PNGs bekommt, lohnt es sich hier also nur bei kleinen Projekten. (Oder bei riesigen Cookies, was die Request-Größe in die Höhe treibt. Da würde ich dann aber eine static-Subdomaine empfehlen. )

Als weiteren Vorteil kann man eine ganze Seite in eine HTML-Datei packen, jedoch kann man auch die Bilder nicht mehr so leicht bearbeiten.

HTML-Attribut contenteditable zum einfachen Editieren

Auch ein spaßiges Feature sind editierbare HTML-Elemente. Man kann das HTML-Attribut contenteditable für einzelne HTML-Elemente setzten oder gleich für die ganze Seite:

<body contenteditable="true">

Das Attribut ist zwar erst mit HTML5 valid, wird aber schon von einigen älteren Browsern unterstützt.

Javascript: Globale Variablen einfach vermeiden

Mit wachsender Zahl an Javascript-Bibliotheken wird die Wahrscheinlichkeit der Kollision globaler Variablen immer größer. Zwar ist es unwahrscheinlich, dass man z.B. $ überschreibt, aber manche Javascript Frameworks haben sich ja sogar zueignen gemacht, die Prototypen der Sprachfunktionen zu erweitern, was natürlich beim Einsatz eigener/anderer Prototypen-Erweiterungen nicht-überschaubare Probleme erzeugen kann. Das lässt sich aber vermeiden, indem man eine Art jQuery für andere Aufgaben erzeugt. Dazu kann man z.B. die ersten ~50 Zeilen von jQuery grob kopieren1, einen eigenen Framework-Namen einsetzen und dann eigene Funkionen einbauen, was man dann z.B. so verwenden kann:

var foo=Array(1,2,3,4);
alert(myFW(foo).contains(4));

Hier benutzt man dass die Funktion myFW einen Weiteren Konstruktor aus sich selbst aufrufen kann.

Es gilt zusätzlich globale Variablen zu vermeiden. Doch man kann für einzelne Komponenten Kürzel als Arrays verwenden, die dann die Globalen speichern. So kann man auch im DOM-Explorer von Firebug einen Überblick über globale Variablen behalten und die Komponenten können kommunizieren.

1 Ich vermute, wer den ganzen jQuery-Code aufmerksam gelesen hat, kann mehr als man in allen Javascript Büchern zusammen lernt.

Um den Speicherbedarf nicht unnötig in die Höhe zu treiben kann man die Variablen-Sichtbarkeit immer recht klein halten, damit die GC die Daten wieder fressen kann, wenn sie nicht mehr gebraucht werden. In JS sind übrigens auch Funktionen nicht global und löschbar. Funktionen, die nur beim Initialisieren gebraucht werden, kann man also mit delete funktionsName; wieder aus dem Speicher nehmen.

Ähnlich der main()-Funktion in anderen Programmiersprachen kann man in Javascript den Code zusätzlich in eine gleich aufgerufene, anonyme Funktion hüllen:

(function(){
  var nichtglobal;
  // code
})();

So kann man ganz normal „globale“ Variablen und Funktionen verwenden, aber ein anderes Script bemerkt davon nichts.

JSON in Script-Tags

Wenn man für Javascript Daten übertragen will, dann bietet sich JSON an, da es einfach Daten austauschen kann und in vielen Programmiersprachen implementiert ist. Da gibt es die eine Methode, JSONP, welche die Daten in einer Variable speichert, bzw. an ein Callback übergibt. Alternativ kann man auch die Daten in <script type="text/x-json" id="dafaultData">-Tags im DOM platzieren und dann mit Javascript auslesen und parsen

JSON-Parser bei Bedarf laden

Da moderne Browser jetzt native JSON-Parser bekommen, muss man den JSON-Parser nicht immer laden. Das könnte man so lösen:

<script>
  if(!this.JSON||typeof JSON.stringify !== 'function'||typeof JSON.parse !== 'function'){
    document.write("<scr"+"ipt type=\"text/javascript\" src=\"json2.js\"></scr"+"ipt>");
  }
</script>

jQuery nach hinten verlegen

Ganz praktisch hat es sich erwiesen, das Javascript nach dem meisten Markup zu laden. So wird durch CSS und HTML schonmal die Seite aufgebaut und dann erst werden die Javascript-Verbesserungen geladen.

Viele Webanwendungen, z.B. Google Mail, zeigen zunächst einen Ladebildschirm. Dadurch fühlt sich die Anwendung gleich viel langsamer an. Schneller wird die Anwendung wenn zunächst der grobe Aufbau steht, mit HTML und CSS zuerst geladen, dann ein kleines Skript erste Programmteile implementiert, sodass die Optik fertig erscheint. Dann läd man jQuery und dann erst weitere Javascripts (die auf jQuery basieren). So kann sich die Seite blitzschnell aufbauen, ohne dass erst jQuery geladen werden muss.

jQuery mouserest-Plugin

Nicht wirklich ein „Plugin“ aber eine kleine Hilfsfunktion. Sie führt ein Callback aus, nachdem die Maus einige Zeit auf dem Element war:

jQuery(function(){ // plugins
  jQuery.fn.mouserest=function (callback,time) {
    jQuery(this).mouseenter(function(e){
      this.dsthTo=setTimeout(function (obj){callback.apply(obj)},time,this);
    }).mouseleave(function(){
      clearTimeout(this.dsthTo);
    });
  }
});

Das ist ganz praktisch, denn wenn man die Zeit (in ms) auf 200 setzt, lässt sich verhindern, dass bestimmte Effekte beim bloßen Überfahren auftreten. Sondern der Event wird erst ausgelößt, wenn die Maus eine kurze Zeit auf dem Element war. Im callback kann man übrigens durch das apply() mit this auf das DOM-Element zugreifen, wie es in jQuery üblich ist.

Kommentare: 2 Einträge

jQuery Shortcuts (hoverfade Plugin)

01.06.2009, 15:53
jQuery hoverfade Plugin

jQuery hoverfade Plugin

Als ich zum Ferienbeginn ein paar Sachen an meinem Blog gerichtet habe, habe ich zum ersten mal die Plugin-Funktion von jQuery (aktiv) benutzt. Es gibt bestimmte Javascript-Effekte, die man immer wieder benutzt. In jQuery sind einige davon schon Enthalten. Doch man baut dann im Endeffekt doch immer einige jQuery-Funktionen zusammen. Ich z.B. „verstecke“ gerne Dinge auf Webseiten, indem ich sie leicht transparent mache und dann bei Mouseover wieder voll anzeigen lasse. Deshalb habe ich dafür ein jQuery „Plugin“ gebastelt:

jQuery.fn.hoverfade = function(hvspeed,hvopacity,uhspeed,uhopacity) {
  return this.each(function(){
    jQuery(this).css({
      opacity:uhopacity
    }).hover(function(){ 
      jQuery(this).stop().fadeTo(hvspeed,hvopacity);
    },function(){ 
      jQuery(this).stop().fadeTo(uhspeed,uhopacity);
    });
  });
};

Man kann es natürlich kaum Plugin nennen, sondern eher ein kleiner Shortcut, sodass man nicht immer schreiben muss:

$("selector").css({
   opacity:0.3
}).hover(function(){ 
   $(this).fadeTo("fast", 1);
},function(){ 
   $(this).fadeTo("slow", 0.3);
});

Sondern nur noch folgendes braucht:

$("selector").hoverfade("fast",1,"slow",0.3);

Wie man sieht ist das Erstellen von solch kleinen Plugins recht einfach: man hängt einfach in das jQuery.fn-Objekt die Funktion ein, die dann den häufig verwendeten Code enthält, und schon kann man sie als Makro auf alle jQuery-Elemente anwenden. Natürlich kann man auch Parameter an die Funktion übergeben, um eine gewisse Konfiguration zuzulassen.

Außerdem empfiehlt es sich in Plugins statt dem kurzen $ das explizite jQuery zu verwenden, damit man das Plugin auch verwenden kann, wenn $ z.B. ein anderes JS-Frameworks ist. In der Plugin-Funktion ist this das jQuery-Objekt auf das das Plugin angewendet wurde. Damit der Code immer klappt, sollte man noch mit each über die enthaltenten Elemente loopen. Im each-Closure zeigt this dann allerdings auf das DOM-Element, weshalb man es (meistens) mit $(this) wieder zu einem jQuery-Objekt machen muss. Damit das Plugin auch wirklich immer läuft, sollte man es vielleicht auch noch von JSLint checken lassen.

OT: andere Änderungen an der Seite

Ich habe übrigens neben den Icons für die Social Networks (Damit die Blogeinträge weiter oben stehen) auch noch ein paar andere Sachen verändert: Die automatischen ids, die nur die <input> mit den <label> verbinden, habe ich verkürzt, damit sie nicht immer so hässlich im Markup stehen. Dann habe ich im CSS alle Schriftgrößen auf Pixel umgestellt. Ich hoffe jetzt natürlich, dass meine Seite weiterhin in allen Browsern (fast) gleich aussieht.

Meine Editor-Toolbar wird auch immer voller. Jetzt habe ich mir noch Buttons dazu gemacht, um encodeierte <> und [] einzufügen. Außerdem habe ich endlich (halb) vimeo-Support im CMS. Ist ja grausam immer diesen ganzen <embed>-Kram erstmal in valides HTML umzuschreiben und dann hat man immer sehr viel HTML-Code zwischen dem Text. Außerdem kann ich so jetzt z.B. ganz einfach mal die Schriftfarbe von allen eingebetteten vimeo-Videos ändern.

Eigentlich sollte es ja so sein, dass im Content der Blogposts nichts ist, das die Darstellung beeinflusst, doch man braucht bei eingebetteten Videos offensichtlich immer Breite (ist fest) und Höhe (leider nicht fest), weshalb ich dann habe: [[vimeo:4767190|338|]]. Um alles 100%ig zu machen müsste ich natürlich aus der oEmbed API die genauen Video-Daten holen, aber das ist dann fast doch ein bisschen zu viel Aufwand. Was mich allerdings wundert: Während diese seltsame embed-Box auf der vimeo-Seite nicht-valides HTML ausspuckt, gibt die API, z.B. http://vimeo.com/api/oembed.xml?url=http%3A//vimeo.com/4767190&width=540 schönes valides HTML XHTML heraus.

Kommentare: keine

Processing: 3D-Koch-Kurve mit Sierpinski-Dreieck

23.05.2009, 17:34

Nachdem ich mich jetzt mal an Processing heran gewagt habe, habe ich auch gleich mal einen fraktalen Körper basteln müssen. Es handelt sich um eine Art dreidimensionale Koch-Schneeflocke.

Die Koch-Schneeflocke an sich ist eigentlich recht simpel, habe ich schon in Logo und PHP implementiert. Es wird eine Linie jeweils durch eine Linie mit einem Dreieck darin ersetzt. Auf den Raum übertragen heißt das dann eine Dreieckfläche bekommt einen Tetraeder eingesetzt. Dies wird dann mit den Flächen des Tetraeders rekursiv wiederholt, sodass dann ungefähr so etwas entsteht:

Es entsteht eigentlich eine etwas andere Form, die allerdings nicht sehr interessant anzusehen ist, nämlich ein Tetraeder, der in viele kleine Tetraeder zerlegt ist. Damit der strenge Tetraeder etwas aufgelockert wird, habe ich die neuen Tetraeder immer um 70% skaliert. Es sind also keine Tetraeder mehr, sondern, je tiefer die Rekursion geht, immer schiefere Pyramiden.

Außerdem habe ich nicht mit nur einem Dreieck begonnen, sondern mit einem Tetraeder, sodass ein Körper ensteht, ähnlich wie wenn man in 2D mit dem Dreieck beginnt. Bei 6 Rekursionsschritten ergeben sich dann 66*4 = 186 624 Dreiecke. Die werden dann von Processing z.B. mit 7%iger Transparenz gerendert, damit es etwas schöner aussieht und so kann dann dieses Video entstehen:


Interessant ist eigentlich auch, dass der Rest, der vom ursprünglichen Dreieck bleibt, wenn man die ganzen Tetraeder heraus nimmt, genau dem Sierpinski-Dreieck entspricht. So sieht der Code aus:

fraqTriang trs[]=new fraqTriang[4];

void setup(){
  size(640, 480, P3D);
  noStroke();
  fill(150,150,150,20);
  int bigrad=200;
  int req=6;
  
  PVector A=new PVector(-bigrad,0,0);
  PVector B=new PVector(bigrad/2,0,-173.21);
  PVector C=new PVector(bigrad/2,0,173.21);
  PVector D=new PVector(0,-bigrad*(sqrt(6)/3),0);
  
  trs[0]=new fraqTriang(A,B,C,req);
  trs[1]=new fraqTriang(A,D,B,req);
  trs[2]=new fraqTriang(A,C,D,req);
  trs[3]=new fraqTriang(B,D,C,req);
}


void draw(){
  background(255);
  lights();
  
  float winkel=(mouseX/float(width))*TWO_PI;
  float xpos=cos(winkel);
  float ypos=sin(winkel);
  float radius=300.000;
  camera(xpos*radius, mouseY, ypos*radius, // eyeX, eyeY, eyeZ
         0.0, -50.0, 0.0, // centerX, centerY, centerZ
         0.0, -1.0, 0.0); // upX, upY, upZ
      
  for (int i=0;i<trs.length;i++) {
    trs[i].display();
  }
  //saveFrame("frames/koch3d-####.png"); //uncomment to record
}

class fraqTriang{
  PVector PointA;
  PVector PointB;
  PVector PointC;
  fraqTriang recTris[]=new fraqTriang[6];
  int rec;
  float scaling;
  
  fraqTriang(PVector A,PVector B,PVector C, int recursion){
    scaling=0.7;
    PointA=A;
    PointB=B;
    PointC=C;
    rec=recursion;
    applyRecursion ();
  }
    
  void applyRecursion () {
    if (rec!=0) {
      PVector PointAB2=PVector.add(PointA,PointB);
      PointAB2.div(2);
      PVector PointAC2=PVector.add(PointA,PointC);
      PointAC2.div(2);
      PVector PointBC2=PVector.add(PointB,PointC);
      PointBC2.div(2);
      
      PVector PointZ=PVector.add(PointA,PointB);
      PointZ.add(PointC);
      PointZ.div(3);
      PVector PointAB=PVector.sub(PointA,PointB);
      PVector PointAC=PVector.sub(PointA,PointC);
      PVector PointH=PointAB.cross(PointAC);
      PointH.normalize();
      PVector PointAAB2=PVector.sub(PointA,PointAB2);
      float a=PointAAB2.mag();
      float pheight=a*(sqrt(6)/3)*scaling;
      PointH.mult(-pheight);
      PVector PointZH=PVector.add(PointZ,PointH);
      
      recTris[0]=new fraqTriang(PointA,PointAB2,PointAC2,rec-1);
      recTris[1]=new fraqTriang(PointB,PointBC2,PointAB2,rec-1);
      recTris[2]=new fraqTriang(PointC,PointAC2,PointBC2,rec-1);
      
      recTris[3]=new fraqTriang(PointZH,PointAC2,PointAB2,rec-1);
      recTris[4]=new fraqTriang(PointZH,PointAB2,PointBC2,rec-1);
      recTris[5]=new fraqTriang(PointZH,PointBC2,PointAC2,rec-1);
    }
  }  
  
  void display () {
    if (rec==0) {
      beginShape();
      vertex(PointA.x, PointA.y ,PointA.z);
      vertex(PointB.x, PointB.y ,PointB.z);
      vertex(PointC.x, PointC.y ,PointC.z);
      endShape(CLOSE);
    } else {
      for (int i=0; i<recTris.length;i++) {
        recTris[i].display();
      }
    }
  }
  
}

Man sieht dem Code an, wie schnell man mit Processing Graphiken erstellen kann, ohne sich mit komplizierteren APIs herumzuschlagen. Durch die vielen Beispiele, die Processing beiliegen und die übersichtliche API-Dokumentation kann man innerhalb von kurzer Zeit schon recht hübsche Ergebnisse erzielen. Viel Synatax muss man auch nicht lernen, da die Processing-Synatx mehr oder weniger der von Java entspricht.

Kommentare: keine

Shortlinks implementiert

22.05.2009, 20:09

Da mein Domainname doch recht lang zu tippen ist, und sich für twitter sowieso kurze URLs gut eigenen, habe ich jetzt auf dieser Seite die meisten Seiten mit kurz-URLs ausgerüstet. So kann man jetzt z.B. mit meinem ShortURL Auto-Discovery Twitter Bookmarklet ohne Probleme Links auf diese Seite posten und man muss nur noch 1-co.de in die Adressleiste tippen, um auf die Startseite zu kommen.

Die Shortlinks werden auf den entsprechenden Seiten mit dem HTML-Tag <link rel="shortlink" href="http://1-co.de/bj" /> und mit dem HTTP-Header Link: <http://1-co.de/bj>; rel=shortlink ausgewiesen.

Hauptsächlich möglich wird das durch ein paar manuelle Einträge in der .htaccess und durch diese zwei bzw. vier netten Helfer-Funktionen (PHP), die Zahlen (int) in Zeichenfolgen (Strings) umwandeln, wodurch sie rund 20-40% kürzer werden:

function toAlphaNumber($num){
  $anum = '';
  $BASE=62;
  while ($num>=1) {
    $x=$num%$BASE;
    $anum=chr2($x).$anum;
    $num=floor($num/$BASE);
  }
  return $anum;
}
function fromAlphaNumber($str){
  $BASE=62;
  $num=0;
  for ($i=0,$len=strlen($str);$i<$len;$i++) {
    $num+=uchr2($str{$i})*(pow($BASE,($len-1-$i)));
  }
  return $num;
}
function chr2($i) {
  $i+=48;
  if ($i>57) $i+=7;
  if ($i>90) $i+=6;
  if ($i>122) throw new Exception('Too high');
  $c=chr($i);
  return $c;
}
function uchr2($c){
  $i=ord($c);
  if ($i>122) throw new Exception('Too high');
  if ($i>90) $i-=6;
  if ($i>57) $i-=7;
  $i-=48;
  return $i;
}

In der .htaccess:

#manual shortening
RewriteRule ^b$ http://bernhardhaeussner.de/blog [R=301,L]
# [...]

#call a php script that redirects to the right blog post
RewriteRule ^b/([A-Za-z0-9]+)$ blogentry.php?encid=$1 [L]

Jetzt bin ich ja mal gespannt, wie viele Leute meine Posts twittern...

Für Wordpress-User (Update 2009-06-23)

Wer sich mit nichts herum ärgern will und ein ausgereiftes und einfach konfigurierbares Plugin sucht, ist mit dem Plugin Twitter Friendly Links (empfohlen von eins78) gut aufgehoben.

Für Wordpress-User & Bastler (Update 2009-06-20)

Auf Anfrage von eins78 hier noch drei Ticks für Wordpress-Blogs: Theoretisch können auch Worpress-Autoren einfach das Bookmarklet ins HTML-Markup der Seite setzten, es ist ja ein ganz normaler Link. Allerdings funktioniert es nicht ohne Javascript und es gibt folgende elegante Lösung:

Empfehlenswerter und fast genauso einfach ist es, dieses Plugin zu benutzen: Es kümmert sich nicht nur um die Erstellung von kurz-URLs und den entsprechenden Link-Tag im <head>-Bereich: Es erstellt u.a. eine globale Variable $shortlink_url in der die kurze URL gespeichert ist. Dann muss man nur noch im Template-Ordner wp-content/themes/(templatename)/ in der (index.php) folgendes in das Template setzen:

<?php if ( isset($shortlink_url) && $shortlink_url!='' ): ?>
  <a
   href="http://twitter.com/home/?status=check+out+<?php echo $shortlink_url;?>"
   rel="nofollow shortlink"
  >
  tweet this
  </a>
<?php endif; ?>

Ich habe es probeweise im default-Template direkt in das <small> gesetzt, in dem auch Datum und Autor stehen, dann wird es klein unter der Überschrift angezeigt. Die Darstellung des Links lässt sich natürlich noch anpassen. Nachteil an dem Plugin ist, dass die Weiterleitung nicht auf Anhieb funktioniert. Man müsste erst ungefähr so etwas in die .htaccess schreiben:

RewriteRule ^([0-9]+)$ ?p=$1 [R=301,L]

Eine Lösung ganz ohne Plugin hat Thomas Scholz veröffentlicht. Sie „schont die Optionstabelle und erleichtert individuelle Anpassungen“. Allerdings enthalten die Kurzlinks ?p=, weshalb die URLs nicht ganz so schön werden.

Kommentare: 7 Einträge

Wellen mit PHP rendern

30.04.2009, 19:52

Da ich heute mal wieder etwas Zeit zum Programmieren hatte (bzw. zum was-ich-will-Programmieren) habe ich unseren aktuellen Physik-Stoff visualisiert und zwar mit PHP und GD.

Ich habe ja schon vorher ein wenig mit SVG herumexperimentiert. Das war allerdings alles etwas krum und schief und ganz ohne Mathematik per Hand zusammengebastelt:


interference

Jetzt musste natürlich ein Algorithmus her. Eigentlich sind es nur 2 Klassen, die festlegen, wie eine Welle aussieht und was passiert, wenn sie von einem Zentrum ausgeht. Und zwar werden zyklische Wellenfronten von verschiedenen Zentren aus übereinandergelegt. Schwer zu erklären, einfacher im PHP-Code zu sehen:

class Wave {
  function __construct($length,$amplitude) {
    $this->length=$length;
    $this->amplitude=$amplitude;
  }
  function getPhaseAtLength($s) {
    $phase=($s%$this->length)/$this->length;
    $phaseWithDelta=fmod($phase+(isset($this->phase)?$this->phase:0)+1,2)-1;
    return $phaseWithDelta;
  }
  function getAmplitudeAtLength($s) { //sinuswelle
    $A=sin(deg2rad($this->getPhaseAtLength($s)*360))*$this->amplitude;
    return $A;
  }
  function setPhase($phase) {
    $this->phase=$phase;
    return $this;
  }
}

class Wavecenter {
  function __construct(Wave $wave,Point $center) {
    $this->wave=$wave;
    $this->center=$center;
  }
  function getAmplitudeAtPoint(Point $point) {
    $distance=$this->center->getDistance($point);
    $amp=$this->wave->getAmplitudeAtLength($distance);
    return $amp;
  }
}

Und mit ein bisschen anderem Code, der das ganze Visualisiert, entsteht dann sowas, wie die roten Wellen oben.

Das erste ist natürlich keine Sinuswelle: Am Anfang hat meine Point::getDistance() nicht funktioniert (^ statt pow()), so dass diese seltsame Figur entstanden ist. Interessant ist, dass man bereits zwei überlagerte Wellen sieht (daher die Symmetrie), diese jedoch seltsam deformiert sind.

Da ich gerade noch eine Phasenverschiebung dazu gezimmert habe, kann ich die Wellen auch noch animieren, also nicht nur in der Position des Mittelpunkts, sondern sie auch wandern lassen. Das sieht dann so aus:

Als kleinen Nachtrag noch ein paar Überlagerung einer Welle und anderen mit kleinerer Wellenlänge, wobei die Wellenlängen in (anfangs) kleinen ganzzahligen Verhältnissen stehen. Daher kann man sie auch recht leicht in der Musik finden. Die oberste Reihe wäre demnach das Schallbild, wenn man 1, 2, und 3 mal den selben Ton spielt, nur eben in der anderen Oktave. Das hört man normalerweise recht einfach, aber beim Sehen ist es etwas anders:

Jetzt wäre es natürlich irgendwie cool, auch einzelne Wellen irgendwie umher wandern zu lassen, um Doppler-Effekt und Reflexion etc. zu zeigen, aber da wären etwas kompliziertere Models nötig.

Nachtrag 26. Mai 2009: OpenGL

Da ich vor kurzem begonnen habe mit Processing Grafiken zu basteln, habe ich Processing auch gleich mal für das Wellen-Darstellen benutzt. Und das funktioniert sehr gut: Processing bietet die Grundlagen, sodass man leicht eine Welle, die von einem Zentrum ausgeht rendern kann. Das macht man dann z.B. mit 10 Frames, immer mit leichter Phasenverschiebung. Das könnte man dann einfach animieren. Wesentlich ansehnlicher ist es aber, wenn man die gerenderte Welle als animierte Textur in eine OpenGL-Szene mit additiver Überblendung einsetzt. Dann entstehen nämlich die oben gezeigten Bilder in realtime. Abgesehen vom anfänglichen Rendern und dem Laden in den Graphikspeicher der 10 2000x2000 Pixel Texturen. Screenshot:

Vor allem wenn man mehr Wellenzentren man hat, übernimmt OpenGL viele Berechnungen, weshalb man die Wellenzentren ohne Wartezeiten einfach mit der Maus verschieben kann.

Kommentare: keine
 
Χρόνογραφ
© 2008-2017 by Bernhard Häussner - Impressum - Login
Kurz-Link zur Homepage: http://1.co.de/