In [ ]:
import k3d
import numpy as np
from math import sqrt, sin, cos
from skimage.measure import label

width = height = length = 100

def r(x, y, z):
r = sqrt((x - width / 2) * (x - width / 2) + (y - height / 2) * (y - height / 2) + (z - length / 2) * (z - length / 2))
r += sin(x / 2) * 3
r += cos(y / 10) * 5

return r

def f(x, y, z):
return 0 if r(x, y, z) > width / 2 else (1 if y + sin(x / 20) * 10 > height / 2 else 2)

def on_click(x, y, z):
coords = [x, y, z]
missing = None
missing_count = 0

for idx, v in enumerate([np.array([0,0,1]), np.array([0,1,0]), np.array([1,0,0])]):
axis = coords[idx]

if axis == 0 or (obj.voxels[tuple(np.array([z, y, x]) - v)] == 0):
missing = -v
missing_count += 1

if axis == obj.voxels.shape[2 - idx] - 1 or obj.voxels[tuple(np.array([z, y, x]) + v)] == 0:
missing = v
missing_count += 1

if missing_count == 1:
if missing[0] != 0:
slice = obj.voxels[z, :, :]
mask = label(slice, connectivity = 2)
if missing[1] != 0:
slice = obj.voxels[:, y, :]
mask = label(slice, connectivity = 2)
if missing[2] != 0:
slice = obj.voxels[:, :, x]
mask = label(slice, connectivity = 2)

obj.push_data('voxels')

color_map = (0xffff00, 0xff0000, 0x00ff00)
voxels = np.array([[[f(x, y, z) for x in range(width)] for y in range(height)] for z in range(length)])

obj = k3d.voxels(voxels.astype(np.uint8), color_map)
plot = k3d.plot()
plot += obj

obj.click_callback = on_click
plot.voxel_paint_color = 3

In [ ]:
# select Controls->Mode->Callback and click on object wall
plot.display()

In [ ]:
plot.camera_auto_fit = False

In [ ]: