Then, I decided to try 3 dimensions. The way to do this would be to think of the shape as a tube that is bent
Seems like you are trying to generate random points inside the volume of a torus (or half a torus). Instead of following your approach (a series of disks), I suggest a different one. First, you need to parameterize the torus.
Then, you need to generate the random distribution of points.
Let's put the pieces together. I'm going to use Plotly as it has an equal aspect ratio for 3d plots. Obviously, you can also apply offsets to the dataset.
import numpy as np
def random_dist_torus(a, c, n_low=1000, n_high=10000):
"""
Parameters
c: radius from the center of the hole to the center of the torus
a: radius of the tube
n_low: minimum number of points in the volume
n_high: maximum number of points in the volume
"""
n = int(np.random.uniform(n_low, n_high))
# consider a cross section of the torus, which is going
# to be a circle. The variable r represents the radius
# of the points in this cross section.
r = a * np.random.uniform(0, 1, n)
# u: angular coordinate of the torus. Here I set it
# to np.pi, so it will generate only half torus
u = np.pi * np.random.uniform(0, 1, n)
# v: circumferential coordinate. Consider a cross section
# of a torus, which is going to be a circle. v represents
# the angle around this circle.
v = 2 * np.pi * np.random.uniform(0, 1, n)
return (
(c + r * np.cos(v)) * np.cos(u), # x-coordinates
(c + r * np.cos(v)) * np.sin(u), # y-coordinates
r * np.sin(v) # z-coordinates
)
import plotly.graph_objects as go
x1, y1, z1 = random_dist_torus(2, 4)
x2, y2, z2 = random_dist_torus(2, 4)
fig = go.Figure(
data=[
go.Scatter3d(
x=x1, y=y1, z=z1,
mode='markers',
marker=dict(
size=2,
)
),
go.Scatter3d(
x=x2, y=-y2, z=z2,
mode='markers',
marker=dict(
size=2,
)
)
])
fig.show()
