Kollision zweier Kugeln (2D): Unterschied zwischen den Versionen
Kowa (Diskussion | Beiträge) |
Kowa (Diskussion | Beiträge) |
||
| Zeile 49: | Zeile 49: | ||
<source lang="javascript"> | <source lang="javascript"> | ||
function collisionBallBall(p_b1, p_b2) | function collisionBallBall(p_b1, p_b2) | ||
{ | { // l_n: Normalenvektor (Verbindung zwischen den beiden Kugelnn) | ||
let l_nx = p_b2.x - p_b1.x; | |||
let l_ny = p_b2.y - p_b1.y; | |||
// Abstand der beiden Kugeln | // Abstand der beiden Kugeln | ||
let l_dist = Math.sqrt( l_nx * l_nx + l_ny * l_ny ); | |||
// Die Kugeln dürfen sich nicht an derselben Stelle befinden, | // Die Kugeln dürfen sich nicht an derselben Stelle befinden, | ||
| Zeile 63: | Zeile 62: | ||
// neue Kugel genau an der Stelle einer existenten Kugel erstellt wird). | // neue Kugel genau an der Stelle einer existenten Kugel erstellt wird). | ||
if (l_dist < EPSILON) | if (l_dist < EPSILON) | ||
{ | { p_b2.x = p_b2.x+ p_b2.r; | ||
l_nx += p_b2.r; | l_nx += p_b2.r; | ||
l_dist = Math.sqrt( l_nx * l_nx + l_ny * l_ny ); | l_dist = Math.sqrt( l_nx * l_nx + l_ny * l_ny ); | ||
| Zeile 72: | Zeile 70: | ||
// der Radien beider Kugeln ist. | // der Radien beider Kugeln ist. | ||
if (l_dist <= p_b1.getR() + p_b2.getR()) | if (l_dist <= p_b1.getR() + p_b2.getR()) | ||
{ | { // Normalenvektor wird normalisiert: |l_n| = 1 | ||
l_nx /= l_dist; | l_nx /= l_dist; | ||
l_ny /= l_dist; | l_ny /= l_dist; | ||
//Tangentialvektor (senkrecht zu Normalenvektor, zwischen beiden Kugeln) | // Tangentialvektor (senkrecht zu Normalenvektor, zwischen beiden Kugeln) | ||
let l_tx = l_ny; | |||
let l_ty = -l_nx; | |||
// Summe der Massen beider Kugeln | // Summe der Massen beider Kugeln | ||
let l_sm1m2 = p_b1.m + p_b2.m; | |||
// Überlappung der beiden Kugeln | // Überlappung der beiden Kugeln | ||
let l_overlap = ( p_b1.r+ p_b2.r ) - l_dist; | |||
// Verschieben der beiden Kugeln entlang der Normalen, | // Verschieben der beiden Kugeln entlang der Normalen, | ||
| Zeile 103: | Zeile 100: | ||
// Ball 1: Zerlegung des Geschwindigkeitsvektors in n- und t-Anteil | // Ball 1: Zerlegung des Geschwindigkeitsvektors in n- und t-Anteil | ||
let l_sn1 = l_nx * p_b1.vx + l_ny * p_b1.vy; | |||
let l_st1 = l_tx * p_b1.vx + l_ty * p_b1.vy; | |||
let l_n1x = l_nx * l_sn1; // Normalenvektor-Anteil von p_b1.vx | |||
let l_n1y = l_ny * l_sn1; | |||
let l_t1x = l_tx * l_st1; // Tangentialvektor-Anteil von p_b1.vx | |||
let l_t1y = l_ty * l_st1; | |||
// Ball 2: Zerlegung des Geschwindigkeitsvektors in n- und t-Anteil | // Ball 2: Zerlegung des Geschwindigkeitsvektors in n- und t-Anteil | ||
let l_sn2 = l_nx * p_b2.vx + l_ny * p_b2.vy; | |||
let l_st2 = l_tx * p_b2.vx + l_ty * p_b2.vy; | |||
let l_n2x = l_nx * l_sn2; // Normalenvektor-Anteil von p_b2.vx | |||
let l_n2y = l_ny * l_sn2; | |||
let l_t2x = l_tx * l_st2; // Tangentialvektor-Anteil von p_b2.vx | |||
let l_t2y = l_ty * l_st2; | |||
// Der Impulserhaltungssatz | // Der Impulserhaltungssatz | ||
| Zeile 138: | Zeile 135: | ||
// Bewegungsrichtungen werden unverändert übernommen. | // Bewegungsrichtungen werden unverändert übernommen. | ||
let l_vspx = 2*(p_b1.m*l_n1x+p_b2.m*l_n2x)/l_sm1m2; | |||
let l_vspy = 2*(p_b1.m*l_n1y+p_b2.m*l_n2y)/l_sm1m2; | |||
p_b1.vx = l_vspx - l_n1x + l_t1x; | p_b1.vx = l_vspx - l_n1x + l_t1x; | ||
| Zeile 148: | Zeile 145: | ||
//// Alternative Berechnung: | //// Alternative Berechnung: | ||
// Differenz der Massen beide Kugeln | // Differenz der Massen beide Kugeln | ||
// | // let l_dm2m1 = p_b2.m - p_b1.m; | ||
// p_b1.vx = (l_n2x*p_b2.m*2-l_n1x*l_dm2m1)/l_sm1m2 + l_t1x; | // p_b1.vx = (l_n2x*p_b2.m*2-l_n1x*l_dm2m1)/l_sm1m2 + l_t1x; | ||
// p_b1.vy = (l_n2y*p_b2.m*2-l_n1y*l_dm2m1)/l_sm1m2 + l_t1y; | // p_b1.vy = (l_n2y*p_b2.m*2-l_n1y*l_dm2m1)/l_sm1m2 + l_t1y; | ||
Version vom 23. November 2018, 12:00 Uhr
Dieser Artikel wird derzeit von einem Autor gründlich bearbeitet. Die Inhalte sind daher evtl. noch inkonsistent.
Dieser Artikel erfüllt die GlossarWiki-Qualitätsanforderungen nur teilweise:
| Korrektheit: 1 (nur rudimäntär überprüft) |
Umfang: 1 (zu gering) |
Quellenangaben: 1 (fehlen großteils) |
Quellenarten: 3 (gut) |
Konformität: 5 (ausgezeichnet) |
Grundannahmen
Es sei ein zweidimensionales Ball-Objekt b gegeben, das folgende Attribute habe:
x,y: Position (Einheit: Pixel)vx,vy: Geschwindigkeit in $x$- und $y$-Richtung (Einheit: Pixel/s)r: Radius (Einheit: Pixel)m: Masse (die Einheit ist irrelevant, sie muss nur für alle Bälle dieselbe sein)
Die Frequenz der Neuberechnung der Positionen aller im System vorhandener Bälle sei f,
d. h., die Positionen werden f mal pro Sekunde neuberechnet. Wenn es zu keiner Kollision kommt, wird
der Ball um vx/f bzw. vy/f Pixel in
$x$- bzw. $y$-Richtung verschoben:
b.x += b.vx/f;
b.y += b.vy/f;
Je höher die Frequent f ist, desto genauer wird die Bewegungsbahn der Bälle simuliert.
Im Folgenden seinen $s_1 = (s_{1x},s_{1y})$ und $s_2 = (s_{2x},s_{2y})$ die Startpositionen zweier Balle und $v_1 = (v_{1x},v_{1y})$ und $v_2 = (v_{2x},v_{2y})$ die zugehörigen Geschwindigkeitsvektoren.
Es gilt also, dass sich die beiden Bälle zu Zeitpunkt $t_0$ an den Positionen $s_1$ und $s_2$ befinden. Eine Sekunde später, d. h. zum Zeitpunkt $t_0+1$ befinden sich sich an den Positionen $s_1+v_1$ und $s_2+v_2$, sofern sie nicht kollidieren. Wenn die Neuberechnung mit einer Frequenz $f$ Hz erfolgt, d. h., wenn die Periodendauer $T = 1/f$ beträgt, dann befinden sich die Bälle nach der Berechnung an den Positionen $s_1+Tv_1$ und $s_2+Tv_2$, sofern sie nicht kollidieren.
In Folgenden wird stets der Fall $t=1$ angenommen. Alle Aussagen, die für einen beliebigen Geschwindigkeitsvektor $v$ gelten, gelten dann natürlich auch für $v' := tv$.
A-posteriori-Kollisionserkennung von zwei Kugeln
function collisionBallBall(p_b1, p_b2)
{ // l_n: Normalenvektor (Verbindung zwischen den beiden Kugelnn)
let l_nx = p_b2.x - p_b1.x;
let l_ny = p_b2.y - p_b1.y;
// Abstand der beiden Kugeln
let l_dist = Math.sqrt( l_nx * l_nx + l_ny * l_ny );
// Die Kugeln dürfen sich nicht an derselben Stelle befinden,
// weil sie sonst nicht entlang der nicht-existenten Normalen
// auseinandergezogen werden können.
// Dieser Fall sollte nur sehr selten eintreten (z.B. wenn eine
// neue Kugel genau an der Stelle einer existenten Kugel erstellt wird).
if (l_dist < EPSILON)
{ p_b2.x = p_b2.x+ p_b2.r;
l_nx += p_b2.r;
l_dist = Math.sqrt( l_nx * l_nx + l_ny * l_ny );
};
// Kugeln kollidieren, wenn der Abstand kleiner gleich der Summe
// der Radien beider Kugeln ist.
if (l_dist <= p_b1.getR() + p_b2.getR())
{ // Normalenvektor wird normalisiert: |l_n| = 1
l_nx /= l_dist;
l_ny /= l_dist;
// Tangentialvektor (senkrecht zu Normalenvektor, zwischen beiden Kugeln)
let l_tx = l_ny;
let l_ty = -l_nx;
// Summe der Massen beider Kugeln
let l_sm1m2 = p_b1.m + p_b2.m;
// Überlappung der beiden Kugeln
let l_overlap = ( p_b1.r+ p_b2.r ) - l_dist;
// Verschieben der beiden Kugeln entlang der Normalen,
// so dass sie sich nicht mehr überlappen!
p_b1.x = p_b1.x - l_nx * l_overlap * (p_b2.m/l_sm1m2) * (1+EPSILON));
p_b1.y = p_b1.y - l_ny * l_overlap * (p_b2.m/l_sm1m2) * (1+EPSILON));
p_b2.x = p_b2.x + l_nx * l_overlap * (p_b1.m/l_sm1m2) * (1+EPSILON));
p_b2.y = p_b2.y + l_ny * l_overlap * (p_b1.m/l_sm1m2) * (1+EPSILON));
// Zerlegung der Geschwindigkeitsvektoren in Normalen- und
// Tangentialanteil: v=sn*n+st*t, wobei
// v Vektor, n Normalenvektor, t Tagentialvektor und
// sn, st zwei skalare Werte sind.
// Es gilt: v*n = sn*(n*n)+st*(t*n) = sn, da t*n=0 und n*n = 1
// Es gilt: v*t = sn*(n*t)+st*(t*t) = st, da t*n=0 und t*t = 1
// Also ist: sn = v*n und st=v*t
// Ball 1: Zerlegung des Geschwindigkeitsvektors in n- und t-Anteil
let l_sn1 = l_nx * p_b1.vx + l_ny * p_b1.vy;
let l_st1 = l_tx * p_b1.vx + l_ty * p_b1.vy;
let l_n1x = l_nx * l_sn1; // Normalenvektor-Anteil von p_b1.vx
let l_n1y = l_ny * l_sn1;
let l_t1x = l_tx * l_st1; // Tangentialvektor-Anteil von p_b1.vx
let l_t1y = l_ty * l_st1;
// Ball 2: Zerlegung des Geschwindigkeitsvektors in n- und t-Anteil
let l_sn2 = l_nx * p_b2.vx + l_ny * p_b2.vy;
let l_st2 = l_tx * p_b2.vx + l_ty * p_b2.vy;
let l_n2x = l_nx * l_sn2; // Normalenvektor-Anteil von p_b2.vx
let l_n2y = l_ny * l_sn2;
let l_t2x = l_tx * l_st2; // Tangentialvektor-Anteil von p_b2.vx
let l_t2y = l_ty * l_st2;
// Der Impulserhaltungssatz
// m1*v1 + m2*v2 = m1*v1' + m2*v2'
// (wobei m1, m2 = Massen der Körper
// und v1, v2, v1', v2' die Geschwindigkeiten)
// und der Energieerhaltsungssatz
// 0,5*m1*v1² + 0,5*m2*v2² = 0,5*m1*v1'² + 0,5*m2*v2'²
// führen nach einfachen mathematischen Umformungen zu
// folgenden Beziehungen (für den eindimensionalen Fall):
// v1' = 2*(m1*v1+m2*v2)/(m1+m2) - v1
// v2' = 2*(m1*v1+m2*v2)/(m1+m2) - v2
// 2*(m1*v1+m2*v2)/(m1+m2) ist die Geschwindigkeit des
// gemeinsamen Schwerpunktes.
// Im zweidimensionalen Fall gilt, dass die Kollision entlang
// der Normalen erfolgt. Die tangentialen Anteile der der
// Bewegungsrichtungen werden unverändert übernommen.
let l_vspx = 2*(p_b1.m*l_n1x+p_b2.m*l_n2x)/l_sm1m2;
let l_vspy = 2*(p_b1.m*l_n1y+p_b2.m*l_n2y)/l_sm1m2;
p_b1.vx = l_vspx - l_n1x + l_t1x;
p_b1.vy = l_vspy - l_n1y + l_t1y;
p_b2.vy = l_vspx - l_n2x + l_t2x;
p_b2.vy = l_vspy - l_n2y + l_t2y;
//// Alternative Berechnung:
// Differenz der Massen beide Kugeln
// let l_dm2m1 = p_b2.m - p_b1.m;
// p_b1.vx = (l_n2x*p_b2.m*2-l_n1x*l_dm2m1)/l_sm1m2 + l_t1x;
// p_b1.vy = (l_n2y*p_b2.m*2-l_n1y*l_dm2m1)/l_sm1m2 + l_t1y;
// p_b2.vx = (l_n1x*p_b1.m*2+l_n2x*l_dm2m1)/l_sm1m2 + l_t2x;
// p_b2.vy =(l_n1y*p_b1.m*2+l_n2y*l_dm2m1)/l_sm1m2 + l_t2y;
}
}
A-priori-Kollisionserkennung von zwei Kugeln


Quellen
- Kowarschick (WebProg): Wolfgang Kowarschick; Vorlesung „Web-Programmierung“; Hochschule: Hochschule Augsburg; Adresse: Augsburg; Web-Link; 2024; Quellengüte: 3 (Vorlesung)
