Phân phối đều n điểm trên một mặt cầu


121

Tôi cần một thuật toán có thể cung cấp cho tôi các vị trí xung quanh một hình cầu cho N điểm (có thể là ít hơn 20) khiến chúng lan truyền một cách mơ hồ. Không cần "sự hoàn hảo", nhưng tôi chỉ cần nó để không có cái nào trong số chúng bó lại với nhau.

  • Câu hỏi này cung cấp mã tốt, nhưng tôi không thể tìm ra cách tạo bộ đồng phục này, vì điều này dường như được ngẫu nhiên hóa 100%.
  • Bài đăng trên blog này được đề xuất có hai cách cho phép nhập số điểm trên hình cầu, nhưng thuật toán Saff và Kuijlaars nằm chính xác trong mã psuedoc mà tôi có thể phiên âm và ví dụ mã mà tôi tìm thấy có chứa "nút [k]", mà tôi không thể xem giải thích và làm hỏng khả năng đó. Ví dụ blog thứ hai là Đường xoắn ốc Golden Section, cho tôi những kết quả tập hợp kỳ lạ, không có cách nào rõ ràng để xác định bán kính không đổi.
  • Thuật toán này từ câu hỏi này có vẻ như nó có thể hoạt động, nhưng tôi không thể ghép những gì trên trang đó thành mã psuedocode hoặc bất cứ thứ gì.

Một vài chủ đề câu hỏi khác mà tôi đã gặp nói về phân phối đồng đều ngẫu nhiên, điều này làm tăng thêm mức độ phức tạp mà tôi không lo ngại. Tôi xin lỗi vì đây là một câu hỏi ngớ ngẩn, nhưng tôi muốn chứng tỏ rằng tôi đã thực sự nhìn chăm chỉ và vẫn còn thiếu sót.

Vì vậy, những gì tôi đang tìm kiếm là mã giả đơn giản để phân bố đều N điểm xung quanh một hình cầu đơn vị, trả về ở dạng cầu hoặc tọa độ Descartes. Thậm chí tốt hơn nếu nó thậm chí có thể phân phối với một chút ngẫu nhiên (nghĩ rằng các hành tinh xung quanh một ngôi sao, trải rộng một cách nhẹ nhàng, nhưng có chỗ cho thời gian dài).


"Với một chút ngẫu nhiên" nghĩa là gì? Ý bạn là sự nhiễu loạn theo một nghĩa nào đó?
ninjagecko

32
OP bối rối. Những gì anh ta đang tìm là đặt n điểm trên một hình cầu, sao cho khoảng cách nhỏ nhất giữa hai điểm bất kỳ càng lớn càng tốt. Điều này sẽ làm cho các điểm trông giống như được "phân bổ đều" trên toàn bộ hình cầu. Điều này hoàn toàn không liên quan đến việc tạo ra một phân bố ngẫu nhiên đồng nhất trên một hình cầu, đó là ý nghĩa của nhiều liên kết đó và nhiều câu trả lời dưới đây đang nói về điều gì.
BlueRaja - Danny Pflughoeft

1
20 không phải là nhiều điểm để đặt trên một hình cầu nếu bạn không muốn chúng trông chỉ là ngẫu nhiên.
John Alexiou

2
Đây là một cách để làm điều đó (nó có ví dụ mã): pdfs.semanticscholar.org/97a6/... (trông giống như nó sử dụng các tính toán lực đẩy)
trusktr

1
Tất nhiên đối với các giá trị trên N trong {4, 6, 8, 12, 20} tồn tại các nghiệm chính xác trong đó khoảng cách từ mỗi điểm đến (mỗi) láng giềng gần nhất của nó là một hằng số cho tất cả các điểm và tất cả các lân cận gần nhất.
dmckee --- cựu điều hành kitten

Câu trả lời:


13

Trong ví dụ này, mã node[k] chỉ là nút thứ k. Bạn đang tạo mảng N điểm và node[k]là điểm thứ k (từ 0 đến N-1). Nếu đó là tất cả những gì làm bạn bối rối, hy vọng bạn có thể sử dụng nó ngay bây giờ.

(nói cách khác, klà một mảng có kích thước N được xác định trước khi đoạn mã bắt đầu và chứa danh sách các điểm).

Ngoài ra , xây dựng câu trả lời khác tại đây (và sử dụng Python):

> cat ll.py
from math import asin
nx = 4; ny = 5
for x in range(nx):
    lon = 360 * ((x+0.5) / nx)
    for y in range(ny):                                                         
        midpt = (y+0.5) / ny                                                    
        lat = 180 * asin(2*((y+0.5)/ny-0.5))                                    
        print lon,lat                                                           
> python2.7 ll.py                                                      
45.0 -166.91313924                                                              
45.0 -74.0730322921                                                             
45.0 0.0                                                                        
45.0 74.0730322921                                                              
45.0 166.91313924                                                               
135.0 -166.91313924                                                             
135.0 -74.0730322921                                                            
135.0 0.0                                                                       
135.0 74.0730322921                                                             
135.0 166.91313924                                                              
225.0 -166.91313924                                                             
225.0 -74.0730322921                                                            
225.0 0.0                                                                       
225.0 74.0730322921                                                             
225.0 166.91313924
315.0 -166.91313924
315.0 -74.0730322921
315.0 0.0
315.0 74.0730322921
315.0 166.91313924

Nếu bạn vẽ biểu đồ đó, bạn sẽ thấy rằng khoảng cách theo chiều dọc lớn hơn ở gần các cực để mỗi điểm nằm trong cùng một tổng số diện tích không gian (gần các cực có ít không gian hơn "theo chiều ngang", vì vậy nó cho nhiều "chiều dọc" hơn ).

Điều này không giống như tất cả các điểm có cùng khoảng cách với hàng xóm của chúng (đó là những gì tôi nghĩ rằng các liên kết của bạn đang nói đến), nhưng nó có thể đủ cho những gì bạn muốn và cải thiện chỉ đơn giản là tạo lưới vĩ độ / kinh độ đồng nhất .


