Soal Tabrakan Bola 2d: tidak ada kekekalan energi

Saya mencoba menulis simulasi fisika sederhana di mana bola dengan jari-jari dan massa yang berbeda-beda memantul dalam lingkungan yang elastis sempurna dan tanpa gesekan. Saya menulis kode saya sendiri dengan mengikuti sumber ini: http://www.vobarian.com/collisions/2dcollisions2.pdf dan saya juga menguji kode dari sini: Ball to Ball Tabrakan - Deteksi dan Penanganan

PERTANYAAN DIEDIT

Dengan bantuan Rick Goldstein dan Ralph, kode saya berfungsi (ada kesalahan ketik..). Terima kasih banyak atas bantuan Anda. Namun saya masih bingung mengapa algoritma lain tidak bekerja untuk saya. Bola memantul ke arah yang benar, namun energi total sistem tidak pernah kekal. Kecepatannya semakin cepat hingga bola mulai berkedip dalam posisi statis di layar. Saya sebenarnya ingin menggunakan kode ini dalam program saya, karena lebih ringkas daripada yang saya tulis.

Berikut adalah algoritma fungsional yang saya tulis (walaupun saya mengambil bit pertama dari sumber lain itu). Ini ada di kelas Bubble:

public void resolveCollision(Bubble b)
{
    // get the minimum translation distance
    Vector2 delta = (position.subtract(b.position));
    float d = delta.getMagnitude();
    // minimum translation distance to push balls apart after intersecting
    Vector2 mtd = delta.multiply(((getRadius() + b.getRadius())-d)/d); 

    // resolve intersection --
    // inverse mass quantities
    float im1 = 1 / getMass(); 
    float im2 = 1 / b.getMass();

    // push-pull them apart based off their mass
    position = position.add(mtd.multiply(im1 / (im1 + im2)));
    b.position = b.position.subtract(mtd.multiply(im2 / (im1 + im2)));

    //get the unit normal and unit tanget vectors
    Vector2 uN = b.position.subtract(this.position).normalize();
    Vector2 uT = new Vector2(-uN.Y, uN.X);

    //project ball 1 & 2 's velocities onto the collision axis
    float v1n = uN.dot(this.velocity);
    float v1t = uT.dot(this.velocity);
    float v2n = uN.dot(b.velocity);
    float v2t = uT.dot(b.velocity);

    //calculate the post collision normal velocities (tangent velocities don't change)
    float v1nPost = (v1n*(this.mass-b.mass) + 2*b.mass*v2n)/(this.mass+b.mass);
    float v2nPost = (v2n*(b.mass-this.mass) + 2*this.mass*v1n)/(this.mass+b.mass);

    //convert scalar velocities to vectors
    Vector2 postV1N = uN.multiply(v1nPost);
    Vector2 postV1T = uT.multiply(v1t);
    Vector2 postV2N = uN.multiply(v2nPost);
    Vector2 postV2T = uT.multiply(v2t);

    //change the balls velocities
    this.velocity = postV1N.add(postV1T);
    b.velocity = postV2N.add(postV2T);
}

Dan inilah yang tidak berhasil

public void resolveCollision(Bubble b)
{
    // get the minimum translation distance
    Vector2 delta = (position.subtract(b.position));
    float d = delta.getMagnitude();
    // minimum translation distance to push balls apart after intersecting
    Vector2 mtd = delta.multiply(((getRadius() + b.getRadius())-d)/d); 

    // resolve intersection --
    // inverse mass quantities
    float im1 = 1 / getMass(); 
    float im2 = 1 / b.getMass();

    // push-pull them apart based off their mass
    position = position.add(mtd.multiply(im1 / (im1 + im2)));
    b.position = b.position.subtract(mtd.multiply(im2 / (im1 + im2)));

    // impact speed
    Vector2 v = (this.velocity.subtract(b.velocity));
    float vn = v.dot(mtd.normalize());

    // sphere intersecting but moving away from each other already
    if (vn > 0.0f) return;

    // collision impulse (1f is the coefficient of restitution)
    float i = (-(1.0f + 1f) * vn) / (im1 + im2);
    Vector2 impulse = mtd.multiply(i);

    // change in momentum
    this.velocity = this.velocity.add(impulse.multiply(im1));
    b.velocity = b.velocity.subtract(impulse.multiply(im2));
}

