Surface Color from Sample DataΒΆ

../../_images/anim_bunny.webp

Animation control:

Visualization

Frame Value

Surface geometry

sectioning parameter per frame

Surface position

fixed to the coordinate axis

Surface color

constant

Shading and highlighting

fixed to the coordinate axis

Axis coordinate

constant

This example uses the same algorithm to generate the surface geometry shown in the Domain Values from Sample Data example. For this example, the surface is colored using a point cloud generated from sample data.

This is just a variation of a theme: change the object that you want Matplotlib to render.

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import s3dlib.surface as s3d
import s3dlib.pntcloud as ptc

# 0. Define animation control parameters ............................
frameSetSize = 30       # numb frames in each transition phase
totalTime, numFrames = 9, 3*frameSetSize         # time in seconds
frames=range(numFrames) 
interval = int(1000.0*totalTime/numFrames)       # milliseconds

# 1a. generate data samples with values .............................
N,seed,val_mult,domain = 50, 6, 25.0, [ [-1,1], [-1,1], [-1,1] ]
np.random.seed(seed)
xc = np.random.uniform(*domain[0], N)
yc = np.random.uniform(*domain[1], N)
zc = np.random.uniform(*domain[2], N)
dt_coor = np.column_stack((xc,yc,zc))
vals = val_mult*np.random.uniform(size=N)
points = np.column_stack((dt_coor,vals))

drez,cmap = 3, 'jet'
cloudObj = ptc.Point3DCloud(drez).domain(domain)
cloudObj.map_vals_from_sampvals(points,vadj='c')
cloudObj.map_cmap_from_cloudvals(cmap)

bunny = s3d.get_surfgeom_from_obj("data/bunny.obj", color='.9')
x0,y0,z0,s = 0.017,  -0.001,  -0.110, 12.500
bunny.transform(translate=[x0,y0,z0]).transform(scale=[s,s,s])
bunny.triangulate(2)
bunny.map_vertvals_from_cloud(cloudObj)
bunny.shade(flat=False,direction=[1,-1,1])

# 1b. Define function to examine ....................................

def get_surface(Z1Z2) :
    z1, z2 = Z1Z2
    # z1 = f(1,1)    z2 = f(-1,-1)
    def topface(xyz, Z1, Z2) :
        x,y,z = xyz
        Z = ( Z2+Z1)/2.0 - (Z2-Z1)*(x+y)/4.0
        #return x,y,Z
        return y,-x,Z  #  <--- rotate view
    def sideface(xyz, Z1, Z2, isX=True) :
        x,y,z = xyz
        Wmax = (Z2+Z1)/2
        Wmin = Z1
        X,Y = x,y
        if isX : 
            L,H,X = y, x, np.ones(len(x))
        else:
            L,H,Y = x,-y, np.ones(len(y))
        W = -(Wmax-Wmin)*L/2 + (Wmax+Wmin)/2
        Z = (W+1)*H/2 + (W-1)/2
        #return X,Y,Z
        return Y,-X,Z  #  <--- rotate view
    
    rez = 5
    ps = lambda : s3d.PlanarSurface(rez)
    top = ps().map_geom_from_op(lambda xyz : topface(xyz,z1,z2))
    front = ps().map_geom_from_op(lambda xyz : sideface(xyz,z1,z2))
    side = ps().map_geom_from_op(lambda xyz : sideface(xyz,z1,z2,False))
    surface = top+front+side
    surface.map_color_from_cloud(cloudObj)
    surface.shade( .5, direction=[1,-1,1])
    return surface

def get_frames(n) :
    # n number of frames per phase.
    # z component in each phase @ (0,0,z) and (1,1,z)
    negmin = -0.9999
    f2 = np.linspace(-1.0, 1.0, n)
    f1 = np.full(n,negmin)
    f2 = np.concatenate( ( f2, np.full(n,1.0) ) )
    f1 = np.concatenate( ( f1,np.linspace( negmin, 1.0, n) ) )
    f2 = np.concatenate( ( f2,np.linspace( 1.0, negmin, n) ) )
    f1 = np.concatenate( ( f1,np.linspace( 1.0, negmin, n) ) )
    return np.transpose([f1,f2])  

framearray = get_frames(frameSetSize)

# 2. Setup and map surfaces .........................................
fID = 30
fID = 89
surface = get_surface( framearray[fID] ) + bunny

# 3. Construct figure, add surface, plot ............................

fig = plt.figure(figsize=plt.figaspect(1),facecolor='k')
title = str(cloudObj) + '\n' + str(surface)
fig.text(0.04,0.04,title, ha='left', va='bottom', fontsize='smaller',c='w')
ax = plt.axes(projection='3d',aspect='equal', facecolor='k')
ax.set(xlim=(-1,1), ylim=(-1,1), zlim=(-1,1) )
ax.set_axis_off()
ax.view_init(25)
ax.add_collection3d(surface)

fig.tight_layout(pad=1.5)
plt.show()

# 4. Animation ======================================================

def update_fig(frame):
    global surface

    surface.remove()
    surface = get_surface( framearray[frame] ) + bunny

    ax.add_collection3d(surface)
    return

anim = FuncAnimation(fig, update_fig, frames, interval=interval, repeat=True)
anim.save('bunny_cloud.html',writer='html')

msg = "saved {} frames, values: [{:.3f} to {:.3f}] @ {} milliseconds/frane"
print(msg.format(numFrames,np.min(frames),np.max(frames),interval))

print('DONE')