Abprallen zweier Bälle (Kreise)

  • VB.NET

Es gibt 29 Antworten in diesem Thema. Der letzte Beitrag () ist von RodFromGermany.

    Abprallen zweier Bälle (Kreise)

    Hey Leute, ich brauche mal euer mathematisches / physikales Wissen, ich verzweifel hier langsam.

    Es nur darum, zwei Kreise gleicher Größe von einander Abprallen zu lassen. Die Kollision zu überprüfen ist kein Problem, aber die neuen Geschwindigkeitsvektoren sind schwer.
    Es handelt sich dabei, wenn ich es richtig verstanden habe, um den nicht zentralen, elastischen Stoß. Und bisher habe ich folgenden Ansatz (ist nur syntaktisch übersetzt aus Ruby, deswegen ist das ganze etwas weniger komplex (keine Properties etc.):

    Visual Basic-Quellcode

    1. Sub vomBallAbprallen(einB As Ball)
    2. Dim dx As Integer = self.get_MitteX - einB.get_MitteX
    3. Dim dy As Integer = self.get_MitteY - einB.get_MitteY
    4. Dim abstand As Double = Math.Sqrt(dx^2 + dy^2)
    5. If abstand <= (self.get_r + einB.get_r) then
    6. 'Kollidieren (self = 1, einB = 2)
    7. 'Nicht zentraler, elastischer Stoß
    8. ' dx / dy = ux / uy (Vektor der neuen Geschwindigkeit und Vektor zwischen den Mittelpunkten zeigen in die gleiche Richtung)
    9. ' vx1^2 + vx1^2 = ux2^2 + uy2^2 (Betrag der Geschwindigkeit 1 vorher = Betrag der Geschwindigkeit 2 nachher)
    10. Dim vx1 As Double = self.get_vx()
    11. Dim vy1 As Double = self.get_vy()
    12. Dim vx2 As Double = einB.get_vx()
    13. Dim vy2 As Double = einB.get_vy()
    14. Dim ux1 As Double = (Math.Sqrt(vx1^2 + vy1^2) * dx)/(Math.Sqrt(dx^2 + dy^2))
    15. Dim uy2 As Double = (Math.Sqrt(vx1^2 + vy1^2) * dy)/(Math.Sqrt(dx^2 + dy^2))
    16. Dim ux1 As Double = -(Math.Sqrt(vx2^2 + vy2^2) * dx)/(Math.Sqrt(dx^2 + dy^2))
    17. Dim uy2 As Double = -(Math.Sqrt(vx2^2 + vy2^2) * dy)/(Math.Sqrt(dx^2 + dy^2)
    18. 'Geschwindigkeiten setzen
    19. Me.set_vx(ux1)
    20. Me.set_vy(uy1)
    21. einB.set_vx(ux2)
    22. einB.set_vy(uy2)
    23. End If
    24. End Sub


    Sieht auch schon garnicht sooo schlecht aus, ist aber falsch. Auf die Formeln bin ich mittels Umstellung der beiden Gleichungen der Formeln darüber gekommen. Habt ihr eine Idee ?
    »There's no need to "teach" atheism. It's the natural result of education without indoctrination.« — Ricky Gervais
    Bau dir als aller erstes mal ne ordentliche Vector2-Klasse, so kannst du nicht arbeiten.
    Bei zwei Kreisen ist es noch relativ einfach, weil du einfach nach dem Prinzip Einfallswinkel = Ausfallswinkel gehen kannst. Im Zeitpunkt des Aufpralles kannst du die beiden Kreismittelpunkte mit einer Linie verbinden. Fällst du die Normale/das Loot an genau der Stelle, an der sich die Kreise berühren, so hast du die imaginäre Wand, an die beide Kreise aufprallen (sind die Kreise gleich groß, dann ist das genau die Mittelsenkrechte). Nun musst du den Winkel zwischen Bewegungsvektor der Kreise und der Wand berechnen. Der neue Bewegungsvektor ist dann genau der Vektor, mit dem selben Betrag des Eingangsvektors, aber eben genau um den negativen Winkel zur Wand geneigt.
    @LaMiy , @Artentus

    ThePlexian schrieb:

    (ist nur syntaktisch übersetzt aus Ruby, deswegen ist das ganze etwas weniger komplex (keine Properties etc.)


    @Artentus Könnte ich dann auch die Geschwindigkeitsvektoren in ein neues Koordiatensystem translatieren (?) mit Matrizen und dann rechnen ? Oder ist das zu kompliziert ?
    »There's no need to "teach" atheism. It's the natural result of education without indoctrination.« — Ricky Gervais

    ThePlexian schrieb:

    Oder ist das zu kompliziert ?
    Was Du brauchst ist Elementarphysik.
    Du hast 2 Erhaltungssätze, die musst Du erfüllen, der Rest ist "Elementarmathematik".
    1. Energieerhaltung: m1 / 2 * v12 + m2 / 2 * v22 = konstant. Gleiche Kreise => gleiche Masse,
      bedeutet: v12(vorher) + v22(vorher) = v12(nachher) + v22(nachher)
    2. Impulserhaltung: m1 * v1 + m2 * v2 = konstant. Gleiche Kreise => gleiche Masse,
      bedeutet: v1(vorher) + v2(vorher) = v1(nachher) + v2(nachher)
      Hier ist der v der Vektor mit den 2 oder 3 Komponenten.
    Rechne das ganze zuerst auf dem Papier aus, damit Du ein Gefühl für die Formeln bekommst, danach gieße es in Code.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    RodFromGermany schrieb:

    danach gieße es in Code.

    Ein mittlerweile typischer Satz für dich ;)

    Ich kenne mich mit dem Energieerhaltungssatz und dem Ipulserhaltungssatz aus, und mir ist ebenfalls bewusst, wie die resultierenden Formels auszusehen haben. Probiert habe ich das ganze auch schon mal, nur ist gelten diese Formeln für den zentral elastischen Stoß, und zwei Kreise prallen nicht Zentral ab wie ich feststellen musste. Denn die Formel für Geschwindigkeit 1 nach dem Stoß ist u1 = ((m1 - m2) * v1 + 2 * m2 * v2) / (m1 + m2), welche bis auf v2 gekürzt wird bei gleichen Massen. Funktioniert vllt für Beträge, aber bei Vektoren nicht (es sei denn, die Vektoren haben die gleiche Steigung wie eine Gerade durch die Mittelpunkte). Trotzdem danke :)

    @Artentus :
    Ich habe mir nochmal Gedanken gemacht, und deine Theorie geht leider nicht so einfach (hatte ich auch schon mal getestet). Stelle dir folgendes vor: Ball 1 und Ball 2 kollidieren mit einer horizontalen Tangente (Ball 1 oben). Dabei hat Ball 1 einen horizontalen Vektor und Ball 2 einen vertikalen (positiv). Nun würde nach deiner Theorie Ball 2 richtig abprallen, Ball 1 aber nicht, da kein Impuls übergeben wird.

    Meine Idee: Artentus Idee beibehalten (wobei ich das erstmal mit den Winkeln hinbekommen muss (nicht das Außen- und Innenwinkel iwie vertauscht werden etc.) und etwas hinzuaddieren. Und zwar einen Vektor, welcher von der Richtung her die gleiche hat wie ein Vektor zwischen den Mittelpunkten und vom Betrag her zwischen 0 und dem Betrag des Geschwindigkeitsvektors des anderen Balls ist. Dieser Betrag müsste entweder prozentual oder mit dem Kosinus zu berechnen sein. Denn wenn der Geschwindigkeitsvektor des anderen Balls die gleiche Richtung hat wie der Mittelpunktsvektor (0°), dann wäre genau der Betrag hinzuzuaddieren (cos(0) = 1). Wenn der Geschw.-vektor aber orthogonal ist (90°), dann genau garnichts hinzuaddieren (cos(90) = 0). Nun weiß ich aber nicht, ob bei bspw. 45° 50% oder cos(45) zu nehmen ist.
    Falls ihr mich nicht versteht hänge ich noch ne Grafik an :D
    »There's no need to "teach" atheism. It's the natural result of education without indoctrination.« — Ricky Gervais

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „ThePlexian“ ()

    Hi,

    hab hier mal das für dich aus meinen Tiefen meiner Alt-Projekte rausgekramt:

    Java-Quellcode

    1. void setup() {
    2. size(500, 400);
    3. background(255);
    4. balls = new Ball[num];
    5. for (int i = 0; i < balls.length; i++) {
    6. balls[i] = new Ball(balls, i);
    7. }
    8. }
    9. int num = 4;
    10. Ball[] balls;
    11. void draw() {
    12. background(255);
    13. for (Ball b : balls) {
    14. b.applyForce(new PVector(0, 0.2)); //gravity
    15. b.collision();
    16. b.edges();
    17. b.move();
    18. b.display();
    19. }
    20. }
    21. class Ball {
    22. Ball[] others;
    23. int ballID;
    24. PVector location;
    25. PVector velocity;
    26. PVector acceleration;
    27. float mass;
    28. float massDisplayFactor;
    29. float spring;
    30. float friction = -1;
    31. float diameter;
    32. Ball(Ball[] _others, int _ballID) {
    33. ballID = _ballID;
    34. others = _others;
    35. location = new PVector(random(width), random(height/4, height-(height/4)));
    36. velocity = new PVector(0, 0);
    37. acceleration = new PVector(0, 0);
    38. mass = random(0.5, 5);
    39. massDisplayFactor = 17;
    40. diameter = mass * massDisplayFactor;
    41. spring = 0.1;
    42. }
    43. void move() {
    44. velocity.add(acceleration);
    45. location.add(velocity);
    46. acceleration.mult(0);
    47. }
    48. void applyForce(PVector force) {
    49. PVector f = PVector.div(force, mass);
    50. acceleration.add(f);
    51. }
    52. void collision() {
    53. //Kollision mit anderen Objecten
    54. for (int i = ballID+1; i < others.length; i++) {
    55. PVector d = new PVector(others[i].location.x - location.x, others[i].location.y - location.y);
    56. float defDist = sqrt(d.x*d.x + d.y*d.y);
    57. float minDist = others[i].diameter / 2 + diameter / 2;
    58. if (defDist < minDist) {
    59. float angle = atan2(d.y, d.x);
    60. PVector target = new PVector(location.x + cos(angle)*minDist, location.y + sin(angle)*minDist);
    61. PVector a = new PVector((target.x - others[i].location.x) * spring, (target.y - others[i].location.y) * spring);
    62. velocity.sub(a);
    63. others[i].velocity.add(a);
    64. }
    65. }
    66. }
    67. void edges() {
    68. //An Fenster abprallen
    69. if (location.x - diameter / 2 < 0) {
    70. location.x = diameter / 2;
    71. velocity.x *= friction;
    72. }
    73. if (location.x + diameter / 2 > width) {
    74. location.x = width - diameter / 2;
    75. velocity.x *= friction;
    76. }
    77. if (location.y - diameter / 2< 0) {
    78. location.y = diameter / 2;
    79. velocity.y *= friction;
    80. }
    81. if (location.y + diameter / 2 > height) {
    82. location.y = height - diameter / 2;
    83. velocity.y *= friction;
    84. }
    85. }
    86. void display() {
    87. //Ball anzeigen
    88. strokeWeight(3);
    89. stroke(0);
    90. fill(#0072bc, 127);
    91. ellipse(location.x, location.y, mass*massDisplayFactor, mass*massDisplayFactor);
    92. }
    93. }


    Vielleicht hilft's dir was. Musst halt nur bissl umschreiben in deine Sprache, aber der Algorithmus der benutzt wird sollte allgemein verständlich sein. Der wichtige Teil is so ab Zeile 60 (void collision())

    Link :thumbup:
    Hello World
    @Link275 : Danke schonmal! Verstehe ich auch größtenteils, nur was ist float spring und wie kommst du auf den neuen Beschleunigungsvektor (Zeile 69), also welchen mathematischen Hintergrund hat das ?
    »There's no need to "teach" atheism. It's the natural result of education without indoctrination.« — Ricky Gervais
    float spring:
    - Deklaration Zeile 33
    - Initialisierung Zeile 46

    spring ist quasi die "bounciness". Verändere doch mal "spring" in einen anderen Wert.

    Achja, um das Beispiel besser zu machen, füge unterhalb von Zeile 16 noch b.applyForce(new PVector(0.1, 0.0)); //wind. So hast immer bissl "Wind" von links.
    Ich vergaß dazuzusagen, das ist Processing-Code. Ich hab dir das Beispiel mal auf dieser Seite als Live-Preview reingestellt
    Da siehst auch gleich die Sache mit dem "Wind", die Bälle fliegen also immer bissl nach rechts.
    Aber was laber ich, lad dir Processing runter und hau den Code dort rein und probier selbst mit den Werten rum ^^


    Link :thumbup:
    Hello World
    Ich hab Processing schon ;)

    Wow das läuft echt, muss zwar noch mit dem Federn etwas probieren (die drücken sich ja richtig ein oO) aber sonst, danke !

    Nur immer noch, woher hast du diese Formeln ?
    »There's no need to "teach" atheism. It's the natural result of education without indoctrination.« — Ricky Gervais
    Glaub hatte das damals nach nem Tutorial gemacht, kann auch sein dass es in den Examples war.
    Und dann hab ich den Code Stück für Stück auseinandergenommen. Zum Schluss wollte ich das Beispiel selbst nachstellen und hab es bissl verbessert, indem ich mir die PVector Klasse zunutze gemacht hab und zusätzlich hab ich noch die Gravitation und weitere Kräfte zum einfachen hinzufügen via applyForce() realisiert. Das Beispiel mit applyForce() kommt von Daniel Shiffman (Nature of Code). Ja und am Ende hatte ich von hier und da Ideen abgeschaut und das entsprechend umgesetzt so wie ich es haben wollte :) Der Kollisionsalgorithmus selbst ist übrigens nicht von mir, den hab ich 1:1 übernommen, ich fand nicht dass Änderungen nötig waren. Gibt mehrere Ansätze hierfür (z.B. mittels dist() und den mag()-Methoden der PVector Klasse).

    Link
    Hello World

    ThePlexian schrieb:

    Ein mittlerweile typischer Satz für dich
    Nein.
    Diesen Satz hat ein Member hier in seine Signatur zitiert.
    Der Impulssatz funktioniert sehr wohl. Wenn es nicht so wäre, ware eine fundamentale Stütze der theoretischen Physik falsch und Du Kandidat auf einen Nobelpreis. :D
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @RodFromGermany : Das war nicht als Kritik gemeint, mir sind diese Worte nur direkt aufgefallen :)

    Und tut mir Leid, aber mit Vektoren kann das nicht gehen. Bei gleichen Massen und dieser Formel u1 = ((m1 - m2) * v1 + 2 * m2 * v2) / (m1 + m2) wird es zu u1 = v2

    Du kannst mir aber nicht erzählen, dass folgendes physikalisch richtig ist ^^ :

    »There's no need to "teach" atheism. It's the natural result of education without indoctrination.« — Ricky Gervais

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „ThePlexian“ ()

    Ich hab es nicht als Kritik aufgefasst. ;)

    ThePlexian schrieb:

    und dieser Formel
    Wo kommt denn die her?
    Die sieht nach der Vereinfachung einer primären Formel aus, und die gilt nur unter gewissen Randbedingungen, und die musst Du einhalten, ansonsten ist diese Formel nicht anwendbar.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    V = Geschwindikeit vorher - U = Geschwindigkeit nachher

    Energieerhaltungssatz: 1/2 * m1 * v1^2 + 1/2 * m2 * v2^2 = 1/2 * m1 * u1^2 + 1/2 * m2 * u2^2
    Impulserhaltungssatz: m1 * v1 + m2 * v2 = m1 * u1 + m2 * u2

    Zwei Gleichungen, 6 Variablen, 2 davon unbekannt --> Gleichungssystem

    Auflösen nach u1 und u2 ergibt:
    u1 = ((m1 - m2) * v1 + 2 * m2 * v2) / (m1 + m2)
    u2 = ((m2 - m1) * v2 + 2 * m1 * v1) / (m1 + m2)

    Einsetzen gleicher Werte für m1 und m2:
    u1 = v2
    u2 = v1

    Okay ?
    »There's no need to "teach" atheism. It's the natural result of education without indoctrination.« — Ricky Gervais

    ThePlexian schrieb:

    Auflösen nach u1 und u2 ergibt:
    Das sehe ich noch nicht. Hast Du ggf. die Vektoren durch ihre Beträge ersetzt?
    Kannst Du diese Schritte mal bitte vereinzeln (Skizze in Paint)?
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Genau das meine ich doch :)

    Quellcode

    1. u1 = ((m1 - m2) * v1 + 2 * m2 * v2) / (m1 + m2) |m1 = m2 = 1
    2. u1 = ((1 - 1) * v1 + 2 * 1 * v2) / (1 + 1)
    3. u1 = (0 * v1 + 2 * v2) / 2
    4. u1 = 2 * v2 / 2
    5. u1 = v2

    Gleiches für u2.

    Und diese Formeln gelten für Beträge. Nicht aber für Vektoren wie es scheint, dass ist ja das Problem.

    ThePlexian schrieb:


    Funktioniert vllt für Beträge, aber bei Vektoren nicht (es sei denn, die Vektoren haben die gleiche Steigung wie eine Gerade durch die Mittelpunkte). Trotzdem danke :)
    »There's no need to "teach" atheism. It's the natural result of education without indoctrination.« — Ricky Gervais

    ThePlexian schrieb:

    Gleiches für u2.
    Frau Googel sagt mir dies hier:
    Elastischer Stoß.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!