thật tuyệt, thật tốt khi thấy một giải pháp toán học. Tôi đã nghĩ đến việc sử dụng sự phân tách độ dài đường xoắn và vòng cung. Tôi vẫn không chắc chắn về cách có được giải pháp tối ưu, đó là một vấn đề thú vị.
robert king

bạn có thấy rằng tôi đã chỉnh sửa câu trả lời của mình để bao gồm phần giải thích về nút [k] ở trên cùng không? tôi nghĩ rằng có thể tất cả các bạn cần ...
andrew Cooke

Tuyệt vời, cảm ơn vì lời giải thích. Tôi sẽ thử nó sau, vì hiện tại tôi không có thời gian, nhưng cảm ơn bạn rất nhiều vì đã giúp tôi. Tôi sẽ cho bạn biết cách nó hoạt động cho mục đích của tôi. ^^
Bắt đầu

Sử dụng phương pháp Xoắn ốc hoàn toàn phù hợp với nhu cầu của tôi, cảm ơn rất nhiều vì đã giúp đỡ và làm rõ. :)
Bắt đầu

13
Liên kết dường như đã chết.
Scheintod

140

Thuật toán hình cầu Fibonacci rất tốt cho việc này. Nó nhanh chóng và cho kết quả mà chỉ cần nhìn thoáng qua sẽ dễ dàng đánh lừa mắt người nhìn. Bạn có thể xem một ví dụ được thực hiện với quá trình xử lý sẽ hiển thị kết quả theo thời gian khi điểm được cộng. Đây là một ví dụ tương tác tuyệt vời khác do @gman thực hiện. Và đây là một triển khai đơn giản trong python.

import math


def fibonacci_sphere(samples=1):

    points = []
    phi = math.pi * (3. - math.sqrt(5.))  # golden angle in radians

    for i in range(samples):
        y = 1 - (i / float(samples - 1)) * 2  # y goes from 1 to -1
        radius = math.sqrt(1 - y * y)  # radius at y

        theta = phi * i  # golden angle increment

        x = math.cos(theta) * radius
        z = math.sin(theta) * radius

        points.append((x, y, z))

    return points

1000 mẫu cung cấp cho bạn điều này:

nhập mô tả hình ảnh ở đây


một biến n được gọi khi xác định phi: phi = ((i + rnd)% n) * tăng. N = mẫu?
Andrew Staroscik

@AndrewStaroscik vâng! Khi tôi viết mã lần đầu tiên, tôi đã sử dụng "n" làm biến và đổi tên sau đó nhưng không thực hiện thẩm định. Cảm ơn bạn đã nắm bắt được điều đó!
Fnord


4
@Xarbrough mã cung cấp cho bạn các điểm xung quanh một hình cầu đơn vị, vì vậy chỉ cần nhân mỗi điểm với bất kỳ đại lượng vô hướng nào bạn muốn cho bán kính.
bảy,

2
@Fnord: Chúng ta có thể làm điều này cho kích thước cao hơn không?
pikachuchameleon

108

Phương pháp xoắn ốc vàng

Bạn nói rằng bạn không thể làm cho phương pháp xoắn ốc vàng hoạt động và điều đó thật đáng tiếc vì nó thực sự rất tốt. Tôi muốn cung cấp cho bạn một sự hiểu biết đầy đủ về nó để có thể bạn có thể hiểu cách giữ cho điều này không bị “bó gọn”.

Vì vậy, đây là một cách nhanh chóng, không ngẫu nhiên để tạo một mạng tinh thể gần đúng; như đã thảo luận ở trên, không có mạng tinh thể nào là hoàn hảo, nhưng điều này có thể đủ tốt. Nó được so sánh với các phương pháp khác, ví dụ tại BendWavy.org nhưng nó chỉ có giao diện đẹp và đẹp cũng như đảm bảo về khoảng cách đều trong giới hạn.

Lớp lót: xoắn ốc hướng dương trên đĩa đơn vị

Để hiểu thuật toán này, trước tiên tôi mời các bạn xem qua thuật toán xoắn ốc 2D hướng dương. Điều này dựa trên thực tế rằng số vô tỷ nhất là tỷ lệ vàng (1 + sqrt(5))/2và nếu một người phát ra điểm theo cách tiếp cận "đứng ở trung tâm, quay một tỷ lệ vàng của toàn bộ lượt, sau đó phát ra điểm khác theo hướng đó", người ta tự nhiên tạo ra một xoắn ốc, khi bạn đạt đến số điểm ngày càng cao, tuy nhiên, từ chối có các 'vạch' được xác định rõ ràng mà các điểm thẳng hàng. (Lưu ý 1.)

Thuật toán cho khoảng cách đều trên đĩa là,

from numpy import pi, cos, sin, sqrt, arange
import matplotlib.pyplot as pp

num_pts = 100
indices = arange(0, num_pts, dtype=float) + 0.5

r = sqrt(indices/num_pts)
theta = pi * (1 + 5**0.5) * indices

pp.scatter(r*cos(theta), r*sin(theta))
pp.show()

và nó tạo ra kết quả giống như (n = 100 và n = 1000):

nhập mô tả hình ảnh ở đây

Giãn cách các điểm một cách xuyên tâm

Điều kỳ lạ chính là công thức r = sqrt(indices / num_pts); làm thế nào tôi đến với cái đó? (Lưu ý 2.)

Tôi đang sử dụng căn bậc hai ở đây vì tôi muốn chúng có khoảng cách diện tích bằng nhau xung quanh đĩa. Điều đó cũng giống như nói rằng trong giới hạn của N lớn, tôi muốn một vùng nhỏ R ∈ ( r , r + d r ), Θ ∈ ( θ , θ + d θ ) chứa một số điểm tỷ lệ với diện tích của nó, là r d r d θ . Bây giờ nếu chúng ta giả vờ rằng chúng ta đang nói về một biến ngẫu nhiên ở đây, thì điều này có một cách hiểu đơn giản là nói rằng mật độ xác suất chung cho ( R , Θ ) chỉ là cr đối với một số hằng sốc . Chuẩn hóa trên đĩa đơn vị sau đó sẽ buộc c = 1 / π.

Bây giờ hãy để tôi giới thiệu một thủ thuật. Nó xuất phát từ lý thuyết xác suất, nơi nó được gọi là lấy mẫu CDF nghịch đảo : giả sử bạn muốn tạo một biến ngẫu nhiên với mật độ xác suất f ( z ) và bạn có một biến ngẫu nhiên U ~ Uniform (0, 1), giống như đi ra từ random()trong hầu hết các ngôn ngữ lập trình. Làm thế nào để bạn làm điều này?

  1. Đầu tiên, hãy biến mật độ của bạn thành một hàm phân phối tích lũy hoặc CDF, chúng ta sẽ gọi là F ( z ). Hãy nhớ rằng một CDF tăng đơn điệu từ 0 đến 1 với đạo hàm f ( z ).
  2. Sau đó tính hàm ngược F -1 ( z ) của CDF .
  3. Bạn sẽ thấy rằng Z = F -1 ( U ) được phân phối theo mật độ mục tiêu. (Chú thích 3).

Bây giờ, mẹo xoắn ốc tỷ lệ vàng sẽ tạo khoảng trống cho các điểm chỉ ra trong một mẫu đồng đều độc đáo cho θ, vì vậy hãy tích hợp điều đó ra; đối với đĩa đơn vị chúng ta còn lại với F ( r ) = r 2 . Vì vậy, hàm ngược là F -1 ( u ) = u 1/2 , và do đó chúng ta sẽ tạo ra các điểm ngẫu nhiên trên đĩa theo tọa độ cực với r = sqrt(random()); theta = 2 * pi * random().

Bây giờ thay vì lấy mẫu ngẫu nhiên hàm nghịch đảo này, chúng tôi lấy mẫu đồng nhất và điều tốt đẹp về lấy mẫu đồng nhất là kết quả của chúng tôi về cách các điểm được trải ra trong giới hạn N lớn sẽ hoạt động như thể chúng tôi đã lấy mẫu ngẫu nhiên. Sự kết hợp này là thủ thuật. Thay vì random()chúng tôi sử dụng (arange(0, num_pts, dtype=float) + 0.5)/num_pts, ví dụ, nếu chúng tôi muốn lấy mẫu 10 điểm r = 0.05, 0.15, 0.25, ... 0.95. Chúng tôi lấy mẫu r một cách thống nhất để có được khoảng cách giữa các vùng bằng nhau và chúng tôi sử dụng gia số hướng dương để tránh các “vạch” điểm khủng khiếp trong đầu ra.

Bây giờ làm hoa hướng dương trên một quả cầu

Những thay đổi mà chúng ta cần thực hiện để chấm hình cầu bằng các điểm chỉ liên quan đến việc chuyển đổi tọa độ cực cho tọa độ cầu. Tất nhiên, tọa độ xuyên tâm không đi vào điều này bởi vì chúng ta đang ở trên một hình cầu đơn vị. Để giữ cho mọi thứ nhất quán hơn một chút ở đây, mặc dù tôi được đào tạo như một nhà vật lý, tôi sẽ sử dụng tọa độ của các nhà toán học trong đó 0 ≤ φ ≤ π là vĩ độ đi xuống từ cực và 0 ≤ θ ≤ 2π là kinh độ. Vì vậy, sự khác biệt so với ở trên là về cơ bản chúng ta đang thay thế biến r bằng φ .

Phần tử diện tích của chúng ta, trước đây là r d r d θ , bây giờ trở thành sin ( φ ) d φ d θ không phức tạp hơn nhiều . Vì vậy, mật độ khớp của chúng ta đối với khoảng cách đều là sin ( φ ) / 4π. Tích phân ra θ , ta tìm được f ( φ ) = sin ( φ ) / 2, do đó F ( φ ) = (1 - cos ( φ )) / 2. Đảo ngược điều này, chúng ta có thể thấy rằng một biến ngẫu nhiên đồng nhất sẽ giống như acos (1 - 2 u ), nhưng chúng ta lấy mẫu đồng nhất thay vì ngẫu nhiên, vì vậy thay vào đó chúng ta sử dụng φ k = acos (1 - 2 ( k+ 0,5) / N ). Và phần còn lại của thuật toán chỉ là chiếu điều này lên các tọa độ x, y và z:

from numpy import pi, cos, sin, arccos, arange
import mpl_toolkits.mplot3d
import matplotlib.pyplot as pp

num_pts = 1000
indices = arange(0, num_pts, dtype=float) + 0.5

phi = arccos(1 - 2*indices/num_pts)
theta = pi * (1 + 5**0.5) * indices

x, y, z = cos(theta) * sin(phi), sin(theta) * sin(phi), cos(phi);

pp.figure().add_subplot(111, projection='3d').scatter(x, y, z);
pp.show()

Một lần nữa cho n = 100 và n = 1000, kết quả giống như sau: nhập mô tả hình ảnh ở đây nhập mô tả hình ảnh ở đây

Nghiên cứu thêm

Tôi muốn gửi lời cảm ơn đến blog của Martin Roberts. Lưu ý rằng ở trên, tôi đã tạo phần bù cho các chỉ số của mình bằng cách thêm 0,5 vào mỗi chỉ mục. Điều này chỉ hấp dẫn về mặt thị giác đối với tôi, nhưng hóa ra việc lựa chọn độ lệch đóng vai trò rất nhiều và không cố định trong khoảng thời gian và có thể có nghĩa là có được độ chính xác tốt hơn 8% trong việc đóng gói nếu được chọn đúng. Cũng cần phải có một cách để chuỗi R 2 của anh ta bao phủ một quả cầu và sẽ rất thú vị nếu điều này cũng tạo ra một lớp phủ đồng đều đẹp mắt, có lẽ là như vậy nhưng có lẽ cần phải được lấy từ một nửa của hình vuông đơn vị được cắt theo đường chéo hoặc dài hơn và kéo dài xung quanh để được một hình tròn.

