กระจาย n จุดบนทรงกลมอย่างเท่าเทียมกัน


121

ฉันต้องการอัลกอริทึมที่สามารถกำหนดตำแหน่งรอบ ๆ ทรงกลมสำหรับ N พอยต์ (อาจน้อยกว่า 20) ที่กระจายออกไปอย่างคลุมเครือ ไม่จำเป็นต้องมี "ความสมบูรณ์แบบ" แต่ฉันแค่ต้องการมันจึงไม่มีสิ่งใดมารวมกัน

  • คำถามนี้ให้รหัสที่ดี แต่ฉันไม่สามารถหาวิธีสร้างเครื่องแบบนี้ได้เนื่องจากดูเหมือนจะสุ่ม 100%
  • บล็อกโพสต์ที่แนะนำนี้มีสองวิธีในการป้อนจำนวนจุดบนทรงกลม แต่อัลกอริทึมSaff และ Kuijlaarsอยู่ในรหัส psuedocode ที่ฉันสามารถถอดเสียงได้และตัวอย่างโค้ดที่ฉันพบมี "node [k]" ซึ่งฉันทำไม่ได้ ดูอธิบายและทำลายความเป็นไปได้นั้น ตัวอย่างบล็อกที่สองคือ Golden Section Spiral ซึ่งทำให้ฉันได้ผลลัพธ์ที่แปลกประหลาดโดยไม่มีวิธีที่ชัดเจนในการกำหนดรัศมีคงที่
  • อัลกอริทึมจากคำถามนี้ดูเหมือนจะใช้งานได้ แต่ฉันไม่สามารถปะติดปะต่อสิ่งที่อยู่ในหน้านั้นเป็น psuedocode หรืออะไรก็ได้

คำถามอื่น ๆ อีกสองสามหัวข้อที่ฉันพบพูดถึงการกระจายสม่ำเสมอแบบสุ่มซึ่งเพิ่มระดับความซับซ้อนที่ฉันไม่กังวล ฉันขอโทษที่นี่เป็นคำถามโง่ ๆ แต่ฉันต้องการแสดงให้เห็นว่าฉันดูยากจริงๆและยังคิดสั้น

ดังนั้นสิ่งที่ฉันกำลังมองหาคือ pseudocode ง่าย ๆ ที่จะกระจายจุด N ให้เท่า ๆ กันรอบ ๆ หน่วยทรงกลมซึ่งจะส่งกลับในพิกัดทรงกลมหรือคาร์ทีเซียน ยิ่งไปกว่านั้นถ้ามันสามารถกระจายได้ด้วยการสุ่มเล็กน้อย (คิดว่าดาวเคราะห์รอบ ๆ ดาวฤกษ์กระจายออกอย่างเหมาะสม แต่มีที่ว่างสำหรับคั่งค้าง)


คุณหมายถึงอะไร "ด้วยการสุ่มเล็กน้อย"? คุณหมายถึงการก่อกวนในบางแง่?
ninjagecko

32
OP งง. สิ่งที่เขากำลังมองหาคือการใส่ n-point บนทรงกลมเพื่อให้ระยะห่างต่ำสุดระหว่างสองจุดใด ๆ มีขนาดใหญ่ที่สุด สิ่งนี้จะทำให้คะแนนมีลักษณะ "กระจายอย่างสม่ำเสมอ" ทั่วทั้งทรงกลม สิ่งนี้ไม่เกี่ยวข้องอย่างสิ้นเชิงกับการสร้างการกระจายแบบสุ่มที่สม่ำเสมอบนทรงกลมซึ่งเป็นสิ่งที่ลิงก์เหล่านี้เกี่ยวข้องกับคำตอบด้านล่างนี้กำลังพูดถึง
BlueRaja - Danny Pflughoeft

1
20 คะแนนไม่มากที่จะวางบนทรงกลมหากคุณไม่ต้องการให้มันดูสุ่ม
John Alexiou

2
นี่คือวิธีการทำ (มีตัวอย่างโค้ด): pdfs.semanticscholar.org/97a6/… (ดูเหมือนว่าจะใช้การคำนวณแรงขับไล่)
trusktr

1
แน่นอนสำหรับค่า N ใน {4, 6, 8, 12, 20} มีคำตอบที่แน่นอนซึ่งระยะห่างจากแต่ละจุดถึง (แต่ละจุด) เพื่อนบ้านที่ใกล้ที่สุดจะเป็นค่าคงที่สำหรับทุกจุดและเพื่อนบ้านที่ใกล้ที่สุดทั้งหมด
dmckee --- อดีตผู้ดูแลลูกแมว

คำตอบ:


13

ในโค้ดตัวอย่างนี้ node[k]เป็นเพียงโหนด kth คุณกำลังสร้างอาร์เรย์ N จุดและnode[k]เป็น kth (จาก 0 ถึง N-1) หากนั่นคือสิ่งที่ทำให้คุณสับสนหวังว่าคุณจะสามารถใช้มันได้ในตอนนี้

(กล่าวอีกนัยหนึ่งkคืออาร์เรย์ขนาด N ที่กำหนดไว้ก่อนที่ส่วนของโค้ดจะเริ่มต้นและประกอบด้วยรายการของจุด)