Beri tahu saya jika Anda menemukan sesuatu. Terima kasih


person Cbas    schedule 15.02.2011    source sumber


Jawaban (3)


Apakah ada kesalahan ketik pada baris yang menyetel v1nPost? Sepertinya penyebutnya seharusnya this.mass + b.mass, bukan this.mass * b.mass.

Selain itu, karena Anda menghitung tumbukan antara this dan b, apakah Anda memeriksa untuk memastikan bahwa Anda juga tidak melakukan tumbukan yang sama antara b dan this, sehingga menggandakan delta yang diterapkan pada setiap gelembung yang berpartisipasi dalam tumbukan?

person Rick Goldstein    schedule 15.02.2011
comment
Ya itu salah ketik... Pasti aku terlalu lama berada di depan komputer, aku mengecek matematika berkali-kali. Terima kasih. Lihat hasil edit saya, saya benar-benar ingin algoritma lain berfungsi dan yang pasti bukan masalah yang sama - person Cbas; 16.02.2011
comment
Adapun poin kedua Anda, saya tidak memeriksa apakah saya sudah menyelesaikan tabrakan di loop saya melalui gelembung, tapi menurut saya itu tidak penting karena hal pertama yang saya lakukan dalam metode resolusiCollision ini adalah memisahkannya. Ketika perulangan berhasil menemukan bola lain yang bertabrakan, perulangan tersebut tidak akan bertabrakan lagi dan tidak akan memanggil metode ini lagi - person Cbas; 16.02.2011
comment
Saat Anda menghitung mtd.normalize(), apakah mtd tetap normal? Jika tidak, saya rasa Anda perlu mengubah perhitungan impulse menjadi mtd.normalize().multiply(i). Selain itu, Anda mungkin melihat akumulasi kesalahan pembulatan, terutama dari terjemahan ke dalam kerangka acuan b (perhitungan 'kecepatan tumbukan'). - person Rick Goldstein; 17.02.2011
comment
Itu dia! Berfungsi dengan baik sekarang. Sejujurnya saya tidak memahami semua perhitungan di balik ini karena saya baru saja mengambilnya dari sumber lain, jadi terima kasih banyak telah membantu saya menyelesaikannya. Saya pasti akan menulis komentar di thread lain untuk memberi tahu mereka bahwa ada kesalahan dalam kode - person Cbas; 17.02.2011
comment
Senang itu membantu. Saya adalah seorang fisikawan di kehidupan sebelumnya, jadi saya telah menyelesaikan soal tumbukan satu atau dua kali. Bersulang! - person Rick Goldstein; 17.02.2011

Saya menebak pertama: getMass() mengembalikan bilangan bulat (atau int) (dan bukan float atau double)?

Jika ini benar, maka masalah Anda adalah 1 / getMass() akan menghasilkan nilai integer (dan hanya bisa 1 atau paling sering 0)). Untuk memperbaikinya, ganti 1 dengan 1.0 atau 1.0f

Karena aturan umumnya sederhana: Jika Anda memiliki operasi matematika (+,-,*,/) tipe yang dihasilkan akan berupa bilangan bulat jika tidak ada satu pun dari kedua operan yang merupakan struktur data floating point (double atau float)

Bagaimanapun: mungkin ada masalah kedua, mungkin perhitungan Anda kurang tepat. Maka Anda harus menggunakan double daripada float.

person Ralph    schedule 15.02.2011
comment
Itu poin yang sangat bagus. getMass() sebenarnya mengembalikan satu byte, dan dalam kode saya sejauh ini, semua gelembung memiliki massa 1. Jika massanya berbeda, saya melihat bahwa saya akan mendapat masalah. Saya akan mengubahnya, Terima kasih banyak. - person Cbas; 16.02.2011

Ada bagian yang terlihat aneh:

Kedua perhitungan tersebut:

float v1nPost = (v1n*(this.mass-b.mass) + 2*b.mass*v2n)/(this.mass*b.mass);
float v2nPost = (v2n*(b.mass-this.mass) + 2*this.mass*v1n)/(this.mass+b.mass);

simetris, kecuali operasi terakhir, operasi pertama adalah *, operasi kedua adalah +

person Ralph    schedule 15.02.2011
comment
Itu saja.. Terima kasih banyak. Lihat hasil edit saya, sekarang saya mencoba membuat algoritma lain berfungsi - person Cbas; 16.02.2011