Rute pada permukaan bola - Temukan geodesik?


8

Saya bekerja dengan beberapa teman di game berbasis browser tempat orang dapat bergerak di peta 2D. Sudah hampir 7 tahun dan masih ada orang yang memainkan game ini, jadi kami memikirkan cara untuk memberi mereka sesuatu yang baru. Sejak itu peta permainan adalah bidang terbatas dan orang-orang dapat bergerak dari (0, 0) ke (MAX_X, MAX_Y) dalam peningkatan X dan Y yang dikuantisasi (bayangkan saja sebagai papan catur besar).
Kami percaya ini saatnya untuk memberikan dimensi lain, jadi, hanya beberapa minggu yang lalu, kami mulai bertanya-tanya bagaimana permainan bisa terlihat dengan pemetaan lain:

  • Pesawat tanpa batas dengan gerakan terus-menerus: ini bisa menjadi langkah maju tetapi saya masih tidak yakin.
  • Dunia Toroidal (gerakan terus-menerus atau terkuantisasi): dengan tulus saya bekerja dengan torus sebelumnya, tetapi kali ini saya menginginkan sesuatu yang lebih ...
  • Dunia bulat dengan gerakan terus-menerus: ini akan luar biasa!

Apa yang kita inginkan Browser pengguna diberi daftar koordinat seperti (lintang, bujur) untuk setiap objek pada peta permukaan bulat; browser kemudian harus menunjukkan ini di layar pengguna rendering mereka di dalam elemen web (kanvas mungkin? ini bukan masalah). Ketika orang mengklik pada pesawat, kami mengonversi (mouseX, mouseY) menjadi (lat, lng) dan mengirimkannya ke server yang harus menghitung rute antara posisi pengguna saat ini ke titik yang diklik.

Apa yang kami miliki. Kami mulai menulis perpustakaan Java dengan banyak matematika yang berguna untuk bekerja dengan Rotation Matrices, Quaternions, Euler Angles, Translations, dll. di dalam JPanel. Kami berhasil menangkap klik dan menerjemahkannya ke koordinat bola dan menyediakan beberapa fitur bermanfaat lainnya seperti rotasi tampilan, skala, terjemahan, dll. Apa yang kami miliki sekarang seperti mesin kecil (memang sangat sedikit) yang mensimulasikan interaksi klien dan server. Sisi klien menunjukkan titik di layar dan menangkap interaksi lain, sisi server membuat tampilan dan melakukan kalkulus lain seperti menginterpolasi rute antara posisi saat ini dan titik yang diklik.

Dimana masalahnya? Jelas kami ingin memiliki jalur terpendek untuk interpolasi antara dua titik rute . Kami menggunakan angka empat untuk menginterpolasi antara dua titik pada permukaan bola dan ini tampaknya bekerja dengan baik sampai saya perhatikan bahwa kami tidak mendapatkan jalur terpendek pada permukaan bola:

Lingkaran yang salah

Kami berpikir masalahnya adalah bahwa rute dihitung sebagai jumlah dari dua rotasi tentang sumbu X dan Y. Jadi kami mengubah cara kami menghitung angka empat tujuan: Kami mendapatkan sudut ketiga (yang pertama adalah lintang, yang kedua adalah garis bujur, yang ketiga adalah rotasi tentang vektor yang menunjuk ke posisi kami saat ini) yang kami sebut orientasi. Sekarang kita memiliki sudut "orientasi" kita memutar sumbu Z dan kemudian menggunakan vektor hasil sebagai sumbu rotasi untuk angka empat tujuan (Anda dapat melihat sumbu rotasi berwarna abu-abu):

Rute yang benar mulai dari 0, 0

Apa yang kami dapatkan adalah rute yang benar (Anda dapat melihatnya berada pada lingkaran besar), tetapi kami HANYA jika titik rute awal adalah lintang, bujur (0, 0) yang berarti vektor awal adalah (sphereRadius, 0 , 0). Dengan versi sebelumnya (gambar 1) kita tidak mendapatkan hasil yang baik bahkan ketika titik awal adalah 0, 0, jadi saya pikir kita sedang bergerak menuju solusi, tetapi prosedur yang kita ikuti untuk mendapatkan rute ini sedikit "aneh " mungkin?

Pada gambar berikut ini Anda mendapatkan tampilan masalah yang kita dapatkan ketika titik awal bukan (0, 0), karena Anda dapat melihat titik awal bukan vektor (sphereRadius, 0, 0), dan seperti yang Anda lihat titik tujuan (yang digambar dengan benar!) tidak pada rute.

Rute salah!

