Ellipsoid made out of voxels in Python

385 views Asked by At

I need to make an ellipsoid out of voxels in python, but I still do not completely understand how to define the boundaries of this figure. I have seen some examples where they use boolean operations to define the voxels but I have not been able to make it work the way I want it to. Any help would be greatly appreciated.

This is what I have been trying out:

import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
from mpl_toolkits.mplot3d.art3d import Poly3DCollection

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

# the angles and radius
u = np.linspace(0, 2 * np.pi, 100)
v = np.linspace(0, np.pi, 100)
radius = 4

# equations for the shell of the ellipsoid
X = 3*radius*np.sin(v)*np.cos(u)
Y = 2*radius*np.sin(v)*np.sin(u)
Z = radius*np.cos(v)


x, y, z = np.indices((10, 10, 10))
voxels = (x <= X) | (y <= Y) | (z <= Z)
ax.voxels(voxels)

plt.show()

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-12-f0d9033151c5> in <module>
     14 
     15 x, y, z = np.indices((10, 10, 10))
---> 16 voxels = (x <= X) | (y <= Y) | (z <= Z)
     17 ax.voxels(voxels)
     18 

ValueError: operands could not be broadcast together with shapes (10,10,10) (100,)
1

There are 1 answers

3
anon01 On

You can filter to points within an ellipsoid on an evenly spaced grid using meshgrid and then applying a boolean mask to the points:

import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D

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

# grid points in spherical coord:
N = 40
R = 1
x,y,z = np.meshgrid(np.linspace(-R, R, N), np.linspace(-R, R, N),np.linspace(-R, R, N))

# filter points outside ellipsoid interior:
mask = (2*x)**2 + (3*y)**2 + z**2 <= R**2
x = x[mask]
y = y[mask]
z = z[mask]


# convert to cartesian for plotting:

ax.scatter3D(x,y,z)
ax.set_xlim(-1.2,1.2)
ax.set_ylim(-1.2,1.2)
ax.set_zlim(-1.2,1.2)
plt.show()

enter image description here