Ghi chú

  1. Các "vạch" đó được hình thành bởi các xấp xỉ hữu tỉ đối với một số và các xấp xỉ hữu tỉ tốt nhất đối với một số đến từ biểu thức phân số liên tục của nó, z + 1/(n_1 + 1/(n_2 + 1/(n_3 + ...)))trong đó zlà một số nguyên và n_1, n_2, n_3, ...là một dãy số nguyên dương hữu hạn hoặc vô hạn:

    def continued_fraction(r):
        while r != 0:
            n = floor(r)
            yield n
            r = 1/(r - n)

    Vì phần của phân số 1/(...)luôn nằm trong khoảng từ 0 đến 1, nên một số nguyên lớn trong phân số tiếp tục cho phép xấp xỉ hữu tỉ đặc biệt tốt: "một chia cho một số từ 100 đến 101" thì tốt hơn "một chia cho một số nào đó từ 1 đến 2" Do đó, số vô tỷ nhất là số có 1 + 1/(1 + 1/(1 + ...))và không có xấp xỉ hữu tỷ đặc biệt tốt; người ta có thể giải φ = 1 + 1 / φ bằng cách nhân với φ để được công thức của tỉ lệ vàng.

  2. Đối với những người không quá quen thuộc với NumPy - tất cả các chức năng đều được "vectơ hóa", vì vậy điều đó sqrt(array)giống với những gì các ngôn ngữ khác có thể viết map(sqrt, array). Vì vậy, đây là một sqrtứng dụng từng thành phần . Điều tương tự cũng xảy ra đối với phép chia cho một đại lượng vô hướng hoặc phép cộng với đại lượng vô hướng - những điều này áp dụng cho tất cả các thành phần song song.

  3. Việc chứng minh rất đơn giản khi bạn biết rằng đây là kết quả. Nếu bạn hỏi xác suất z < Z < z + d z là bao nhiêu , thì điều này cũng giống như hỏi xác suất z < F -1 ( U ) < z + d z là bao nhiêu , áp dụng F cho cả ba biểu thức, lưu ý rằng nó là một hàm tăng đơn điệu, do đó F ( z ) < U < F ( z + d z ), hãy mở rộng vế phải để tìm F ( z ) + f(z ) d z , và vì U là đồng nhất nên xác suất chỉ là f ( z ) d z như đã hứa.


4
Tôi không chắc tại sao điều này lại giảm đi rất nhiều, đây là phương pháp nhanh tốt nhất để làm điều này.
whn

2
@snb cảm ơn bạn vì những lời tốt đẹp! nó thấp hơn rất nhiều một phần vì nó trẻ hơn rất nhiều so với tất cả các câu trả lời còn lại ở đây. Tôi ngạc nhiên rằng nó thậm chí đang hoạt động tốt như nó đã được.
CR Drost

Một câu hỏi vẫn còn đối với tôi là: Tôi cần phân phối bao nhiêu điểm n để khoảng cách lớn nhất cho trước giữa hai điểm bất kỳ?
Felix D.

1
@FelixD. Điều đó nghe có vẻ như một câu hỏi có thể trở nên rất phức tạp rất nhanh, đặc biệt nếu bạn bắt đầu sử dụng, chẳng hạn như khoảng cách vòng tròn lớn hơn là khoảng cách Euclide. Nhưng có lẽ tôi có thể trả lời một câu hỏi đơn giản, nếu một người chuyển đổi các điểm trên hình cầu thành biểu đồ Voronoi của họ, người ta có thể mô tả mỗi ô Voronoi có diện tích xấp xỉ 4π / N và người ta có thể chuyển đổi điều này thành một khoảng cách đặc trưng bằng cách giả sử nó là một hình tròn chứ không phải hơn hình thoi, πr² = 4π / N. Khi đó r = 2 / √ (N).
CR Drost

2
Sử dụng định lý lấy mẫu với đầu vào thực sự đồng nhất thay vì đầu vào đồng nhất ngẫu nhiên là một trong những điều khiến tôi phải thốt lên "Chà, tại sao # $% & tôi không nghĩ đến điều đó?" . Đẹp.
dmckee --- cựu điều hành kitten

86

Đây được gọi là các điểm đóng gói trên một hình cầu, và không có (đã biết) giải pháp chung hoàn hảo. Tuy nhiên, có rất nhiều giải pháp không hoàn hảo. Ba phổ biến nhất dường như là:

  1. Tạo một mô phỏng . Coi mỗi điểm như một electron bị ràng buộc vào một hình cầu, sau đó chạy mô phỏng theo một số bước nhất định. Lực đẩy của các electron tự nhiên sẽ hướng hệ thống đến một trạng thái ổn định hơn, nơi mà các điểm càng xa nhau càng tốt.
  2. Từ chối siêu khối . Phương pháp nghe có vẻ lạ lùng này thực sự rất đơn giản: bạn chọn đồng nhất các điểm (nhiều hơn nchúng) bên trong khối lập phương bao quanh khối cầu, sau đó loại bỏ các điểm bên ngoài khối cầu. Coi các điểm còn lại dưới dạng vectơ và chuẩn hóa chúng. Đây là "mẫu" của bạn - hãy chọn ntrong số chúng bằng một số phương pháp (ngẫu nhiên, tham lam, v.v.).
  3. Xấp xỉ xoắn ốc . Bạn vạch một đường xoắn ốc xung quanh một hình cầu và phân bố đều các điểm xung quanh đường xoắn ốc. Do liên quan đến toán học, chúng phức tạp hơn để hiểu so với mô phỏng, nhưng nhanh hơn nhiều (và có thể liên quan đến ít mã hơn). Phổ biến nhất dường như là của Saff, et al .

Một biết thêm thông tin về vấn đề này có thể được tìm thấy ở đây