หรือสร้างคำตอบอื่น ๆ ที่นี่ (และใช้ 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

หากคุณวางแผนไว้คุณจะเห็นว่าระยะห่างแนวตั้งมีขนาดใหญ่กว่าใกล้กับเสาเพื่อให้แต่ละจุดตั้งอยู่ในพื้นที่ทั้งหมดเท่ากัน (ใกล้กับเสามีพื้นที่ "แนวนอน" น้อยกว่าดังนั้นจึงให้ "แนวตั้ง" มากกว่า )

สิ่งนี้ไม่เหมือนกับทุกจุดที่มีระยะห่างเท่ากันกับเพื่อนบ้าน (ซึ่งเป็นสิ่งที่ฉันคิดว่าลิงก์ของคุณกำลังพูดถึง) แต่อาจเพียงพอสำหรับสิ่งที่คุณต้องการและปรับปรุงเพียงแค่สร้างเส้นตาราง lat / lon ที่สม่ำเสมอ .


ดีมันเป็นเรื่องดีที่ได้เห็นวิธีแก้ปัญหาทางคณิตศาสตร์ ฉันคิดว่าจะใช้การแยกความยาวของเกลียวและส่วนโค้ง ฉันยังไม่แน่ใจว่าจะหาทางออกที่ดีที่สุดได้อย่างไรซึ่งเป็นปัญหาที่น่าสนใจ
robert king

คุณเห็นไหมว่าฉันแก้ไขคำตอบของฉันเพื่อรวมคำอธิบายของโหนด [k] ที่ด้านบน ฉันคิดว่านั่นอาจเป็นทั้งหมดที่คุณต้องการ ...
andrew cooke

วิเศษมากขอบคุณสำหรับคำอธิบาย ฉันจะลองใช้ในภายหลังเนื่องจากตอนนี้ฉันยังไม่มีเวลา แต่ขอบคุณมากที่ช่วยฉันออกไป ฉันจะแจ้งให้คุณทราบว่ามันทำงานตามวัตถุประสงค์ของฉันอย่างไร ^^
เกิด

การใช้วิธี Spiral เหมาะกับความต้องการของฉันอย่างสมบูรณ์ขอบคุณมากสำหรับความช่วยเหลือและคำชี้แจง :)
เกิดขึ้น

13
ลิงก์ดูเหมือนจะตาย
Scheintod

140

อัลกอริทึม Fibonacci sphere นั้นยอดเยี่ยมสำหรับสิ่งนี้ รวดเร็วและให้ผลลัพธ์ที่เพียงแวบเดียวจะหลอกสายตามนุษย์ได้อย่างง่ายดาย คุณสามารถดูตัวอย่างที่ทำการประมวลผลซึ่งจะแสดงผลลัพธ์เมื่อเวลาผ่านไปเมื่อมีการเพิ่มคะแนน นี่คืออีกหนึ่งตัวอย่างเชิงโต้ตอบที่ยอดเยี่ยมที่สร้างโดย @gman และนี่คือการนำไปใช้งานง่ายๆใน 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

ตัวอย่าง 1,000 รายการให้สิ่งนี้แก่คุณ:

ใส่คำอธิบายภาพที่นี่


ตัวแปร n ถูกเรียกเมื่อกำหนด phi: phi = ((i + rnd)% n) * Increment n = ตัวอย่างหรือไม่
Andrew Staroscik

@AndrewStaroscik ใช่! เมื่อฉันเขียนโค้ดครั้งแรกฉันใช้ "n" เป็นตัวแปรและเปลี่ยนชื่อในภายหลัง แต่ไม่ได้ทำการตรวจสอบสถานะ ขอบคุณที่จับได้!
Fnord


4
@ Xarbrough รหัสจะให้คะแนนรอบ ๆ หน่วยทรงกลมดังนั้นเพียงแค่คูณแต่ละจุดด้วยสเกลาร์ที่คุณต้องการสำหรับรัศมี
Fnord

2
@ ฟอร์ด: เราสามารถทำสิ่งนี้เพื่อมิติที่สูงขึ้นได้ไหม?
pikachuchameleon

108

วิธีเกลียวทอง

คุณบอกว่าคุณไม่สามารถใช้วิธีเกลียวทองได้ผลและนั่นเป็นเรื่องน่าเสียดายเพราะมันดีมากจริงๆ ฉันอยากจะให้คุณเข้าใจอย่างถ่องแท้เพื่อที่คุณจะได้เข้าใจว่าจะทำอย่างไรเพื่อไม่ให้สิ่งนี้ "ถูกมัด"

ต่อไปนี้เป็นวิธีที่รวดเร็วและไม่สุ่มในการสร้างโครงตาข่ายที่ถูกต้องโดยประมาณ ตามที่กล่าวไว้ข้างต้นไม่มีโครงตาข่ายใดที่สมบูรณ์แบบ แต่อาจจะดีพอ เมื่อเทียบกับวิธีอื่น ๆ เช่นที่BendWavy.orgแต่ก็มีรูปลักษณ์ที่สวยงามและสวยงามรวมถึงการรับประกันเกี่ยวกับการเว้นระยะห่างในขีด จำกัด

รองพื้น: ดอกทานตะวันเกลียวบนดิสก์ยูนิต

เพื่อทำความเข้าใจอัลกอริทึมนี้ก่อนอื่นฉันขอเชิญคุณดูอัลกอริทึมเกลียวดอกทานตะวัน 2 มิติ นี่ขึ้นอยู่กับความจริงที่ว่าจำนวนที่ไม่ลงตัวที่สุดคืออัตราส่วนทองคำ(1 + sqrt(5))/2และถ้าใครปล่อยคะแนนออกมาโดยวิธี“ ยืนอยู่ที่จุดศูนย์กลางให้เปลี่ยนอัตราส่วนทองคำของรอบทั้งหมดจากนั้นปล่อยอีกจุดหนึ่งไปในทิศทางนั้น” หนึ่งสร้างโดยธรรมชาติ เกลียวซึ่งเมื่อคุณไปถึงจุดที่สูงขึ้นและสูงขึ้นอย่างไรก็ตามปฏิเสธที่จะมี 'แท่ง' ที่กำหนดไว้อย่างดีซึ่งจุดเรียงกัน (หมายเหตุ 1. )

