Как анимировать BuiltinSurface в Mayavi mlab?

Я пытаюсь оживить вращение Земли, используя Mayavi mlab. В прошлом мне удавалось просто вращать камеру вокруг представления Земли BuiltinSurface, но это становится неудобным, когда мне нужно также отображать в кадре множество других объектов (космический корабль, звезды и т. д.). Приведенный ниже код работает «почти»: на моем компьютере с Windows 10 он выполняется 8 итераций, а затем анимация зависает. Как я могу исправить этот код или есть лучший способ анимировать BuiltinSurface в целом?

import numpy as np
from mayavi import mlab
from mayavi.sources.builtin_surface import BuiltinSurface
from mayavi.modules.surface import Surface
from mayavi.filters.transform_data import TransformData


def rotMat3D(axis, angle, tol=1e-12):
    """Return the rotation matrix for 3D rotation by angle `angle` degrees about an
    arbitrary axis `axis`.
    """
    t = np.radians(angle)
    x, y, z = axis
    R = (np.cos(t))*np.eye(3) +\
    (1-np.cos(t))*np.matrix(((x**2,x*y,x*z),(x*y,y**2,y*z),(z*x,z*y,z**2))) + \
    np.sin(t)*np.matrix(((0,-z,y),(z,0,-x),(-y,x,0)))
    R[np.abs(R)<tol]=0.0
    return R



@mlab.show    
@mlab.animate(delay=200)
def anim():

    fig = mlab.figure()

    engine = mlab.get_engine()

    # Add a cylinder builtin source
    cylinder_src = BuiltinSurface()
    engine.add_source(cylinder_src)
    cylinder_src.source = 'earth'
    # Add transformation filter to rotate cylinder about an axis
    transform_data_filter = TransformData()
    engine.add_filter(transform_data_filter, cylinder_src)
    Rt = np.eye(4)
    Rt[0:3,0:3] = rotMat3D((0,0,1), 0) # in homogeneous coordinates
    Rtl = list(Rt.flatten()) # transform the rotation matrix into a list

    transform_data_filter.transform.matrix.__setstate__({'elements': Rtl})
    transform_data_filter.widget.set_transform(transform_data_filter.transform)
    transform_data_filter.filter.update()
    transform_data_filter.widget.enabled = False   # disable the rotation control further.

    # Add surface module to the cylinder source
    cyl_surface = Surface()
    engine.add_filter(cyl_surface, transform_data_filter)
    #add color property
    #cyl_surface.actor.property.color = (1.0, 0.0, 0.0)

    ind=1
    while ind<90:
        print ind
        Rt[0:3,0:3] = rotMat3D((0,0,1), ind) # in homogeneous coordinates
        Rtl = list(Rt.flatten()) # transform the rotation matrix into a list

        transform_data_filter.transform.matrix.__setstate__({'elements': Rtl})
        transform_data_filter.widget.set_transform(transform_data_filter.transform)
        transform_data_filter.filter.update()
        transform_data_filter.widget.enabled = False   # disable the rotation control further.

        # Add surface module to the cylinder source
        cyl_surface = Surface()
        engine.add_filter(cyl_surface, transform_data_filter)
        # add color property
        #cyl_surface.actor.property.color = (1.0, 0.0, 0.0)

        yield
        ind+=1


anim()

person aerocooper    schedule 13.06.2016    source источник


Ответы (1)


Я не смог найти способ использовать Mayavi, чтобы это произошло. Тем не менее, Vpython кажется гораздо лучше подходит для выполнения этой задачи. Ниже я разместил пример кода для создания вращающейся Земли, а также несколько других функций.

from visual import *

def destroy():
    for obj in scene.objects:
        obj.visible = False
        del obj

R = 6378. # radius of sphere
angle=0.
scene.range = 10000.
SunDirection=vector(.77,.77,0)
# scene.fov = 0.5
scene.center = (0,0,0)
scene.forward = (-1,0,-1)
scene.up = (0,0,1)
scene.lights=[distant_light(direction=SunDirection, color=color.gray(0.8)),
              distant_light(direction=-SunDirection, color=color.gray(0.3))]
x=0
y=0

while True:
    rate(10)

    angle=angle+1.*pi/180.

    destroy()
    s = sphere(pos=(x,y,0), radius=R, material=materials.BlueMarble)
    s.rotate(angle=90.*pi/180.,axis=(1,0,0)) # Always include this to rotate Earth into correct ECI x y z frame
    s.rotate(angle=90.*pi/180.,axis=(0,0,1)) # Always include this to rotate Earth into correct ECI x y z frame
    s.rotate(angle=angle, axis=(0,0,1)) # This rotation causes Earth to spin on its axis

    xaxis = arrow(pos=(0,0,0),  axis=vector(1,0,0)*7000, shaftwidth=100, color=color.red)
    yaxis = arrow(pos=(0,0,0),  axis=vector(0,1,0)*7000, shaftwidth=100, color=color.green)
    zaxis = arrow(pos=(0,0,0),  axis=vector(0,0,1)*7000, shaftwidth=100, color=color.blue)

    ST = cone(pos=(0,8000,0),axis=(0,700,0),radius=700*tan(10*pi/180),color=color.blue,opacity=1)
person aerocooper    schedule 03.08.2016