Tôi sẽ xem xét chiến thuật xoắn ốc mà andrew cooke được đăng bên dưới, tuy nhiên, bạn có thể vui lòng làm rõ sự khác biệt giữa những gì tôi muốn và "phân phối ngẫu nhiên đồng nhất" là gì không? Đó có phải chỉ là sự sắp xếp ngẫu nhiên 100% các điểm trên một hình cầu để chúng được đặt đồng nhất không? Cảm ơn đã giúp đỡ. :)
Bắt đầu

4
@Befall: "phân phối ngẫu nhiên đồng nhất" đề cập đến phân phối xác suất là đồng nhất - có nghĩa là khi chọn một điểm ngẫu nhiên trên hình cầu, mọi điểm đều có khả năng được chọn bằng nhau. Nó không liên quan gì đến sự phân phối không gian cuối cùng của các điểm, và do đó không liên quan gì đến câu hỏi của bạn.
BlueRaja - Danny Pflughoeft

Ahhh, được rồi, cảm ơn rất nhiều. Tìm kiếm câu hỏi của tôi dẫn đến rất nhiều câu trả lời cho cả hai và tôi thực sự không thể hiểu được điều nào là vô nghĩa đối với tôi.
Bắt đầu

Nói rõ hơn, mọi điểm đều không có xác suất được chọn. Tỷ số của xác suất mà điểm sẽ thuộc hai khu vực bất kỳ trên bề mặt của hình cầu, bằng tỷ số của các bề mặt.
AturSams

2
Liên kết cuối cùng hiện đã chết
Felix D.

10

Những gì bạn đang tìm kiếm được gọi là lớp phủ hình cầu . Bài toán che hình cầu rất khó và chưa biết lời giải trừ một số điểm nhỏ. Một điều chắc chắn là đã cho n điểm trên một mặt cầu thì luôn tồn tại hai điểm cách xa d = (4-csc^2(\pi n/6(n-2)))^(1/2)hoặc gần nhau hơn.

Nếu bạn muốn một phương pháp xác suất để tạo ra các điểm được phân bố đồng nhất trên một hình cầu, thật dễ dàng: tạo các điểm trong không gian một cách đồng nhất theo phân phối Gaussian (nó được tích hợp trong Java, không khó để tìm mã cho các ngôn ngữ khác). Vì vậy, trong không gian 3 chiều, bạn cần một cái gì đó như

Random r = new Random();
double[] p = { r.nextGaussian(), r.nextGaussian(), r.nextGaussian() };

Sau đó chiếu điểm lên hình cầu bằng cách chuẩn hóa khoảng cách của nó từ điểm gốc

double norm = Math.sqrt( (p[0])^2 + (p[1])^2 + (p[2])^2 ); 
double[] sphereRandomPoint = { p[0]/norm, p[1]/norm, p[2]/norm };

Phân bố Gauss theo n chiều là đối xứng cầu nên hình chiếu lên hình cầu là đều.

Tất nhiên, không có gì đảm bảo rằng khoảng cách giữa hai điểm bất kỳ trong tập hợp các điểm được tạo đồng nhất sẽ bị giới hạn bên dưới, vì vậy bạn có thể sử dụng từ chối để thực thi bất kỳ điều kiện nào như vậy mà bạn có thể có: có lẽ tốt nhất là tạo toàn bộ tập hợp và sau đó từ chối toàn bộ bộ sưu tập nếu cần thiết. (Hoặc sử dụng "từ chối sớm" để từ chối toàn bộ bộ sưu tập bạn đã tạo cho đến nay; chỉ cần không giữ một số điểm và bỏ các điểm khác.) Bạn có thể sử dụng công thức cho dở trên, trừ đi một số điểm chùng, để xác định khoảng cách tối thiểu giữa điểm dưới đây mà bạn sẽ từ chối một tập hợp điểm. Bạn sẽ phải tính n để chọn 2 khoảng cách, và xác suất bị từ chối sẽ phụ thuộc vào độ chùng; thật khó để nói như thế nào, vì vậy hãy chạy mô phỏng để có cảm nhận về các số liệu thống kê có liên quan.


Đã ủng hộ cho các biểu thức khoảng cách tối đa nhỏ nhất. Hữu ích để đặt giới hạn về số điểm bạn muốn sử dụng. Tuy nhiên, một tham chiếu đến một nguồn có thẩm quyền sẽ rất tốt.
dmckee --- con mèo con người điều hành cũ

6

Câu trả lời này dựa trên cùng một 'lý thuyết' được nêu rõ bởi câu trả lời này