อัลกอริทึมสำหรับการเว้นระยะห่างบนดิสก์คือ

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()

และให้ผลลัพธ์ที่ดูเหมือน (n = 100 และ n = 1000):

ใส่คำอธิบายภาพที่นี่

การเว้นจุดในแนวรัศมี

สิ่งสำคัญที่แปลกคือสูตรr = sqrt(indices / num_pts); ฉันมาที่นั่นได้อย่างไร (โน้ต 2.)

ฉันใช้สแควร์รูทตรงนี้เพราะฉันต้องการให้สิ่งเหล่านี้มีระยะห่างเท่ากันรอบ ๆ ดิสก์ นั่นก็เหมือนกับการบอกว่าในขีด จำกัด ของNขนาดใหญ่ฉันต้องการพื้นที่เล็กน้อยR ∈ ( r , r + d r ), Θ∈ ( θ , θ + d θ ) เพื่อให้มีจำนวนจุดตามสัดส่วนกับพื้นที่ ซึ่งเป็นR d R d θ ทีนี้ถ้าเราแกล้งทำเป็นว่าเรากำลังพูดถึงตัวแปรสุ่มตรงนี้มันมีการตีความอย่างตรงไปตรงมาว่าบอกว่าความหนาแน่นของความน่าจะเป็นร่วมสำหรับ ( R , Θ ) เป็นเพียงcrสำหรับค่าคงที่ = 1 / π . Normalization บนดิสก์ยูนิตจะบังคับให้c

ตอนนี้ให้ฉันแนะนำเคล็ดลับ มันมาจากทฤษฎีความน่าจะเป็นที่เรียกว่าการสุ่มตัวอย่าง CDF ผกผันสมมติว่าคุณต้องการสร้างตัวแปรสุ่มที่มีความหนาแน่นของความน่าจะเป็นf ( z ) และคุณมีตัวแปรสุ่มU ~ Uniform (0, 1) เช่นเดียวกับที่ออกมาจากrandom()ในภาษาโปรแกรมส่วนใหญ่ คุณจะทำอย่างไร?

  1. ขั้นแรกเปลี่ยนความหนาแน่นของคุณให้เป็นฟังก์ชันการแจกแจงสะสมหรือ CDF ซึ่งเราจะเรียกว่าF ( z ) โปรดจำไว้ว่า CDF จะเพิ่มขึ้นอย่างจำเจจาก 0 เป็น 1 ด้วยอนุพันธ์f ( z )
  2. จากนั้นคำนวณฟังก์ชันผกผันของ CDF F -1 ( z )
  3. คุณจะพบว่าZ = F -1 ( U ) กระจายตามความหนาแน่นของเป้าหมาย (หมายเหตุ 3)

ตอนนี้เคล็ดลับเกลียวอัตราส่วนทองคำจะชี้ให้เห็นในรูปแบบที่สวยงามสม่ำเสมอสำหรับθดังนั้นลองรวมมันเข้าด้วยกัน สำหรับดิสก์หน่วยที่เราจะเหลือF ( R ) = R 2 ดังนั้นฟังก์ชันผกผันคือF -1 ( u ) = u 1/2ดังนั้นเราจะสร้างจุดสุ่มบนดิสก์ในพิกัดเชิงขั้วด้วยr = sqrt(random()); theta = 2 * pi * random()และดังนั้นเราจะสร้างจุดสุ่มบนดิสก์ในพิกัดเชิงขั้วกับ

ตอนนี้แทนการสุ่มเก็บตัวอย่างฟังก์ชันผกผันนี้เรากำลังสม่ำเสมอสุ่มตัวอย่างมันและสิ่งที่ดีเกี่ยวกับการสุ่มตัวอย่างเครื่องแบบคือว่าผลของเราเกี่ยวกับวิธีการจุดกระจายออกไปในวงเงินที่มีขนาดใหญ่Nจะทำงานเป็นถ้าเราได้สุ่มมัน การรวมกันนี้เป็นเคล็ดลับ แทนการrandom()ที่เราใช้(arange(0, num_pts, dtype=float) + 0.5)/num_ptsเพื่อให้พูดว่าถ้าเราต้องการที่จะลิ้มลอง 10 r = 0.05, 0.15, 0.25, ... 0.95จุดที่พวกเขามี เราสุ่มตัวอย่างrอย่างสม่ำเสมอเพื่อให้ได้ระยะห่างของพื้นที่เท่ากันและเราใช้การเพิ่มของดอกทานตะวันเพื่อหลีกเลี่ยง "แท่ง" ที่น่ากลัวในเอาต์พุต

ตอนนี้ทำทานตะวันบนทรงกลม