Titik magenta (titik yang terletak pada rute) adalah titik akhir rute yang diputar di sekitar pusat bola (-mulaiLatitude, 0, -mulaiLongitude). Ini berarti bahwa jika saya menghitung matriks rotasi dan menerapkannya ke setiap titik pada rute mungkin saya akan mendapatkan rute yang sebenarnya, tetapi saya mulai berpikir bahwa ada cara yang lebih baik untuk melakukan ini.

Mungkin saya harus mencoba untuk mendapatkan pesawat melalui pusat bola dan titik rute, memotongnya dengan bola dan mendapatkan geodesik? Tapi bagaimana caranya?

Maaf karena terlalu bertele-tele dan mungkin karena bahasa Inggris yang salah, tetapi hal ini mengejutkan saya!

EDIT: Kode di bawah ini berfungsi dengan baik! Terima kasih untuk semuanya:

public void setRouteStart(double srcLat, double srcLng, double destLat, destLng) {
    //all angles are in radians
    u = Choords.sphericalToNormalized3D(srcLat, srcLng);
    v = Choords.sphericalToNormalized3D(destLat, destLng);
    double cos = u.dotProduct(v);
    angle = Math.acos(cos);
    if (Math.abs(cos) >= 0.999999) {
        u = new V3D(Math.cos(srcLat), -Math.sin(srcLng), 0);
    } else {
        v.subtract(u.scale(cos));
        v.normalize();
    }
}

public static V3D sphericalToNormalized3D( double radLat, double radLng) {
    //angles in radians
    V3D p = new V3D();
    double cosLat = Math.cos(radLat);
    p.x = cosLat*Math.cos(radLng);
    p.y = cosLat*Math.sin(radLng);
    p.z = Math.sin(radLat);
    return p;
}

public void setRouteDest(double lat, double lng) {
    EulerAngles tmp = new AngoliEulero(
       Math.toRadians(lat), 0, -Math.toRadians(lng));
    qtEnd.setInertialToObject(tmp);
    //do other stuff like drawing dest point...
}

public V3D interpolate(double totalTime, double t) {
    double _t = angle * t/totalTime;
    double cosA = Math.cos(_t);
    double sinA = Math.sin(_t);
    V3D pR = u.scale(cosA);
    pR.sum(
       v.scale(sinA)
    );
    return pR;
}

1
Tolong tunjukkan kode slerp / interpolasi angka empat Anda.
Maik Semder

1
Di samping catatan: bahkan buku dapat mengandung kesalahan yang tidak teramati, tetapi bencana. Sebelum menyalin sesuatu, pastikan Anda memahaminya sendiri .. hanya dengan begitu Anda dapat menganggapnya valid (baik, kecuali Anda salah paham sendiri - tetapi ini jauh lebih kecil kemungkinannya).
teodron

@MaikSemder menambahkan fungsi di mana RotationMatrix dikompilasi mulai dari kelas Quaternion
CaNNaDaRk

Mungkin masalahnya ada di dalam setRouteDest (double lat, double lng) dan setRouteStart (double lat, double lng). Saya pikir saya kehilangan sudut ketika saya membuat objek EulerAngles seperti ini: EulerAngles tmp = new EulerAngles (Math.toRadians (lat), ???, -Math.toRadians (lng))
CaNNaDaRk

Saya tidak melihat di mana Anda menggunakan "RotationMatrix" untuk membuat titik yang diputar "p" dikembalikan dari "interpolasi". Anda baru saja mengatur "RotationMatrix" dari angka empat yang diinterpolasi, tetapi Anda tidak menggunakannya
Maik Semder

Jawaban:


5

Masalah Anda murni dua dimensi, pada bidang yang dibentuk oleh pusat bola dan titik sumber dan tujuan Anda. Menggunakan angka empat sebenarnya membuat hal-hal lebih kompleks, karena selain posisi pada bola 3D, angka empat mengkodekan orientasi.

Anda mungkin sudah memiliki sesuatu untuk diinterpolasi pada lingkaran, tetapi untuk berjaga-jaga, berikut adalah beberapa kode yang seharusnya berfungsi.

V3D u, v;
double angle;

public V3D geographicTo3D(double lat, double long)
{
    return V3D(sin(Math.toRadians(long)) * cos(Math.toRadians(lat)),
               cos(Math.toRadians(long)) * cos(Math.toRadians(lat)),
               sin(Math.toRadians(lat)));
}

public V3D setSourceAndDest(double srcLat, double srcLong,
                            double dstLat, double dstLong)
{
    u = geographicTo3D(srcLat, srcLong);
    V3D tmp = geographicTo3D(dstLat, dstLong);
    angle = acos(dot(u, tmp));
    /* If there are an infinite number of routes, choose
     * one arbitrarily. */
    if (abs(dot(u, tmp)) >= 0.999999)
        v = V3D(cos(srcLong), -sin(srcLong), 0);
    else
        v = normalize(tmp - dot(u, tmp) * u);
}