Tôi thêm câu trả lời này là:
- Không có lựa chọn nào khác phù hợp với nhu cầu 'đồng nhất' cần 'tại chỗ' (hoặc không rõ ràng-rõ ràng như vậy). (Lưu ý để có được hành tinh giống như hành vi tìm kiếm phân phối đặc biệt mong muốn trong yêu cầu ban đầu, bạn chỉ cần từ chối từ danh sách hữu hạn k điểm được tạo đồng nhất một cách ngẫu nhiên (ngẫu nhiên đếm chỉ số trong k mục trở lại).
- Gần nhất cách khác buộc bạn phải quyết định 'N' theo 'trục góc', so với chỉ 'một giá trị của N' trên cả hai giá trị trục góc (mà ở số lượng thấp của N rất khó để biết điều gì có thể hoặc có thể không quan trọng ( ví dụ bạn muốn '5' điểm - vui vẻ))
--Hơn nữa, rất khó để 'tìm hiểu' cách phân biệt giữa các tùy chọn khác mà không có bất kỳ hình ảnh nào, vì vậy đây là tùy chọn này trông như thế nào (bên dưới) và triển khai sẵn sàng chạy đi kèm với nó.

với N ở 20:

nhập mô tả hình ảnh ở đây
và sau đó là N ở 80: nhập mô tả hình ảnh ở đây


đây là mã python3 sẵn sàng chạy, trong đó mô phỏng cũng chính là nguồn đó: " http://web.archive.org/web/20120421191837/http://www.cgafaq.info/wiki/Evenly_distributed_points_on_sphere " được tìm thấy bởi những người khác . (Âm mưu mà tôi đã bao gồm, sẽ kích hoạt khi chạy dưới dạng 'chính', được lấy từ: http://www.scipy.org/Cookbook/Matplotlib/mplot3D )

from math import cos, sin, pi, sqrt

def GetPointsEquiAngularlyDistancedOnSphere(numberOfPoints=45):
    """ each point you get will be of form 'x, y, z'; in cartesian coordinates
        eg. the 'l2 distance' from the origion [0., 0., 0.] for each point will be 1.0 
        ------------
        converted from:  http://web.archive.org/web/20120421191837/http://www.cgafaq.info/wiki/Evenly_distributed_points_on_sphere ) 
    """
    dlong = pi*(3.0-sqrt(5.0))  # ~2.39996323 
    dz   =  2.0/numberOfPoints
    long =  0.0
    z    =  1.0 - dz/2.0
    ptsOnSphere =[]
    for k in range( 0, numberOfPoints): 
        r    = sqrt(1.0-z*z)
        ptNew = (cos(long)*r, sin(long)*r, z)
        ptsOnSphere.append( ptNew )
        z    = z - dz
        long = long + dlong
    return ptsOnSphere

if __name__ == '__main__':                
    ptsOnSphere = GetPointsEquiAngularlyDistancedOnSphere( 80)    

    #toggle True/False to print them
    if( True ):    
        for pt in ptsOnSphere:  print( pt)

    #toggle True/False to plot them
    if(True):
        from numpy import *
        import pylab as p
        import mpl_toolkits.mplot3d.axes3d as p3

        fig=p.figure()
        ax = p3.Axes3D(fig)

        x_s=[];y_s=[]; z_s=[]

        for pt in ptsOnSphere:
            x_s.append( pt[0]); y_s.append( pt[1]); z_s.append( pt[2])

        ax.scatter3D( array( x_s), array( y_s), array( z_s) )                
        ax.set_xlabel('X'); ax.set_ylabel('Y'); ax.set_zlabel('Z')
        p.show()
        #end

được thử nghiệm ở số lượng thấp (N trong 2, 5, 7, 13, v.v.) và có vẻ hoạt động 'tốt'


5

Thử:

function sphere ( N:float,k:int):Vector3 {
    var inc =  Mathf.PI  * (3 - Mathf.Sqrt(5));
    var off = 2 / N;
    var y = k * off - 1 + (off / 2);
    var r = Mathf.Sqrt(1 - y*y);
    var phi = k * inc;
    return Vector3((Mathf.Cos(phi)*r), y, Mathf.Sin(phi)*r); 
};

Hàm trên nên chạy trong vòng lặp với tổng N vòng lặp và k vòng lặp hiện tại.

Nó dựa trên mẫu hạt hướng dương, ngoại trừ các hạt hướng dương được uốn cong thành nửa vòm, và lại thành hình cầu.

Đây là một bức ảnh, ngoại trừ việc tôi đặt máy ảnh nửa bên trong hình cầu để nó trông 2d thay vì 3 chiều vì máy ảnh có khoảng cách như nhau từ tất cả các điểm. http://3.bp.blogspot.com/-9lbPHLccQHA/USXf88_bvVI/AAAAAAAAADY/j7qhQsSZsA8/s640/sphere.jpg


2

Healpix giải quyết một vấn đề có liên quan chặt chẽ (tạo pixel hình cầu với các pixel diện tích bằng nhau):

http://healpix.sourceforge.net/

Nó có thể là quá mức cần thiết, nhưng có thể sau khi xem xét nó, bạn sẽ nhận ra một số thuộc tính tốt đẹp khác của nó rất thú vị đối với bạn. Nó không chỉ là một chức năng xuất ra một đám mây điểm.

Tôi đã hạ cánh ở đây để cố gắng tìm lại nó; tên "healpix" không chính xác gợi lên hình cầu ...


1

với một số điểm nhỏ, bạn có thể chạy mô phỏng:

from random import random,randint
r = 10
n = 20
best_closest_d = 0
best_points = []
points = [(r,0,0) for i in range(n)]
for simulation in range(10000):
    x = random()*r
    y = random()*r
    z = r-(x**2+y**2)**0.5
    if randint(0,1):
        x = -x
    if randint(0,1):
        y = -y
    if randint(0,1):
        z = -z
    closest_dist = (2*r)**2
    closest_index = None
    for i in range(n):
        for j in range(n):
            if i==j:
                continue
            p1,p2 = points[i],points[j]
            x1,y1,z1 = p1
            x2,y2,z2 = p2
            d = (x1-x2)**2+(y1-y2)**2+(z1-z2)**2
            if d < closest_dist:
                closest_dist = d
                closest_index = i
    if simulation % 100 == 0:
        print simulation,closest_dist
    if closest_dist > best_closest_d:
        best_closest_d = closest_dist
        best_points = points[:]
    points[closest_index]=(x,y,z)


print best_points
>>> best_points
[(9.921692138442777, -9.930808529773849, 4.037839326088124),
 (5.141893371460546, 1.7274947332807744, -4.575674650522637),
 (-4.917695758662436, -1.090127967097737, -4.9629263893193745),
 (3.6164803265540666, 7.004158551438312, -2.1172868271109184),
 (-9.550655088997003, -9.580386054762917, 3.5277052594769422),
 (-0.062238110294250415, 6.803105171979587, 3.1966101417463655),
 (-9.600996012203195, 9.488067284474834, -3.498242301168819),
 (-8.601522086624803, 4.519484132245867, -0.2834204048792728),
 (-1.1198210500791472, -2.2916581379035694, 7.44937337008726),
 (7.981831370440529, 8.539378431788634, 1.6889099589074377),
 (0.513546008372332, -2.974333486904779, -6.981657873262494),
 (-4.13615438946178, -6.707488383678717, 2.1197605651446807),
 (2.2859494919024326, -8.14336582650039, 1.5418694699275672),
 (-7.241410895247996, 9.907335206038226, 2.271647103735541),
 (-9.433349952523232, -7.999106443463781, -2.3682575660694347),
 (3.704772125650199, 1.0526567864085812, 6.148581714099761),
 (-3.5710511242327048, 5.512552040316693, -3.4318468250897647),
 (-7.483466337225052, -1.506434920354559, 2.36641535124918),
 (7.73363824231576, -8.460241422163824, -1.4623228616326003),
 (10, 0, 0)]

để cải thiện câu trả lời của tôi bạn nên thay đổi closest_index = i để closest_index = randchoice (i, j)
robert vua

1

Lấy hai yếu tố lớn nhất của bạn N, nếu N==20thì hai yếu tố lớn nhất là {5,4}, hoặc nói chung là {a,b}. Tính toán

dlat  = 180/(a+1)
dlong = 360/(b+1})

Đặt điểm đầu tiên của bạn tại {90-dlat/2,(dlong/2)-180}, điểm thứ hai {90-dlat/2,(3*dlong/2)-180}, điểm thứ 3 của bạn {90-dlat/2,(5*dlong/2)-180}, cho đến khi bạn vấp ngã một lần quanh thế giới, vào thời điểm bạn phải đến {75,150}khi bạn đi tiếp {90-3*dlat/2,(dlong/2)-180}.

Rõ ràng là tôi đang làm việc này theo độ trên bề mặt của trái đất hình cầu, với các quy ước thông thường để dịch +/- sang N / S hoặc E / W. Và rõ ràng điều này cung cấp cho bạn một phân phối hoàn toàn không ngẫu nhiên, nhưng nó đồng nhất và các điểm không bị chụm lại với nhau.

Để thêm một số mức độ ngẫu nhiên, bạn có thể tạo 2 phân phối chuẩn (với trung bình là 0 và std dev là {dlat / 3, dlong / 3} nếu thích hợp) và thêm chúng vào các điểm được phân phối đồng đều của bạn.


5
điều đó sẽ đẹp hơn rất nhiều nếu bạn làm việc trong sin (lat) hơn là lat. vì nó là như vậy, bạn sẽ nhận được rất nhiều chùm gần các cực.
andrew Cooke

1

chỉnh sửa: Điều này không trả lời câu hỏi OP định hỏi, hãy để nó ở đây trong trường hợp mọi người thấy nó hữu ích bằng cách nào đó.

Chúng tôi sử dụng quy tắc nhân xác suất, kết hợp với các số vô hạn. Điều này dẫn đến 2 dòng mã để đạt được kết quả mong muốn của bạn:

longitude: φ = uniform([0,2pi))
azimuth:   θ = -arcsin(1 - 2*uniform([0,1]))

(được xác định trong hệ tọa độ sau :)

nhập mô tả hình ảnh ở đây

Ngôn ngữ của bạn thường có một số nguyên thủy ngẫu nhiên thống nhất. Ví dụ: trong python, bạn có thể sử dụng random.random()để trả về một số trong phạm vi [0,1). Bạn có thể nhân số này với k để được một số ngẫu nhiên trong phạm vi [0,k). Vì vậy, trong python, uniform([0,2pi))sẽ có nghĩa là random.random()*2*math.pi.


Bằng chứng

Bây giờ chúng ta không thể chỉ định θ một cách đồng nhất, nếu không chúng ta sẽ kết tụ ở các cực. Chúng tôi muốn gán các xác suất tỷ lệ với diện tích bề mặt của hình nêm hình cầu (θ trong biểu đồ này thực tế là φ):

nhập mô tả hình ảnh ở đây

Một dịch chuyển góc dφ tại đường xích đạo sẽ dẫn đến dịch chuyển dφ * r. Độ dời đó sẽ như thế nào tại một phương vị tùy ý θ? Chà, bán kính từ trục z là r*sin(θ), vì vậy độ dài cung của "vĩ độ" giao với hình nêm là dφ * r*sin(θ). Do đó, chúng tôi tính toán phân phối tích lũy của khu vực cần lấy mẫu từ nó, bằng cách tích phân diện tích của lát cắt từ cực nam đến cực bắc.

nhập mô tả hình ảnh ở đây(nơi có thứ = dφ*r)

Bây giờ chúng tôi sẽ cố gắng lấy nghịch đảo của CDF để lấy mẫu từ nó: http://en.wikipedia.org/wiki/Inverse_transform_sampling

Đầu tiên, chúng tôi chuẩn hóa bằng cách chia gần như CDF của chúng tôi cho giá trị lớn nhất của nó. Điều này có tác dụng phụ là hủy bỏ dφ và r.

azimuthalCDF: cumProb = (sin(θ)+1)/2 from -pi/2 to pi/2

inverseCDF: θ = -sin^(-1)(1 - 2*cumProb)

Như vậy:

let x by a random float in range [0,1]
θ = -arcsin(1-2*x)

Điều này không tương đương với tùy chọn mà anh ta đã loại bỏ là "100% ngẫu nhiên"? sự hiểu biết của tôi là anh ấy muốn chúng cách đều nhau hơn là một phân phối ngẫu nhiên đồng nhất.
andrew Cooke

@ BlueRaja-DannyPflughoeft: Hừm, đủ công bằng. Tôi đoán rằng tôi đã không đọc câu hỏi cẩn thận như tôi nên có. Tôi vẫn để điều này ở đây trong trường hợp những người khác thấy nó hữu ích. Cảm ơn vì đã chỉ ra điều này.
ninjagecko

1

HOẶC ... để đặt 20 điểm, tính toán trung tâm của các mặt hình khối. Để có 12 điểm, hãy tìm các đỉnh của hình tứ diện. Đối với 30 điểm, điểm giữa của các cạnh của khối lập phương. bạn có thể làm điều tương tự với tứ diện, hình lập phương, khối đa diện và bát diện: một tập hợp các điểm nằm trên các đỉnh, một tập hợp các điểm nằm trên tâm của mặt và một tập hợp các điểm khác ở tâm các cạnh. Tuy nhiên, chúng không thể trộn lẫn.


Một ý tưởng hay, nhưng nó chỉ hiệu quả với 4, 6, 8, 12, 20, 24 hoặc 30 điểm.
Các Guy với The Hat

Nếu bạn muốn ăn gian, bạn có thể sử dụng tâm của các mặt và các đường thẳng đứng. Chúng sẽ không phải là khoảng cách tương đương mà là một khoảng gần đúng. Điều này là tốt vì nó xác định.
flagsofnerd

0
# create uniform spiral grid
numOfPoints = varargin[0]
vxyz = zeros((numOfPoints,3),dtype=float)
sq0 = 0.00033333333**2
sq2 = 0.9999998**2
sumsq = 2*sq0 + sq2
vxyz[numOfPoints -1] = array([(sqrt(sq0/sumsq)), 
                              (sqrt(sq0/sumsq)), 
                              (-sqrt(sq2/sumsq))])
vxyz[0] = -vxyz[numOfPoints -1] 
phi2 = sqrt(5)*0.5 + 2.5
rootCnt = sqrt(numOfPoints)
prevLongitude = 0
for index in arange(1, (numOfPoints -1), 1, dtype=float):
  zInc = (2*index)/(numOfPoints) -1
  radius = sqrt(1-zInc**2)

  longitude = phi2/(rootCnt*radius)
  longitude = longitude + prevLongitude
  while (longitude > 2*pi): 
    longitude = longitude - 2*pi

  prevLongitude = longitude
  if (longitude > pi):
    longitude = longitude - 2*pi

  latitude = arccos(zInc) - pi/2
  vxyz[index] = array([ (cos(latitude) * cos(longitude)) ,
                        (cos(latitude) * sin(longitude)), 
                        sin(latitude)])

4
Sẽ rất hữu ích nếu bạn viết một số văn bản giải thích ý nghĩa của việc này, vì vậy OP không cần phải tin rằng nó sẽ hoạt động.
hcarver

0

@robert king Đó là một giải pháp thực sự tốt nhưng có một số lỗi cẩu thả trong đó. Tôi biết nó đã giúp tôi rất nhiều, vì vậy đừng bận tâm đến sự luộm thuộm. :) Đây là một phiên bản đã được làm sạch ....

