RGB MappingΒΆ

../../_images/anim_rgb_cube.png

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

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

# 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

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

def xyz2rgb(xyz) :
    # rgb color cube from -1 to 1
    x,y,z = xyz
    r = ( x + 1 ) /2.0
    g = ( y + 1 ) /2.0
    b = ( z + 1 ) /2.0  
    return r,g,b

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
    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
    
    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_op( xyz2rgb )
    surface.shade(0.925, 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 = 60
surface = get_surface( framearray[fID] )

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

fig = plt.figure(figsize=plt.figaspect(1),facecolor='k')
fig.text(0.05,0.05,str(surface), ha='left', va='bottom', fontsize='smaller',c='w')
ax = plt.axes(projection='3d',aspect='equal', facecolor='k',proj_type='ortho',)
ax.set(xlim=(-1,1), ylim=(-1,1), zlim=(-1,1) )
ax.set_axis_off()
ax.view_init(azim=25)

ax.add_collection3d(surface)

plt.show()

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

def update_fig(frame):
    global surface

    surface.remove()
    surface = get_surface( framearray[frame] )
    
    ax.add_collection3d(surface)
    return

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

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