การเปลี่ยนแปลงที่เราต้องทำเพื่อจุดทรงกลมด้วยจุดนั้นเกี่ยวข้องกับการเปลี่ยนพิกัดเชิงขั้วสำหรับพิกัดทรงกลมเท่านั้น แน่นอนว่าพิกัดแนวรัศมีจะไม่เข้าสู่สิ่งนี้เพราะเราอยู่ในหน่วยทรงกลม เพื่อให้สิ่งเล็ก ๆ น้อย ๆ ที่สอดคล้องเพิ่มเติมได้ที่นี่แม้ว่าฉันได้รับการฝึกฝนให้เป็นนักฟิสิกส์ฉันจะใช้พิกัดคณิตศาสตร์ที่ 0 ≤ ไว ≤เธมีเส้นรุ้งลงมาจากเสาและ 0 ≤ θ ≤2πมีเส้นแวง ดังนั้นความแตกต่างจากข้างต้นคือการที่เรามีพื้นแทนที่ตัวแปรRกับφ

องค์ประกอบพื้นที่ของเราซึ่งเป็นr d r d θตอนนี้กลายเป็นบาป ( φ ) d φ d θที่ไม่ซับซ้อนมากขึ้น ดังนั้นความหนาแน่นร่วมของเราสำหรับระยะห่างสม่ำเสมอจึงเป็นบาป ( φ ) / 4π เมื่อรวมออกθเราจะพบf ( φ ) = sin ( φ ) / 2 ดังนั้นF ( φ ) = (1 - cos ( φ )) / 2 เมื่อเปลี่ยนสิ่งนี้เราจะเห็นว่าตัวแปรสุ่มที่เหมือนกันจะมีลักษณะเหมือน acos (1-2 u ) แต่เราสุ่มตัวอย่างแบบสม่ำเสมอแทนที่จะสุ่มดังนั้นเราจึงใช้φ k = acos แทน (1 - 2 ( k+ 0.5) /N ). และส่วนที่เหลือของอัลกอริทึมกำลังฉายสิ่งนี้บนพิกัด x, y และ 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()

อีกครั้งสำหรับ n = 100 และ n = 1,000 ผลลัพธ์จะมีลักษณะดังนี้: ใส่คำอธิบายภาพที่นี่ ใส่คำอธิบายภาพที่นี่

การวิจัยต่อไป

ฉันอยากจะพูดถึงบล็อกของ Martin Roberts โปรดทราบว่าด้านบนฉันได้สร้างค่าชดเชยของดัชนีของฉันโดยเพิ่ม 0.5 ในแต่ละดัชนี นี่เป็นเพียงการดึงดูดสายตาสำหรับฉัน แต่ปรากฎว่าการเลือกออฟเซ็ตมีความสำคัญมากและไม่คงที่ตลอดช่วงเวลาและอาจหมายถึงความแม่นยำในการบรรจุที่ดีขึ้นถึง 8% หากเลือกอย่างถูกต้อง นอกจากนี้ยังควรมีวิธีที่จะทำให้ลำดับR 2ของเขาครอบคลุมทรงกลมและมันก็น่าสนใจที่จะดูว่าสิ่งนี้ให้การครอบคลุมที่ดีหรือไม่บางทีก็เป็นไปตามที่เป็นอยู่ แต่บางทีอาจจำเป็นต้องพูดโดยนำมาจากเพียงครึ่งหนึ่งของ สี่เหลี่ยมจัตุรัสของหน่วยตัดตามแนวทแยงมุมหรือมากกว่านั้นและยืดออกไปรอบ ๆ เพื่อให้ได้วงกลม

หมายเหตุ

  1. "แท่ง" เหล่านั้นเกิดจากการประมาณอย่างมีเหตุผลกับจำนวนและการประมาณอย่างมีเหตุผลที่ดีที่สุดสำหรับจำนวนมาจากนิพจน์เศษส่วนต่อเนื่องโดยz + 1/(n_1 + 1/(n_2 + 1/(n_3 + ...)))ที่zเป็นจำนวนเต็มและn_1, n_2, n_3, ...เป็นลำดับที่ จำกัด หรือไม่สิ้นสุดของจำนวนเต็มบวก:

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

    เนื่องจากส่วนที่เป็นเศษส่วน1/(...)อยู่ระหว่างศูนย์และหนึ่งเสมอจำนวนเต็มขนาดใหญ่ในเศษส่วนต่อเนื่องจึงช่วยให้สามารถหาค่าประมาณที่มีเหตุผลได้ดีโดยเฉพาะ: "หารด้วยค่าระหว่าง 100 ถึง 101" จะดีกว่า "หารด้วยค่าระหว่าง 1 ถึง 2" ดังนั้นจำนวนที่ไม่ลงตัวที่สุดจึงเป็นจำนวนที่มี1 + 1/(1 + 1/(1 + ...))และไม่มีการประมาณเชิงเหตุผลที่ดีเป็นพิเศษ เราสามารถแก้φ = 1 + 1 / φโดยการคูณด้วยφเพื่อรับสูตรสำหรับอัตราส่วนทองคำ

  2. สำหรับคนที่ไม่คุ้นเคยให้กับ NumPy - ทุกฟังก์ชั่นที่มี“vectorized” เพื่อให้sqrt(array)เป็นเช่นเดียวกับสิ่งที่ภาษาอื่น ๆ map(sqrt, array)อาจเขียน ดังนั้นนี่คือsqrtแอปพลิเคชันทีละองค์ประกอบ เช่นเดียวกันกับการหารด้วยสเกลาร์หรือการบวกด้วยสเกลาร์ซึ่งใช้กับส่วนประกอบทั้งหมดแบบขนาน

  3. การพิสูจน์นั้นง่ายมากเมื่อคุณรู้ว่านี่คือผลลัพธ์ ถ้าคุณถามว่าความน่าจะเป็นที่z < Z < z + d z เป็นเท่าใดนี่ก็เหมือนกับการถามความน่าจะเป็นที่z < F -1 ( U ) < z + d zคืออะไรให้ใช้Fกับทั้งสามนิพจน์โดยสังเกตว่าเป็น ฟังก์ชันที่เพิ่มขึ้นอย่างจำเจดังนั้นF ( z ) < U < F ( z + d z ) ให้ขยายด้านขวามือออกเพื่อค้นหาF ( z ) + f( z ) d zและเนื่องจากUสม่ำเสมอความน่าจะเป็นนี้จึงเป็นเพียงf ( z ) d zตามที่สัญญาไว้


