Bagaimana saya bisa membandingkan dua angka empat untuk kesetaraan logis?


9

Saya mencoba menulis beberapa unit test dan menyadari saya tidak tahu bagaimana membandingkan angka empat. Saya perlu tahu apakah dua angka empat mewakili orientasi yang sama (objek akan menghadap ke arah yang sama). Dengan posisi seperti vektor, saya hanya akan membandingkan bagian-bagian dan memeriksa mereka cukup dekat, tetapi untuk angka empat nilai bisa sangat berbeda.

Bagaimana saya bisa membandingkan dua angka empat?


Saya tidak yakin apakah ini merupakan praktik standar, tetapi dalam misal Java dan Unity angka empat disimpan sebagai empat nilai float. Hanya membandingkan ini untuk eachother seperti yang dijelaskan dalam posting ini: answers.unity3d.com/questions/288338/... stackoverflow.com/questions/5803627/quaternion-comparision
Tholle

1
@Tolle pengguna juga prihatin dengan dampak penerapan angka empat untuk mengubah / memutar entitas 3D (yaitu berpose bijaksana). Dua angka empat yang berbeda dapat mencapai rotasi yang sama (misalnya qdan -q). Cara naif (secara komputasi) akan menerapkan kedua angka empat pada vektor yang sama dan melihat apakah hasil vektornya berbeda ..
teodron

Jawaban:


7

Jika dua angka empat Anda q1dan q2, mereka mewakili rotasi yang sama jika salah satu dari kedua kondisi ini berlaku:

  1. q1adalah komponen bijaksana kira-kira sama dengan q2OR
  2. q1 adalah komponen yang kira-kira sama dengan -q2

Mengetahui hal ini, Anda dapat menulis tester kesetaraan yang cukup sederhana yang sesuai dengan tujuan Anda.


9
+1, satu nitpick, qdan -qmewakili orientasi yang sama (yang diminta), tetapi bukan rotasi yang sama. Ini sangat penting saat interpolasi.
Falstro

@falstro, saya pikir saya mengerti apa yang Anda maksud: sumbu rotasi terbalik, tetapi sudut argumen juga dinegasikan antara qdan -qketika direpresentasikan sebagai operator rotasi sudut-sumbu. Jadi, memang, secara teknis efek dari rotasi ini adalah sama, meskipun operator tidak. Dan, ya, ketika SLERPING, kita harus memastikan q1dan q2berbaring di belahan yang sama dari S3 hypersphere agar slerp mengambil jalur terpendek.
teodron

1
Tepat, ketika Anda menjalankan salah satu rotasi, Anda akan berakhir dengan orientasi yang sama, tetapi interpolasi (apakah Anda lerp atau slerp atau interpolasi mewah lainnya), Anda akan melihatnya berputar dengan cara yang berbeda. Dan ya, argumen sudut dinegasikan, tetapi itu sama dengan 2pi-angle, jadi itu memutar jauh di sekitar sumbu dinegasikan. Kadang-kadang inilah yang Anda inginkan; itu hanya sesuatu yang harus diperhatikan, q1 dot q2 > 0hasil dalam belokan pendek, q1 dot q2 < 0mengambil belokan panjang.
falstro

12

Hanya karena belum disebutkan. Karena angka empat yang digunakan untuk orientasi spasial selalu satuan panjang (atau seharusnya), berikut ini juga akan berfungsi.

abs(q1.dot(q2)) > 1-EPS

di mana EPS adalah beberapa faktor fudge untuk memungkinkan kesalahan kecil karena presisi floating point terbatas. Jika (dan hanya jika) kedua angka empat mewakili orientasi yang sama q1 = +- q2, maka , dan dengan demikian q1.dot(q2) = +- 1. Jika Anda ingin memastikan mereka rotasi yang sama (bukan hanya orientasi), lalu hapus abs.


@bogglez benar. Tersembunyi dalam teks dr. :)
falstro

+1, cukup elegan dan, mungkin bahkan lebih efisien secara numerik daripada jawaban saya (asalkan operasi SIMD digunakan :)).
teodron

Apa pembenaran matematis untuk ini?
fabian789

"Matematika" (dalam kutipan menyebabkan saya bukan ahli matematika :)) pembenaran: Dua vektor panjang satuan memiliki titik produk (alias produk dalam) yaitu 0 jika mereka vertikal satu sama lain, 1 * 1 = 1 jika mereka menunjuk tepat arah yang sama, dan 1 * 1 * cos (phi) dalam kasus umum, dengan phi sudutnya ...
ntg

2

Kuasi disimpan sebagai 4 mengapung atau ganda, sering disebut x, y, z dan w, di mana tiga yang pertama mewakili suatu sumbu dan w tingkat rotasi di sekitar sumbu itu.

Pendekatan yang naif adalah dengan hanya membandingkan angka-angka dari dua angka empat untuk kesetaraan. Namun, karena perhitungan floating point melibatkan kesalahan, Anda setidaknya harus menggunakan kesalahan, sering disebut eps (untuk epsilon) dan membandingkan setiap komponen seperti

    double const eps = 1e-12; // some error threshold
    abs(quat1_x - quat2_x) < eps // similar enough?
    // repeat for other values..

Tes yang lebih baik adalah menghitung titik produk dari dua angka empat dan menguji apakah mendekati 1.0. Anda harus melihat persamaan angka empat dengan dosa dan cos dan hanya menunjukkan dua angka empat, maka Anda harus siap melihat mengapa ini bekerja.


0

Berdasarkan semua saran untuk menggunakan Dot dan eps saya menemukan bahwa menggunakan (dalam kesatuan):

Mathf.Approximately(Mathf.Abs(Quaternion.Dot(transform.rotation, to)), 1.0f)

bekerja dengan baik tanpa saya harus membuat keputusan untuk ukuran eps.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.