
# randScatter3D.py
'''

Note that the inverse cosine is required for the same reason that the sqrt is required in randScatter.py.

https://extremelearning.com.au/how-to-generate-uniformly-random-points-on-n-spheres-and-n-balls/

'''

import random, math
import matplotlib.pyplot as plt
import numpy as np


NUM_PTS = 1000

def drawSphere(ax):
  alphas, thetas = np.mgrid[0.0:np.pi:100j, 
                          0.0:2.0*np.pi:100j]
  xcs = radius*np.cos(thetas)*np.sin(alphas)
  ycs = radius*np.sin(thetas)*np.sin(alphas)
  zcs = radius*np.cos(alphas)
  ax.plot_surface(xcs, ycs, zcs,  
               rstride=1, cstride=1, color='c', 
               alpha=0.3, linewidth=0)

# random coordinates
xs = [0]*NUM_PTS
ys = [0]*NUM_PTS
zs = [0]*NUM_PTS
radius = 1 
for i in range(NUM_PTS):
  theta = 2*math.pi*random.random()
  alpha = math.pi*random.random()
  # alpha = math.acos(1-2*random.random()) # for uniformity
  xs[i] = radius*math.cos(theta)*math.sin(alpha)
  ys[i] = radius*math.sin(theta)*math.sin(alpha)
  zs[i] = radius*math.cos(alpha)


fig = plt.figure(figsize=(7, 7))
ax = fig.add_subplot(projection='3d')

drawSphere(ax)
ax.scatter(xs, ys, zs, color="k",s=10)

ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
plt.axis('scaled')
plt.title("Random 3D Polar Coordinates")
plt.show()