from math import pi, asin, sin, degrees
halfpi, twopi = .5 * pi, 2 * pi
sphere_area = lambda R=1.0: 4 * pi * R ** 2

lat_dist = lambda lat, R=1.0: R*(1-sin(lat))

#A = 2*pi*R^2(1-sin(lat))
def sphere_latarea(lat, R=1.0):
    if -halfpi > lat or lat > halfpi:
        raise ValueError("lat must be between -halfpi and halfpi")
    return 2 * pi * R ** 2 * (1-sin(lat))

sphere_lonarea = lambda lon, R=1.0: \
        4 * pi * R ** 2 * lon / twopi

#A = 2*pi*R^2 |sin(lat1)-sin(lat2)| |lon1-lon2|/360
#    = (pi/180)R^2 |sin(lat1)-sin(lat2)| |lon1-lon2|
sphere_rectarea = lambda lat0, lat1, lon0, lon1, R=1.0: \
        (sphere_latarea(lat0, R)-sphere_latarea(lat1, R)) * (lon1-lon0) / twopi


def test_sphere(n_lats=10, n_lons=19, radius=540.0):
    total_area = 0.0
    for i_lons in range(n_lons):
        lon0 = twopi * float(i_lons) / n_lons
        lon1 = twopi * float(i_lons+1) / n_lons
        for i_lats in range(n_lats):
            lat0 = asin(2 * float(i_lats) / n_lats - 1)
            lat1 = asin(2 * float(i_lats+1)/n_lats - 1)
            area = sphere_rectarea(lat0, lat1, lon0, lon1, radius)
            print("{:} {:}: {:9.4f} to  {:9.4f}, {:9.4f} to  {:9.4f} => area {:10.4f}"
                    .format(i_lats, i_lons
                    , degrees(lat0), degrees(lat1)
                    , degrees(lon0), degrees(lon1)
                    , area))
            total_area += area
    print("total_area = {:10.4f} (difference of {:10.4f})"
            .format(total_area, abs(total_area) - sphere_area(radius)))