4
ฉันไม่แน่ใจว่าทำไมมันถึงลดลงนี่เป็นวิธีที่รวดเร็วที่สุดในการทำเช่นนี้
WHN

2
@snb ขอบคุณสำหรับคำพูด! ส่วนหนึ่งมันลดลงไปมากเพราะมันอ่อนกว่าคำตอบที่เหลือทั้งหมดในนี้มาก ฉันแปลกใจที่มันทำได้ดีเหมือนที่เคยเป็นมา
CR Drost

คำถามหนึ่งที่ยังคงอยู่สำหรับฉันคือฉันต้องแจก n กี่คะแนนสำหรับระยะห่างสูงสุดที่กำหนดระหว่างสองจุดใด ๆ
Felix D.

1
@FelixD ฟังดูเหมือนคำถามที่อาจซับซ้อนมากอย่างรวดเร็วโดยเฉพาะอย่างยิ่งถ้าคุณเริ่มใช้พูดว่าระยะทางวงกลมใหญ่แทนที่จะเป็นระยะทางแบบยุคลิด แต่บางทีฉันสามารถตอบคำถามง่ายๆได้ถ้ามีคนแปลงจุดบนทรงกลมเป็นแผนภาพโวโรโนอิเราสามารถอธิบายเซลล์โวโรโนอิแต่ละเซลล์ได้ว่ามีพื้นที่ประมาณ4π / N และสามารถแปลงค่านี้เป็นระยะทางที่มีลักษณะเฉพาะได้โดยแกล้งทำเป็นวงกลมแทน กว่ารูปสี่เหลี่ยมขนมเปียกปูนπr² = 4π / N จากนั้น r = 2 / √ (N)
CR Drost

2
การใช้ทฤษฎีบทการสุ่มตัวอย่างกับเครื่องแบบจริงแทนการป้อนข้อมูลเครื่องแบบสุ่มเป็นสิ่งหนึ่งที่ทำให้ฉันพูดว่า"ทำไม # $% & ฉันไม่คิดอย่างนั้น" . ดี
dmckee --- อดีตผู้ดูแลลูกแมว

86

สิ่งนี้เรียกว่าจุดบรรจุบนทรงกลมและไม่มีวิธีแก้ปัญหาทั่วไปที่สมบูรณ์แบบ อย่างไรก็ตามมีวิธีแก้ปัญหาที่ไม่สมบูรณ์มากมาย สามที่ได้รับความนิยมมากที่สุดดูเหมือนจะเป็น:

  1. สร้างแบบจำลอง ถือว่าแต่ละจุดเป็นอิเล็กตรอนที่ถูก จำกัด ให้อยู่ในทรงกลมจากนั้นเรียกใช้การจำลองสำหรับขั้นตอนจำนวนหนึ่ง การขับไล่ของอิเล็กตรอนจะทำให้ระบบมีเสถียรภาพมากขึ้นโดยธรรมชาติซึ่งจุดต่างๆจะอยู่ห่างจากกันมากที่สุดเท่าที่จะทำได้
  2. hypercube ปฏิเสธ วิธีการทำให้เกิดเสียงแฟนซีนี้ง่ายมาก: คุณเลือกจุด(มากกว่าnของพวกเขา)อย่างสม่ำเสมอภายในลูกบาศก์รอบ ๆ ทรงกลมจากนั้นปฏิเสธจุดที่อยู่นอกทรงกลม ถือว่าจุดที่เหลือเป็นเวกเตอร์และทำให้เป็นปกติ นี่คือ "ตัวอย่าง" ของคุณ - เลือกnจากตัวอย่างโดยใช้วิธีการบางอย่าง (สุ่มโลภ ฯลฯ )
  3. ประมาณเกลียว คุณติดตามเกลียวรอบ ๆ ทรงกลมและกระจายจุดรอบ ๆ เกลียวให้เท่า ๆ กัน เนื่องจากคณิตศาสตร์เกี่ยวข้องสิ่งเหล่านี้จึงซับซ้อนในการทำความเข้าใจมากกว่าการจำลอง แต่เร็วกว่ามาก (และอาจเกี่ยวข้องกับรหัสน้อยกว่า) ความนิยมมากที่สุดน่าจะเป็นของSaff และอื่น

มากข้อมูลเพิ่มเติมเกี่ยวกับปัญหานี้สามารถพบได้ที่นี่


ฉันจะดูกลยุทธ์เกลียวที่ andrew cooke โพสต์ไว้ด้านล่างนี้โปรดอธิบายความแตกต่างระหว่างสิ่งที่ฉันต้องการและ "การแจกแจงแบบสุ่มสม่ำเสมอ" คืออะไร นั่นเป็นเพียงตำแหน่งสุ่ม 100% ของจุดบนทรงกลมเพื่อให้วางในตำแหน่งที่สม่ำเสมอหรือไม่? ขอบคุณสำหรับความช่วยเหลือ :)
เกิด

