2014-12-08 4 views
11

ich Three.js bin mit Punkten auf einer Kugel zu schaffen, ähnlich den periodic table of elements exampleunregelmäßige Kreise auf der Oberfläche einer Kugel Verpackung

Meines Datensatz ist ein Kreis von unregelmäßiger Größe, und ich wünsche gleichmäßig sie verteilen um die Oberfläche einer Kugel. Nach vielen Stunden Suche im Internet, merke ich, dass viel härter ist als es klingt.

Hier sind Beispiele für diese Idee in Aktion:

vimeo

pic

circlePack java applet

Kann mir jemand helfen zum Auffinden eines Algorithmus in die Richtung, die mir erlauben, zu tun Dies? Das Packungsverhältnis muss nicht sehr hoch sein und es wäre idealerweise etwas schneller und einfacher in Javascript zum Rendern in THREE.js (Kartesisch oder Koordinatensystem) zu berechnen. Effizienz ist hier der Schlüssel.

Edit: Kreisradien können sehr unterschiedlich sein. Hier ist ein Beispiel mit dem Periodensystem-Code: example

+2

Worauf möchten Sie optimieren? IE: Kleinste Kugel für alle Kreise oder die Anzahl der Kreise, die auf eine Kugel mit bestimmter Größe passen oder was? In Bezug auf diese Frage, was meinst du mit "gleichmäßig verteilen"? – Nuclearman

+0

werfen Sie einen Blick auf die Quelle für diese Seite - könnte Ihnen eine Idee oder zwei geben; http://www.engineeringtoolbox.com/kleinere-kreise-in-larger-circle-d_1849.html – mike510a

Antwort

4

Hier ist etwas, auf dem Sie vielleicht aufbauen können. Es wird Ihre Kugeln zufällig entlang einer Kugel verteilen. Später werden wir über diesen Startpunkt iterieren, um eine gleichmäßige Verteilung zu erhalten.

//random point on sphere of radius R 
var sphereCenters = [] 
var numSpheres = 100; 
for(var i = 0; i < numSpheres; i++) { 
    var R = 1.0; 
    var vec = new THREE.Vector3(Math.random(), Math.random(), Math.random()).normalize(); 
    var sphereCenter = new THREE.Vector3().copy(vec).multiplyScalar(R); 
    sphereCenter.radius = Math.random() * 5; // RANDOM SPHERE SIZE, plug in your sizes here 
    sphereCenters.push(sphereCenter); 
    //Create a THREE.js sphere at sphereCenter 
    ... 

} 

Dann den Code unten ein paar Mal laufen effizient die Kugeln zu packen:

for(var i = 0; i < sphereCenters.length; i++) { 
    for(var j = 0; j < sphereCenters.length; j++) { 
     if(i === j) continue; 
     //calculate the distance between sphereCenters[i] and sphereCenters[j] 
     var dist = new THREE.Vector3().copy(sphereCenters[i]).sub(sphereCenters[j]); 
     if(dist.length() < sphereSize) { 
      //move the center of this sphere to to compensate 
      //how far do we have to move? 
      var mDist = sphereSize - dist.length(); 
      //perturb the sphere in direction of dist magnitude mDist 
      var mVec = new THREE.Vector3().copy(dist).normalize(); 
      mVec.multiplyScalar(mDist); 
      //offset the actual sphere 
      sphereCenters[i].add(mVec).normalize().multiplyScalar(R); 

     } 
    } 
} 

der zweite Abschnitt Ausführen einer Anzahl von Malen wird „konvergieren“ auf die Lösung, die Sie suchen. Sie müssen wählen, wie oft es ausgeführt werden soll, um den besten Kompromiss zwischen Geschwindigkeit und Genauigkeit zu finden.

Aktualisiert für Genauigkeit

-1

Sie können den gleichen Code wie im Periodensystem der Elemente verwenden. Die Rechtecke berühren sich nicht, so dass Sie mit Kreisen denselben Effekt erzielen können, indem Sie praktisch denselben Code verwenden. Hier

ist der Code, den sie haben:

  var vector = new THREE.Vector3(); 

      for (var i = 0, l = objects.length; i < l; i ++) { 

       var phi = Math.acos(-1 + (2 * i)/l); 
       var theta = Math.sqrt(l * Math.PI) * phi; 

       var object = new THREE.Object3D(); 

       object.position.x = 800 * Math.cos(theta) * Math.sin(phi); 
       object.position.y = 800 * Math.sin(theta) * Math.sin(phi); 
       object.position.z = 800 * Math.cos(phi); 

       vector.copy(object.position).multiplyScalar(2); 

       object.lookAt(vector); 

       targets.sphere.push(object); 

      } 