public V3D interpolate(double totalTime, double t)
{
    double a = t / totalTime * angle;
    return cos(a) * u + sin(a) * v;
}

Iya! Itulah yang saya cari, ini masalah saya yang sebenarnya, saya harus bekerja di pesawat yang memotong C, tujuan dan sumber! Satu-satunya masalah adalah saya masih tidak bisa membuatnya berfungsi ... Saya akan menempelkan kode dan hasil yang saya dapatkan dari kode Anda!
CaNNaDaRk

mengedit pertanyaan. Ada masalah ... mungkin saya salah menerjemahkan kode ???
CaNNaDaRk

@CaNNaDaRk Saya tidak melihat apa yang salah. Apakah penggunaan normalisasi (), kurangi (), skala () dll. Benar untuk efek samping? Dan apakah tmencapai totalTime? Juga jika Anda ingin mendapatkan lingkaran penuh, buatlah nilai tmaks, 2 * pi / angle * totalTimebukan hanya totalTime.
sam hocevar

Sempurna! Di sana saya menambahkan kesalahan bodoh ke fungsi normalisasi dan karena itu mendapatkan besaran yang salah dalam vektor "v". Sekarang semuanya bekerja dengan baik! Terima kasih lagi;)
CaNNaDaRk

3

Pastikan kedua angka empat berada di belahan bumi yang sama di hypersphere. Jika produk-titik mereka kurang dari 0, maka tidak. Dalam hal itu negasikan salah satu dari mereka (negasikan masing-masing nomornya), sehingga mereka berada di belahan bumi yang sama dan akan memberi Anda jalan terpendek. Kodesemu:

quaternion from, to;

// is "from" and "to" on the same hemisphere=
if(dot(from, to) < 0.0)
{
    // put "from" to the other hemisphere, so its on the same as "to"
    from.x = -from.x;
    from.y = -from.y;
    from.z = -from.z;
    from.w = -from.w;
}

// now simply slerp them

Jawaban saya di sini menjelaskan secara rinci apa yang meniadakan setiap istilah angka empat dan mengapa orientasi masih sama, hanya di sisi lain dari hypersphere.


EDIT fungsi interpolasi akan terlihat seperti ini:

public V3D interpolate(double totalTime, double t) {
    double _t = t/totalTime;    
    Quaternion tmp;
    if(dot(qtStart, qtEnd) < 0.0)
    {
        tmp.x = -qtEnd.x;
        tmp.y = -qtEnd.y;
        tmp.z = -qtEnd.z;
        tmp.w = -qtEnd.w;
    }
    else
    {
        tmp = qtEnd;
    }
    Quaternion q = Quaternion.Slerp(qtStart, tmp, _t);
    RotationMatrix.inertialQuatToIObject(q);
    V3D p = matInt.inertialToObject(V3D.Xaxis.scale(sphereRadius));
    //other stuff, like drawing point ...
    return p;
}

Saya mencoba kode Anda tetapi saya mendapatkan hasil yang sama. Dalam mode debug saya menonton untuk produk titik dan saya yakin dua angka empat berada di belahan bumi yang sama di hypersphere. Maaf, mungkin pertanyaan saya tidak cukup jelas?
CaNNaDaRk

Apa maksud Anda "Anda yakin mereka berada di belahan bumi yang sama"? jika dot> = 0 maka mereka, jika tidak, maka tidak.
Maik Semder

Ini bukan tentang belahan bola normal Anda, ini tentang belahan di hypersphere, ruang 4D angka empat. Luangkan waktu untuk membaca tautan, sulit dijelaskan di kotak komentar.
Maik Semder

Itulah yang saya katakan, saya meletakkan kode Anda dan menghitung titik. Bahkan ketika itu> = 0 (jadi saya yakin mereka berada di belahan bumi yang sama) masalahnya selalu sama: rute yang saya dapatkan bukan pada lingkaran besar. Saya pikir masalahnya ada di tempat lain ..? Mungkin saya harus menambahkan beberapa kode ke pertanyaan ...? Sunting: saya membaca tautan Anda, saya masih berpikir masalahnya tidak ada. Saya juga mencoba kode yang Anda berikan kepada saya tetapi saya masih mendapatkan rute pada lingkaran kecil.
CaNNaDaRk

Tolong tunjukkan kode interpolasi Anda
Maik Semder

0

Karena Anda ingin V3Dkembali dari interpolator Anda, pendekatan paling sederhana adalah dengan melewatkan angka empat seluruhnya. Konversikan titik awal dan akhir menjadi V3Ddan letakkan di antara keduanya.

Jika Anda bersikeras menggunakan quaternions maka angka empat yang mewakili rotasi dari Pke Qmemiliki arah P x Qdan wdari P . Q.

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.