4
@Befall: "การแจกแจงแบบสุ่มสม่ำเสมอ" หมายถึงการแจกแจงความน่าจะเป็นที่สม่ำเสมอซึ่งหมายความว่าเมื่อเลือกจุดสุ่มบนทรงกลมทุกจุดมีโอกาสถูกเลือกเท่ากัน ไม่มีอะไรเกี่ยวข้องกับการกระจายประเด็นเชิงพื้นที่ขั้นสุดท้ายและไม่มีส่วนเกี่ยวข้องกับคำถามของคุณ
BlueRaja - Danny Pflughoeft

โอเคขอบคุณมาก การค้นหาคำถามของฉันนำไปสู่คำตอบมากมายสำหรับทั้งคู่และฉันไม่สามารถเข้าใจได้เลยว่าสิ่งที่ไม่มีจุดหมายสำหรับฉัน
เกิด

เพื่อความชัดเจนทุกจุดมีความน่าจะเป็นที่จะถูกเลือกเป็นศูนย์ อัตราส่วนของความน่าจะเป็นที่จุดจะเป็นของสองพื้นที่ใด ๆ บนพื้นผิวของทรงกลมจะเท่ากับอัตราส่วนของพื้นผิว
AturSams

2
ลิงค์สุดท้ายตายแล้ว
เฟลิกซ์ดี

10

สิ่งที่คุณกำลังมองหาที่เรียกว่าครอบคลุมทรงกลม ปัญหาการครอบคลุมทรงกลมนั้นยากมากและไม่ทราบวิธีแก้ปัญหายกเว้นจุดเล็ก ๆ สิ่งหนึ่งที่ทราบแน่ชัดก็คือการกำหนด n จุดบนทรงกลมจะมีระยะห่างd = (4-csc^2(\pi n/6(n-2)))^(1/2)หรือใกล้กว่าสองจุดเสมอ

หากคุณต้องการวิธีที่น่าจะเป็นในการสร้างจุดที่กระจายอย่างสม่ำเสมอบนทรงกลมทำได้ง่าย: สร้างจุดในอวกาศอย่างสม่ำเสมอโดยการแจกแจงแบบเกาส์เซียน (สร้างใน Java ไม่ใช่เรื่องยากที่จะหาโค้ดสำหรับภาษาอื่น) ดังนั้นในพื้นที่ 3 มิติคุณต้องมีบางอย่างเช่น

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

จากนั้นฉายจุดลงบนทรงกลมโดยกำหนดระยะห่างจากจุดกำเนิดให้เป็นปกติ

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

การแจกแจงแบบเสียนในขนาด n นั้นสมมาตรแบบทรงกลมดังนั้นการฉายภาพบนทรงกลมจึงมีความสม่ำเสมอ

แน่นอนว่าไม่มีการรับประกันว่าระยะห่างระหว่างสองจุดใด ๆ ในคอลเลกชันของจุดที่สร้างขึ้นอย่างสม่ำเสมอจะถูก จำกัด ไว้ด้านล่างดังนั้นคุณสามารถใช้การปฏิเสธเพื่อบังคับใช้เงื่อนไขใด ๆ ที่คุณอาจมี: อาจเป็นการดีที่สุดที่จะสร้างคอลเลกชันทั้งหมดแล้ว ปฏิเสธคอลเล็กชันทั้งหมดหากจำเป็น (หรือใช้ "การปฏิเสธก่อนกำหนด" เพื่อปฏิเสธคอลเลกชันทั้งหมดที่คุณสร้างไว้จนถึงตอนนี้อย่าเก็บคะแนนไว้และทิ้งคะแนนอื่น ๆ ) คุณสามารถใช้สูตรที่dระบุข้างต้นลบความหย่อนบางส่วนเพื่อกำหนดระยะห่างขั้นต่ำระหว่าง จุดด้านล่างซึ่งคุณจะปฏิเสธชุดคะแนน คุณจะต้องคำนวณ n เลือก 2 ระยะทางและความน่าจะเป็นของการปฏิเสธจะขึ้นอยู่กับระยะหย่อน ยากที่จะบอกว่าเป็นอย่างไรดังนั้นให้เรียกใช้การจำลองสถานการณ์เพื่อให้ทราบถึงสถิติที่เกี่ยวข้อง


เพิ่มขึ้นสำหรับนิพจน์ระยะทางสูงสุดต่ำสุด มีประโยชน์สำหรับการ จำกัด จำนวนคะแนนที่คุณต้องการใช้ การอ้างอิงถึงแหล่งที่มาที่เชื่อถือได้สำหรับสิ่งนั้นจะดี
dmckee --- อดีตผู้ดูแลลูกแมว

6

คำตอบนี้เป็นไปตาม 'ทฤษฎี' เดียวกันที่คำตอบนี้สรุปไว้เป็นอย่างดี