test_sphere()

-1

Điều này hoạt động và nó đơn giản chết người. Bao nhiêu điểm tùy thích:

    private function moveTweets():void {


        var newScale:Number=Scale(meshes.length,50,500,6,2);
        trace("new scale:"+newScale);


        var l:Number=this.meshes.length;
        var tweetMeshInstance:TweetMesh;
        var destx:Number;
        var desty:Number;
        var destz:Number;
        for (var i:Number=0;i<this.meshes.length;i++){

            tweetMeshInstance=meshes[i];

            var phi:Number = Math.acos( -1 + ( 2 * i ) / l );
            var theta:Number = Math.sqrt( l * Math.PI ) * phi;

            tweetMeshInstance.origX = (sphereRadius+5) * Math.cos( theta ) * Math.sin( phi );
            tweetMeshInstance.origY= (sphereRadius+5) * Math.sin( theta ) * Math.sin( phi );
            tweetMeshInstance.origZ = (sphereRadius+5) * Math.cos( phi );

            destx=sphereRadius * Math.cos( theta ) * Math.sin( phi );
            desty=sphereRadius * Math.sin( theta ) * Math.sin( phi );
            destz=sphereRadius * Math.cos( phi );

            tweetMeshInstance.lookAt(new Vector3D());


            TweenMax.to(tweetMeshInstance, 1, {scaleX:newScale,scaleY:newScale,x:destx,y:desty,z:destz,onUpdate:onLookAtTween, onUpdateParams:[tweetMeshInstance]});

        }

    }
    private function onLookAtTween(theMesh:TweetMesh):void {
        theMesh.lookAt(new Vector3D());
    }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.