+0

Ich habe ein paar Tests mit dieser Methode durchgeführt und es bricht mit großen Diskrepanzen von vales: dh. Kreise so wenig wie 10 und so hoch wie 100. – Jared

+0

Ich fügte einen Screenshot hinzu, falls Sie unregelmäßige Kreise sehen wollten. IMO sieht es nicht gut aus und ich suche nach einer besseren Verteilung. – Jared

+1

oh, ich habe den Teil vermisst, dass sie unterschiedliche Radien haben .. –

6

Hier ist eine Methode, um zu versuchen: eine iterative Suche eine simulierte Abstoßungskraft verwendet wird.

Algorithm

zuerst die Daten durch die Anordnung der Kreise über die Oberfläche in jeder Art von Algorithmus eingestellt initialisieren. Dies ist nur für die Initialisierung, also muss es nicht großartig sein. Der Periodensystemcode wird gut funktionieren. Weisen Sie jedem Kreis eine "Masse" zu, indem Sie seinen Radius als Massenwert verwenden.

Jetzt beginnen Sie die Iteration, um auf eine Lösung zu konvergieren. Führen Sie für jeden Durchgang durch die Hauptschleife Folgendes aus:

  1. Berechnen Sie die Abstoßungskräfte für jeden Kreis. Modellieren Sie Ihre Abstoßungskraft nach der Formel für die Gravitationskraft mit zwei Anpassungen: (a) Objekte sollten weggeschoben werden voneinander, nicht zueinander hingezogen, und (b) müssen Sie die "Kraftkonstante" zwicken Wert entsprechend der Größe Ihres Modells. Abhängig von Ihrer mathematischen Fähigkeit können Sie während der Planung einen guten konstanten Wert berechnen. Sonst experimentieren Sie einfach ein wenig und Sie werden einen guten Wert finden.

  2. Nach der Berechnung der Gesamtkräfte auf jedem Kreis (bitte schauen Sie sich das N-Körper-Problem an, wenn Sie nicht sicher sind, wie dies zu tun ist), bewegen Sie jeden Kreis entlang des Vektors seiner gesamten berechneten Kraft mit der Länge von der Vektor als die Entfernung zu bewegen. An dieser Stelle müssen Sie möglicherweise den Wert für die Kraftkonstante anpassen. Zuerst werden Bewegungen mit einer Länge von weniger als 5% des Radius der Kugel gewünscht.

  3. Die Bewegungen in Schritt 2 haben die Kreise von der Oberfläche der Kugel weggeschoben (weil sie sich gegenseitig abstoßen). Bewegen Sie nun jeden Kreis zurück zur Kugeloberfläche, in Richtung zum Mittelpunkt der Kugel.

  4. Berechnen Sie für jeden Kreis den Abstand von der alten Position des Kreises zu seiner neuen Position. Die größte bewegte Strecke ist die Bewegungslänge für diese Iteration in der Hauptschleife.

Fahren Sie eine Weile mit der Iteration durch die Hauptschleife fort. Im Laufe der Zeit sollte die Bewegungslänge immer kleiner werden, wenn sich die relativen Positionen der Kreise zu einer Anordnung stabilisieren, die Ihren Kriterien entspricht. Verlasse die Schleife, wenn die Bewegungslänge unter einen sehr kleinen Wert fällt.

Tweaking

Sie können feststellen, dass Sie die Kraftberechnung zu optimieren, den Algorithmus zu bekommen auf einer Lösung zu konvergieren. Wie Sie optimieren, hängt von der Art des Ergebnisses ab, nach dem Sie suchen. Beginne damit, die Kraftkonstante zu optimieren. Wenn das nicht funktioniert, müssen Sie möglicherweise die Massenwerte nach oben oder unten ändern. Oder vielleicht ändern Sie den Exponenten des Radius in der Kraftberechnung. Zum Beispiel, statt dies:

f = (k * m[i] * m[j])/(r * r); 

Sie könnten versuchen, diese:

f = (k * m[i] * m[j])/pow(r, p); 

Dann können Sie mit unterschiedlichen Werten von p experimentieren.

Sie können auch mit verschiedenen Algorithmen für die anfängliche Verteilung experimentieren.

Die Anzahl der Versuche hängt von Ihren Entwurfszielen ab.

+0

Danke für diese Erklärung dieser Methode. Die Methodik gilt nur für drei.js/javascript und ist ein großartiges Beispiel für jeden, der Kreispackungen versucht – Jared

Verwandte Themen