ฉันกำลังเพิ่มคำตอบนี้เป็น:
- ไม่มีตัวเลือกอื่นใดที่เหมาะกับ 'ความสม่ำเสมอ' ที่ต้องการ 'เฉพาะจุด' (หรือไม่ชัดเจนอย่างนั้น) (สังเกตว่าการได้รับดาวเคราะห์เช่นพฤติกรรมการมองการกระจายที่ต้องการโดยอนุภาคในการถามดั้งเดิมคุณเพียงแค่ปฏิเสธจากรายการ จำกัด ของจุดที่สร้างขึ้นอย่างสม่ำเสมอโดยการสุ่ม (สุ่มเขียนจำนวนดัชนีในรายการ k กลับ) -
- ใกล้เคียงที่สุด นัยอื่น ๆ บังคับให้คุณตัดสินใจ 'N' โดย 'แกนเชิงมุม' เทียบกับ 'ค่าเดียวของ N' ในค่าแกนเชิงมุมทั้งสองค่า (ซึ่งการนับ N ที่ต่ำนั้นเป็นเรื่องยากมากที่จะรู้ว่าอะไรอาจหรือไม่สำคัญ ( เช่นคุณต้องการ '5' คะแนน - สนุก))
- ยิ่งไปกว่านั้นมันยากมากที่จะ 'ควานหา' วิธีแยกความแตกต่างระหว่างตัวเลือกอื่น ๆ โดยไม่มีภาพใด ๆ ดังนั้นนี่คือลักษณะของตัวเลือกนี้ (ด้านล่าง) และการใช้งานที่พร้อมใช้งาน

กับ N ที่ 20:

ใส่คำอธิบายภาพที่นี่
แล้ว N ที่ 80: ใส่คำอธิบายภาพที่นี่


นี่คือโค้ด python3 ที่พร้อมรันซึ่งการจำลองเป็นแหล่งเดียวกัน: " http://web.archive.org/web/20120421191837/http://www.cgafaq.info/wiki/Evenly_distributed_points_on_sphere " ที่พบโดยผู้อื่น . (การวางพล็อตที่ฉันรวมไว้ซึ่งจะเริ่มทำงานเมื่อทำงานเป็น 'main' นำมาจาก: 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

ทดสอบที่จำนวนน้อย (N ใน 2, 5, 7, 13 ฯลฯ ) และดูเหมือนจะทำงานได้ดี


5

ลอง:

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); 
};

ฟังก์ชันข้างต้นควรทำงานแบบวนซ้ำโดยมีการวนซ้ำ N loop และ k วนซ้ำปัจจุบัน

มันขึ้นอยู่กับรูปแบบเมล็ดทานตะวันยกเว้นเมล็ดทานตะวันจะโค้งรอบเป็นโดมครึ่งหนึ่งและอีกครั้งเป็นทรงกลม

นี่คือภาพยกเว้นว่าฉันวางกล้องไว้ครึ่งทางภายในทรงกลมดังนั้นมันจึงดูเป็น 2d แทนที่จะเป็น 3d เพราะกล้องอยู่ห่างจากทุกจุดเท่ากัน http://3.bp.blogspot.com/-9lbPHLccQHA/USXf88_bvVI/AAAAAAAAADY/j7qhQsSZsA8/s640/sphere.jpg


2

Healpix แก้ปัญหาที่เกี่ยวข้องอย่างใกล้ชิด (การสร้างพิกเซลทรงกลมด้วยพิกเซลพื้นที่เท่ากัน):

http://healpix.sourceforge.net/

มันอาจจะมากเกินไป แต่หลังจากดูแล้วคุณจะรู้ว่ามีคุณสมบัติดีๆอื่น ๆ ที่น่าสนใจสำหรับคุณ เป็นมากกว่าฟังก์ชันที่ส่งออกพอยต์คลาวด์

ฉันมาที่นี่เพื่อพยายามค้นหามันอีกครั้ง ชื่อ "ฮีลพิกซ์" ไม่ได้ทำให้เกิดทรงกลม ...


1

ด้วยจุดเล็ก ๆ น้อย ๆ ที่คุณสามารถเรียกใช้การจำลอง:

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)]

เพื่อปรับปรุงคำตอบของฉันคุณควรเปลี่ยน closest_index = i เป็น closest_index = randchoice (i, j)
robert king

1

พิจารณาปัจจัยที่ใหญ่ที่สุดสองประการของคุณNถ้าN==20ปัจจัยที่ใหญ่ที่สุดสองประการคือ{5,4}หรือโดยทั่วไป{a,b}แล้ว คำนวณ

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

วางจุดแรกของคุณที่{90-dlat/2,(dlong/2)-180}สองของคุณใน{90-dlat/2,(3*dlong/2)-180}3 ของคุณได้{90-dlat/2,(5*dlong/2)-180}จนกว่าคุณจะได้สะดุดรอบโลกครั้งตามเวลาที่คุณได้มีการเกี่ยวกับเมื่อคุณไปติดกับ{75,150}{90-3*dlat/2,(dlong/2)-180}

เห็นได้ชัดว่าฉันกำลังทำงานเป็นองศาบนพื้นผิวของโลกทรงกลมโดยมีแบบแผนปกติสำหรับการแปล +/- เป็น N / S หรือ E / W และเห็นได้ชัดว่าสิ่งนี้ทำให้คุณได้การแจกแจงแบบไม่สุ่ม แต่มีความสม่ำเสมอและจุดไม่รวมกัน

ในการเพิ่มระดับของการสุ่มคุณสามารถสร้าง 2 แบบกระจายตามปกติ (โดยมีค่าเฉลี่ย 0 และ std dev ของ {dlat / 3, dlong / 3} ตามความเหมาะสม) และเพิ่มลงในจุดที่กระจายอย่างสม่ำเสมอ


5
นั่นจะดูดีกว่ามากถ้าคุณทำงานใน sin (lat) มากกว่า lat ตามที่เป็นอยู่คุณจะได้รับจำนวนมากใกล้กับเสา
andrew cooke

