Saya memerlukan algoritme yang dapat memberi saya posisi di sekitar bola untuk poin N (kurang dari 20, mungkin) yang menyebarkannya secara samar. Tidak perlu "kesempurnaan", tapi saya hanya membutuhkannya jadi tidak ada yang bisa digabungkan.
- Pertanyaan ini memberikan kode yang bagus, tetapi saya tidak dapat menemukan cara untuk membuat seragam ini, karena ini tampak 100% acak.
- Posting blog ini merekomendasikan memiliki dua cara yang memungkinkan input jumlah titik pada bola, tetapi algoritma Saff dan Kuijlaars persis dalam psuedocode yang dapat saya transkripsikan, dan contoh kode yang saya temukan berisi "node [k]", yang tidak dapat saya lihat menjelaskan dan menghancurkan kemungkinan itu. Contoh blog kedua adalah Golden Section Spiral, yang memberi saya hasil yang aneh dan terkumpul, tanpa cara yang jelas untuk menentukan radius konstan.
- Algoritme dari pertanyaan ini sepertinya dapat berfungsi, tetapi saya tidak dapat mengumpulkan apa yang ada di halaman itu ke dalam psuedocode atau apa pun.
Beberapa utas pertanyaan lain yang saya temukan berbicara tentang distribusi seragam secara acak, yang menambah tingkat kerumitan yang tidak saya khawatirkan. Saya minta maaf karena ini pertanyaan yang konyol, tetapi saya ingin menunjukkan bahwa saya benar-benar berusaha keras dan masih gagal.
Jadi, yang saya cari adalah pseudocode sederhana untuk mendistribusikan titik N secara merata di sekitar bola satuan, yang mengembalikan dalam koordinat bola atau Kartesius. Bahkan lebih baik jika ia bahkan dapat menyebar dengan sedikit pengacakan (pikirkan planet di sekitar bintang, tersebar dengan baik, tetapi dengan ruang untuk kelonggaran).
Jawaban:
Dalam contoh kode
node[k]
ini hanya simpul ke-k. Anda menghasilkan titik array N dannode[k]
merupakan kth (dari 0 hingga N-1). Jika hanya itu yang membuat Anda bingung, semoga Anda bisa menggunakannya sekarang.(dengan kata lain,
k
adalah larik berukuran N yang ditentukan sebelum fragmen kode dimulai, dan yang berisi daftar poin).Atau , membangun jawaban lain di sini (dan menggunakan Python):
Jika Anda memplotnya, Anda akan melihat bahwa jarak vertikal lebih besar di dekat kutub sehingga setiap titik terletak di sekitar total luas ruang yang sama (di dekat kutub ada lebih sedikit ruang "secara horizontal", sehingga memberi lebih banyak "vertikal" ).
Ini tidak sama dengan semua titik yang memiliki jarak yang kira-kira sama ke tetangga mereka (yang menurut saya link Anda bicarakan), tetapi mungkin cukup untuk apa yang Anda inginkan dan meningkatkan hanya dengan membuat kisi lintang / bujur yang seragam .
sumber
Algoritma Fibonacci sphere sangat bagus untuk ini. Cepat dan memberikan hasil yang sekilas akan dengan mudah menipu mata manusia. Anda dapat melihat contoh selesai dengan pemrosesan yang akan menunjukkan hasilnya seiring waktu saat poin ditambahkan. Berikut contoh interaktif hebat lainnya yang dibuat oleh @gman. Dan inilah implementasi sederhana di python.
1000 sampel memberi Anda ini:
sumber
Metode spiral emas
Anda bilang Anda tidak bisa mendapatkan metode spiral emas untuk bekerja dan itu memalukan karena itu benar-benar bagus. Saya ingin memberi Anda pemahaman yang lengkap tentang hal itu sehingga mungkin Anda dapat memahami cara menjaga agar ini tidak "terkumpul".
Jadi, inilah cara cepat dan tidak acak untuk membuat kisi yang kira-kira benar; Seperti dibahas di atas, tidak ada kisi yang sempurna, tetapi ini mungkin cukup baik. Ini dibandingkan dengan metode lain misalnya di BendWavy.org tetapi hanya memiliki tampilan yang bagus dan cantik serta jaminan tentang jarak yang merata dalam batas.
Primer: spiral bunga matahari pada disk unit
Untuk memahami algoritma ini, pertama-tama saya mengundang Anda untuk melihat algoritma spiral bunga matahari 2D. Hal ini didasarkan pada fakta bahwa bilangan paling irasional adalah rasio emas
(1 + sqrt(5))/2
dan jika seseorang mengeluarkan poin dengan pendekatan "berdiri di tengah, putar rasio emas dari seluruh belokan, lalu pancarkan titik lain ke arah itu", seseorang secara alami membangun a spiral yang, ketika Anda mencapai jumlah poin yang semakin tinggi, namun menolak untuk memiliki 'batang' yang terdefinisi dengan baik di mana titik-titik tersebut berbaris. (Catatan 1.)Algoritme untuk spasi genap pada disk adalah,
dan menghasilkan hasil yang terlihat seperti (n = 100 dan n = 1000):
Memberi jarak titik secara radial
Hal aneh utama adalah rumusnya
r = sqrt(indices / num_pts)
; bagaimana saya bisa sampai yang itu? (Catatan 2.)Nah, saya menggunakan akar kuadrat di sini karena saya ingin ini memiliki jarak area yang sama di sekitar disk. Itu sama dengan mengatakan bahwa dalam batas N besar saya ingin sedikit daerah R ∈ ( r , r + d r ), Θ ∈ ( θ , θ + d θ ) berisi sejumlah titik sebanding dengan luasnya, yang merupakan r d r d θ . Sekarang jika kita berpura-pura bahwa kita berbicara tentang variabel acak di sini, ini memiliki interpretasi langsung yang mengatakan bahwa kepadatan probabilitas gabungan untuk ( R , Θ ) hanya cr untuk beberapa konstanta c . Normalisasi pada disk unit kemudian akan memaksa c = 1 / π.
Sekarang izinkan saya memperkenalkan trik. Itu berasal dari teori probabilitas di mana itu dikenal sebagai pengambilan sampel CDF terbalik : misalkan Anda ingin menghasilkan variabel acak dengan kepadatan probabilitas f ( z ) dan Anda memiliki variabel acak U ~ Uniform (0, 1), seperti keluar dari
random()
di sebagian besar bahasa pemrograman. Bagaimana kamu melakukan ini?Sekarang trik spiral rasio emas memberi jarak pada poin dengan pola yang sama bagusnya untuk θ jadi mari kita integrasikan; untuk disk unit kita mendapatkan F ( r ) = r 2 . Jadi fungsi inversnya adalah F -1 ( u ) = u 1/2 , dan oleh karena itu kita akan menghasilkan titik acak pada piringan dalam koordinat kutub dengan
r = sqrt(random()); theta = 2 * pi * random()
.Sekarang alih-alih mengambil sampel secara acak dari fungsi terbalik ini, kami mengambil sampelnya secara seragam , dan hal yang menyenangkan tentang pengambilan sampel yang seragam adalah bahwa hasil kami tentang bagaimana titik-titik tersebar dalam batas N besar akan berperilaku seolah-olah kami telah mengambil sampelnya secara acak. Kombinasi ini adalah triknya. Alih-alih
random()
kita gunakan(arange(0, num_pts, dtype=float) + 0.5)/num_pts
, jadi, katakanlah, jika kita ingin mencicipi 10 poin itur = 0.05, 0.15, 0.25, ... 0.95
. Kami mencontohkan r secara seragam untuk mendapatkan jarak area yang sama, dan kami menggunakan kenaikan bunga matahari untuk menghindari "batang" titik yang buruk dalam output.Sekarang melakukan bunga matahari di atas bola
Perubahan yang perlu kita lakukan untuk menandai bola dengan titik hanya melibatkan penggantian koordinat kutub untuk koordinat bola. Koordinat radial tentu saja tidak masuk ke sini karena kita berada di bola satuan. Untuk menjaga hal-hal sedikit lebih konsisten di sini, meskipun saya dilatih sebagai fisikawan, saya akan menggunakan koordinat matematikawan di mana 0 ≤ φ ≤ π adalah garis lintang yang turun dari kutub dan 0 ≤ θ ≤ 2π adalah bujur. Jadi perbedaan dari atas adalah pada dasarnya kita mengganti variabel r dengan φ .
Elemen luas kita, yang tadinya r d r d θ , sekarang menjadi sin ( φ ) d φ d θ yang tidak lebih rumit . Jadi kepadatan gabungan kita untuk jarak seragam adalah sin ( φ ) / 4π. Mengintegrasikan θ , kita menemukan f ( φ ) = sin ( φ ) / 2, jadi F ( φ ) = (1 - cos ( φ )) / 2. Membalik ini kita dapat melihat bahwa variabel acak yang seragam akan terlihat seperti acos (1 - 2 u ), tetapi kita mengambil sampel secara seragam dan bukan secara acak, jadi kita menggunakan φ k = acos (1 - 2 ( k)+ 0,5) / N ). Dan algoritme lainnya hanya memproyeksikan ini ke koordinat x, y, dan z:
Sekali lagi untuk n = 100 dan n = 1000 hasilnya terlihat seperti:
Penelitian lebih lanjut
Saya ingin memberikan teriakan ke blog Martin Roberts. Perhatikan bahwa di atas saya membuat offset indeks saya dengan menambahkan 0,5 ke setiap indeks. Ini hanya menarik secara visual bagi saya, tetapi ternyata pilihan offset sangat penting dan tidak konstan selama interval dan bisa berarti mendapatkan akurasi 8% lebih baik dalam pengemasan jika dipilih dengan benar. Seharusnya juga ada cara agar urutan R 2 -nya menutupi sebuah bola dan akan menarik untuk melihat apakah ini juga menghasilkan penutup yang rata dan bagus, mungkin apa adanya tetapi mungkin perlu, katakanlah, diambil dari hanya setengah dari unit persegi dipotong secara diagonal atau lebih dan diregangkan untuk membentuk lingkaran.
Catatan
"Batang" tersebut dibentuk oleh pendekatan rasional terhadap sebuah angka, dan pendekatan rasional terbaik untuk sebuah angka berasal dari ekspresi pecahan lanjutannya, di
z + 1/(n_1 + 1/(n_2 + 1/(n_3 + ...)))
manaz
adalah bilangan bulat dann_1, n_2, n_3, ...
merupakan urutan bilangan bulat positif terbatas atau tak terbatas:Sejak bagian pecahan
1/(...)
selalu antara nol dan satu, bilangan bulat besar dalam pecahan lanjutan memungkinkan perkiraan rasional yang sangat baik: "satu dibagi sesuatu antara 100 dan 101" lebih baik daripada "satu dibagi sesuatu antara 1 dan 2." Oleh karena itu, bilangan yang paling irasional adalah yang merupakan1 + 1/(1 + 1/(1 + ...))
dan tidak memiliki perkiraan rasional yang sangat baik; seseorang dapat menyelesaikan φ = 1 + 1 / φ dengan mengalikannya dengan φ untuk mendapatkan rumus rasio emas.Untuk orang-orang yang tidak begitu akrab dengan NumPy - semua fungsinya “di-vectorisasi”, jadi itu
sqrt(array)
sama dengan yang mungkin ditulis oleh bahasa lainmap(sqrt, array)
. Jadi ini adalah aplikasi komponen demi komponensqrt
. Hal yang sama juga berlaku untuk pembagian dengan skalar atau penjumlahan dengan skalar - yang berlaku untuk semua komponen secara paralel.Buktinya sederhana setelah Anda tahu bahwa inilah hasilnya. Jika Anda bertanya berapa probabilitas z < Z < z + d z , ini sama dengan menanyakan berapa probabilitas z < F -1 ( U ) < z + d z , terapkan F ke ketiga ekspresi dengan memperhatikan bahwa itu adalah fungsi yang meningkat secara monoton, maka F ( z ) < U < F ( z + d z ), perluas sisi kanan keluar untuk mencari F ( z ) + f( z ) d z , dan karena U seragam, probabilitas ini hanya f ( z ) d z seperti yang dijanjikan.
sumber
Ini dikenal sebagai titik pengepakan pada bola, dan tidak ada solusi umum yang sempurna (diketahui). Namun, ada banyak solusi yang tidak sempurna. Tiga yang paling populer tampaknya:
n
dari mereka) di dalam kubus yang mengelilingi bola, lalu menolak titik-titik di luar bola. Perlakukan titik yang tersisa sebagai vektor, dan normalkan. Ini adalah "sampel" Anda - pilihn
dari mereka menggunakan beberapa metode (secara acak, serakah, dll).Lebih banyak informasi tentang masalah ini dapat ditemukan di sini
sumber
Apa yang Anda cari disebut penutup bola . Masalah penutup bola sangat sulit dan solusinya tidak diketahui kecuali untuk sejumlah kecil poin. Satu hal yang diketahui dengan pasti adalah bahwa dengan n titik pada sebuah bola, selalu ada dua titik jarak
d = (4-csc^2(\pi n/6(n-2)))^(1/2)
atau lebih dekat.Jika Anda menginginkan metode probabilistik untuk menghasilkan titik-titik yang didistribusikan secara seragam pada sebuah bola, itu mudah: menghasilkan titik-titik dalam ruang secara seragam dengan distribusi Gaussian (ini dibangun ke dalam Java, tidak sulit untuk menemukan kode untuk bahasa lain). Jadi dalam ruang 3 dimensi, Anda membutuhkan sesuatu seperti
Kemudian proyeksikan titik tersebut pada bola dengan menormalkan jaraknya dari asalnya
Distribusi Gaussian dalam n dimensi simetris bola sehingga proyeksi ke bola seragam.
Tentu saja, tidak ada jaminan bahwa jarak antara dua titik mana pun dalam kumpulan titik yang dihasilkan secara seragam akan dibatasi di bawah, jadi Anda dapat menggunakan penolakan untuk menerapkan ketentuan apa pun yang mungkin Anda miliki: mungkin yang terbaik adalah menghasilkan seluruh koleksi lalu tolak seluruh koleksi jika perlu. (Atau gunakan "penolakan awal" untuk menolak seluruh koleksi yang telah Anda hasilkan sejauh ini; hanya saja, jangan simpan beberapa poin dan jatuhkan yang lain.) Anda dapat menggunakan rumus yang
d
diberikan di atas, dikurangi beberapa kelonggaran, untuk menentukan jarak min antara poin di bawah ini yang akan Anda tolak serangkaian poin. Anda harus menghitung n memilih 2 jarak, dan kemungkinan penolakan akan bergantung pada kelonggaran; sulit untuk mengatakan caranya, jadi jalankan simulasi untuk mengetahui statistik yang relevan.sumber
Jawaban ini didasarkan pada 'teori' yang sama yang diuraikan dengan baik oleh jawaban ini
Saya menambahkan jawaban ini sebagai:
- Tidak ada pilihan lain yang sesuai dengan kebutuhan 'keseragaman' 'tepat' (atau tidak jelas-jelas begitu). (Memperhatikan untuk mendapatkan planet seperti distribusi perilaku mencari yang secara khusus diinginkan dalam permintaan awal, Anda hanya menolak dari daftar terbatas dari k titik-titik yang dibuat secara seragam secara acak (tuliskan secara acak jumlah indeks dalam k item kembali).)
- impl lainnya memaksa Anda untuk memutuskan 'N' dengan 'sumbu sudut', vs. hanya 'satu nilai N' di kedua nilai sumbu sudut (yang pada jumlah rendah N sangat sulit untuk mengetahui apa yang mungkin, atau mungkin tidak penting ( misalnya Anda ingin poin '5' - bersenang-senanglah))
--Selanjutnya, sangat sulit untuk 'memahami' cara membedakan antara opsi lain tanpa citra apa pun, jadi inilah tampilan opsi ini (di bawah), dan implementasi yang siap dijalankan yang menyertainya.
dengan N pada 20:
dan kemudian N pada 80:
berikut kode python3 yang siap dijalankan, dengan emulasinya dari sumber yang sama: " http://web.archive.org/web/20120421191837/http://www.cgafaq.info/wiki/Evenly_distributed_points_on_sphere " ditemukan oleh orang lain . (Plotting yang saya sertakan, yang menyala ketika dijalankan sebagai 'utama,' diambil dari: http://www.scipy.org/Cookbook/Matplotlib/mplot3D )
diuji pada hitungan rendah (N dalam 2, 5, 7, 13, dll) dan tampaknya berfungsi 'bagus'
sumber
Mencoba:
Fungsi di atas harus berjalan dalam loop dengan N loop total dan k loop iterasi saat ini.
Ini didasarkan pada pola biji bunga matahari, kecuali biji bunga matahari yang melengkung menjadi setengah kubah, dan sekali lagi menjadi bulatan.
Ini adalah fotonya, kecuali saya meletakkan kamera setengah jalan di dalam bola sehingga terlihat 2d bukan 3d karena jarak kamera sama dari semua titik. http://3.bp.blogspot.com/-9lbPHLccQHA/USXf88_bvVI/AAAAAAAAADY/j7qhQsSZsA8/s640/sphere.jpg
sumber
Healpix memecahkan masalah yang terkait erat (membuat piksel bola dengan piksel area yang sama):
http://healpix.sourceforge.net/
Ini mungkin berlebihan, tapi mungkin setelah melihatnya Anda akan menyadari beberapa properti bagus lainnya yang menarik bagi Anda. Ini lebih dari sekedar fungsi yang menghasilkan point cloud.
Saya mendarat di sini mencoba menemukannya lagi; nama "healpix" tidak benar-benar membangkitkan bola ...
sumber
dengan sejumlah kecil poin, Anda dapat menjalankan simulasi:
sumber
Ambillah dua faktor terbesar dari Anda
N
, jikaN==20
maka dua faktor terbesar adalah{5,4}
, atau, secara lebih umum{a,b}
. MenghitungTempatkan poin pertama Anda di
{90-dlat/2,(dlong/2)-180}
, poin kedua di{90-dlat/2,(3*dlong/2)-180}
, poin ketiga di{90-dlat/2,(5*dlong/2)-180}
, hingga Anda pernah melakukan perjalanan keliling dunia satu kali, yang pada saat itu Anda harus melakukannya{75,150}
saat berikutnya{90-3*dlat/2,(dlong/2)-180}
.Jelas saya mengerjakan ini dalam derajat di permukaan bumi bulat, dengan konvensi biasa untuk menerjemahkan +/- ke N / S atau E / W. Dan jelas ini memberi Anda distribusi yang sama sekali tidak acak, tetapi seragam dan poinnya tidak digabungkan bersama.
Untuk menambahkan beberapa derajat keacakan, Anda dapat membuat 2 yang terdistribusi normal (dengan mean 0 dan std dev dari {dlat / 3, dlong / 3} yang sesuai) dan menambahkannya ke titik terdistribusi seragam Anda.
sumber
edit: Ini tidak menjawab pertanyaan OP yang dimaksudkan untuk ditanyakan, meninggalkannya di sini jika orang merasa berguna.
Kami menggunakan aturan perkalian probabilitas, dikombinasikan dengan infinitessimals. Ini menghasilkan 2 baris kode untuk mencapai hasil yang Anda inginkan:
(ditentukan dalam sistem koordinat berikut :)
Bahasa Anda biasanya memiliki primitif nomor acak yang seragam. Misalnya di python Anda dapat menggunakan
random.random()
untuk mengembalikan angka dalam kisaran[0,1)
. Anda bisa mengalikan angka ini dengan k untuk mendapatkan angka acak dalam kisaran tersebut[0,k)
. Jadi dalam python,uniform([0,2pi))
artinyarandom.random()*2*math.pi
.Bukti
Sekarang kita tidak dapat menetapkan θ secara seragam, jika tidak kita akan menggumpal di kutub. Kami ingin menetapkan probabilitas yang proporsional dengan luas permukaan irisan bola (θ dalam diagram ini sebenarnya adalah φ):
Perpindahan sudut dφ di ekuator akan menghasilkan perpindahan dφ * r. Apa perpindahan itu pada azimuth sewenang-wenang θ? Nah, jari-jari dari sumbu z adalah
r*sin(θ)
, jadi panjang ar dari "garis lintang" yang memotong irisan tersebut adalahdφ * r*sin(θ)
. Jadi kami menghitung distribusi kumulatif area untuk mengambil sampel darinya, dengan mengintegrasikan area potongan dari kutub selatan ke kutub utara.(dimana barang =
dφ*r
)Kami sekarang akan mencoba untuk mendapatkan kebalikan dari CDF untuk mengambil sampel darinya: http://en.wikipedia.org/wiki/Inverse_transform_sampling
Pertama kita normalisasi dengan membagi hampir CDF kita dengan nilai maksimumnya. Ini memiliki efek samping menghilangkan dφ dan r.
Jadi:
sumber
ATAU ... untuk menempatkan 20 poin, hitung pusat-pusat permukaan ikosahedronal. Untuk 12 poin, temukan simpul dari ikosahedron. Untuk 30 poin, titik tengah dari tepi ikosahedron. Anda dapat melakukan hal yang sama dengan tetrahedron, kubus, dodecahedron, dan oktahedron: satu set titik ada di simpul, satu lagi di tengah muka dan satu lagi di tengah tepi. Namun, mereka tidak dapat dicampur.
sumber
sumber
@robert king Ini adalah solusi yang sangat bagus tetapi memiliki beberapa bug di dalamnya. Saya tahu itu sangat membantu saya, jadi tidak masalah kecerobohannya. :) Ini adalah versi yang sudah dibersihkan ....
sumber
Ini berhasil dan sangat sederhana. Poin sebanyak yang Anda inginkan:
sumber