1

แก้ไข:นี่ไม่ได้ตอบคำถามที่ OP ตั้งใจจะถามปล่อยไว้ที่นี่เผื่อว่าจะมีประโยชน์

เราใช้กฎการคูณของความน่าจะเป็นรวมกับ infinitessimals ผลลัพธ์นี้เป็นโค้ด 2 บรรทัดเพื่อให้ได้ผลลัพธ์ที่คุณต้องการ:

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

(กำหนดไว้ในระบบพิกัดต่อไปนี้ :)

ใส่คำอธิบายภาพที่นี่

โดยทั่วไปภาษาของคุณจะมีตัวเลขสุ่มแบบดั้งเดิม ยกตัวอย่างเช่นในหลามคุณสามารถใช้เพื่อกลับตัวเลขในช่วงrandom.random() [0,1)คุณสามารถคูณจำนวนนี้โดย k [0,k)ที่จะได้รับจำนวนสุ่มในช่วง เพราะฉะนั้นในหลามจะหมายถึงuniform([0,2pi))random.random()*2*math.pi


พิสูจน์

ตอนนี้เราไม่สามารถกำหนดθให้เท่ากันได้มิฉะนั้นเราจะจับกันเป็นก้อนที่เสา เราต้องการกำหนดความน่าจะเป็นเป็นสัดส่วนกับพื้นที่ผิวของลิ่มทรงกลม (จริง ๆ แล้วθในแผนภาพนี้คือφ):

ใส่คำอธิบายภาพที่นี่

การกระจัดเชิงมุมdφที่เส้นศูนย์สูตรจะทำให้เกิดการกระจัดของdφ * r การกระจัดนั้นจะเป็นอย่างไรในแนวราบโดยพลการθ? ดีรัศมีจากแกน z เป็นr*sin(θ)ดังนั้นความยาวส่วนโค้งของ "รุ้ง" dφ * r*sin(θ)การตัดลิ่มคือ ดังนั้นเราจึงคำนวณการแจกแจงสะสมของพื้นที่ที่จะสุ่มตัวอย่างโดยการรวมพื้นที่ของชิ้นส่วนจากขั้วใต้ไปยังขั้วเหนือ

ใส่คำอธิบายภาพที่นี่(ที่สิ่ง = dφ*r)

ตอนนี้เราจะพยายามหาค่าผกผันของ CDF เพื่อสุ่มตัวอย่างจากมัน: http://en.wikipedia.org/wiki/Inverse_transform_sampling

อันดับแรกเราทำให้ปกติโดยหาร CDF เกือบของเราด้วยค่าสูงสุด สิ่งนี้มีผลข้างเคียงของการยกเลิกdφและ r

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

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

ดังนั้น:

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

สิ่งนี้ไม่เทียบเท่ากับตัวเลือกที่เขาทิ้งไปว่าเป็นแบบ "สุ่ม 100%" หรือเปล่า? ความเข้าใจของฉันคือเขาต้องการให้พวกมันมีระยะห่างเท่า ๆ กันมากกว่าการแจกแจงแบบสุ่มสม่ำเสมอ
andrew cooke

@ BlueRaja-DannyPflughoeft: อืมยุติธรรมพอแล้ว ฉันเดาว่าฉันไม่ได้อ่านคำถามอย่างระมัดระวังเท่าที่ควร ฉันปล่อยไว้ที่นี่ต่อไปเผื่อว่าคนอื่นจะเห็นว่ามีประโยชน์ ขอบคุณที่ชี้ให้เห็น
ninjagecko

1

หรือ ... เพื่อวาง 20 จุดให้คำนวณจุดศูนย์กลางของใบหน้าน้ำแข็ง สำหรับ 12 จุดให้หาจุดยอดของ icosahedron สำหรับ 30 คะแนนคือจุดกึ่งกลางของขอบของ icosahedron คุณสามารถทำสิ่งเดียวกันกับจัตุรมุขลูกบาศก์เดคาฮีดรอนและแปดเหลี่ยม: จุดหนึ่งชุดอยู่บนจุดยอดอีกชุดหนึ่งที่กึ่งกลางของใบหน้าและอีกจุดหนึ่งที่กึ่งกลางของขอบ อย่างไรก็ตามไม่สามารถผสมกันได้


เป็นความคิดที่ดี แต่ใช้ได้กับ 4, 6, 8, 12, 20, 24 หรือ 30 คะแนนเท่านั้น
The Guy with The Hat

หากคุณต้องการโกงคุณสามารถใช้กึ่งกลางใบหน้าและแนวตั้ง พวกเขาจะไม่เว้นระยะเท่ากัน แต่เป็นค่าประมาณที่เหมาะสม นี่เป็นสิ่งที่ดีเพราะมันถูกกำหนด
chessofnerd

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
มันจะมีประโยชน์ถ้าคุณเขียนข้อความอธิบายว่าสิ่งนี้มีไว้เพื่ออะไรดังนั้น OP จึงไม่จำเป็นต้องเชื่อว่ามันจะได้ผล
hcarver

0

@robert king เป็นทางออกที่ดีจริงๆ แต่มีข้อบกพร่องบางอย่างอยู่ในนั้น ฉันรู้ว่ามันช่วยฉันได้มากดังนั้นอย่ารังเกียจความเลอะเทอะ :) นี่คือเวอร์ชันที่ล้างแล้ว ....

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

มันได้ผลและมันง่ายมาก คะแนนมากเท่าที่คุณต้องการ:

    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());
    }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.